Not able to select pause button I have added to the screen - swift

My game is setup with a background, a road in the middle of it, then a bar at the top which displays the score and pause button. zPositon of the road and background are 1. The bar at the top zPosition is 4, and the pause button zPosition is 4 as well.
Code for road and background.
road.position = CGPoint(x: CGFloat(0), y: CGFloat(0))
road.zPosition = 1
road.name = roadName
background.position = CGPoint(x: CGFloat(0), y: CGFloat(0))
background.zPosition = 1
background.name = backgroundName
addChild(background)
addChild(road)
Code for the bar at the top.
topBar = SKSpriteNode(color: .black, size: CGSize(width: screenWidth, height: CGFloat(150)))
topBar.position = CGPoint(x: 0, y: (screenHeight/2) + topBar.size.height/2)
topBar.zPosition = 4
topBar.name = topBarName
addChild(topBar)
Code for the pause button.
pauseButton.position = CGPoint(x: (-topBar.size.width/2) + (pauseButton.size.width + (pauseButton.size.width/2)), y: 0)
pauseButton.zPosition = 4
pauseButton.name = pauseButtonName
topBar.addChild(pauseButton)
In my touches began function, I attempted to search for the nodes at the position of the touch, but it only returns the names of the road and background. It doesn't even pick up the topBar or pause button.
for node in nodes
{
print(node.name)
if node.name == pauseButtonName
{
print("paused")
}
}
This will output
Optional("Road")
Optional("Background")
I also tried this method, but "paused" was never returned.
if pauseButton.contains(touch.location(in: self))
{
print("paused")
}
I think it may be important to note that the top bar is positioned off the screen initially. When you start the game, it runs an SKAction to move the bar on screen.
topBar.run(SKAction.moveTo(y: (screenHeight/2) - (topBar.size.height/2), duration: 0.5))
Why am I not able to select the pause button, and how can this be resolved?

I resolved the issue by using this code. Instead of checking for the location in the game scene, I checked for it in the topBar.
if pauseButton.contains(touch.location(in: topBar))
{
print("paused")
}

Related

set SKEmitterNode to background

I am setting up a scene with a fixed background (a simple rectangle), an SKEmitterNode, and a backgroundLayer (a SKNode including many SKShapeNodes) : this is the hierarchy of my scene. But, even if I am adding the emitter node as a child of the scene just after the fixed background and just before the background layer, the particles emitted are at the foreground, which is not what I am expecting. indeed, I would like them to be rendered between the fixed background and the background layer, which is not happening.
I am running this app on ios 10. I've tried to add childs in a different order, or to change the target node, but it didn't change anything...
All of the following code comes from 'init(size: CGSize) {}' of a scene class which inherits from SKScene.This is all the scene set up process (when childs are added).
anchorPoint = CGPoint(x: 0, y: 0)
background.position = CGPoint(x: sceneSize.width / 2, y: sceneSize.height / 2)
background.fillColor = UIColor(white: 0.5, alpha: 1)
background.strokeColor = UIColor.lightGray
addChild(background)
setUpParticleEmitter() // it sets up the particle emitter which is an attribute of the class
addChild(backgroundEmitter) // This is the name of the emitter
backgroundEmitter.targetNode = scene
backgroundLayer.position = CGPoint(x: 0, y: 0)
addChild(backgroundLayer)
gameLayer.position = CGPoint(x: -1 * sceneSize.width, y: 0) // another layer for futur nodes
addChild(gameLayer)
I expect the particles to be rendered between 'background' and 'backgroundLayer', but they are rendered at the foreground (=over the backgroundLayer's childs), is it possible to change that ?
You can chose which nodes to be in front and which in back by setting them the zPosition.
first_node.zPosition = 1
second_node.zPosition = 2 // displayed over first node

Remove a function from SKScene when Touches Begin

I have a blue sky texture moving from the top of the screen to the bottom, repeating forever in a function. However, when touches begin, I would like the blue sky to completely fade out after a duration, then completely remove from the scene.
I am able to get the sky to fade out momentarily, then it seems as though half of the loop is removed, but I still get the sky coming down every other time. Here's a video of the problem: Blue Sky Video
In the video, touches begin when the pause button appears at the top left of the screen - before touches begin, the blue sky moves from top to bottom seamlessly as it should.
FUNCTION
func createBlueSky() {
let blueSkyTexture = SKTexture(imageNamed: "blueSky")
for i in 0 ... 1 {
let blueSky = SKSpriteNode(texture: blueSkyTexture)
blueSky.name = "blueSky"
blueSky.zPosition = -60
blueSky.anchorPoint = CGPoint.zero
blueSky.position = CGPoint(x: 0, y: (blueSkyTexture.size().height * CGFloat(i)))
worldNode.addChild(blueSky)
let moveDown = SKAction.moveBy(x: 0, y: -blueSkyTexture.size().height, duration: 10)
let moveReset = SKAction.moveBy(x: 0, y: blueSkyTexture.size().height, duration: 0)
let moveLoop = SKAction.sequence([moveDown, moveReset])
let moveForever = SKAction.repeatForever(moveLoop)
blueSky.run(moveForever)
}
}
I've added the above function to didMove(toView)
override func didMove
createBlueSky()
Then in my touches began I added this code to fade out and remove from parent.
I saw in another post that to access the blue sky from another function, I'd need to give it a name, which I did. Still no luck :/
override func touchesBegan
let blueSky = worldNode.childNode(withName: "blueSky") as! SKSpriteNode
let blueSkyFade = SKAction.fadeOut(withDuration: 3)
let blueSkyFadeWait = SKAction.wait(forDuration: 3)
let removeBlueSky = SKAction.removeFromParent()
blueSky.run(SKAction.sequence([blueSkyFadeWait, blueSkyFade, removeBlueSky]))
I'm very new to Swift, but I hope the question was specific enough. I'm happy to provide any other necessary information.
You are creating 2 blueSky nodes, but you only fade and remove 1 of them. You need to enumerate through all of the nodes with the name you are looking for. To do this, you call enumerateChildNodes(withName:}
let blueSkyFade = SKAction.fadeOut(withDuration: 3)
let blueSkyFadeWait = SKAction.wait(forDuration: 3)
let removeBlueSky = SKAction.removeFromParent()
enumerateChleNodes(withName:"blueSky")
{
(blueSky,stop) in
blueSky.run(SKAction.sequence([blueSkyFadeWait, blueSkyFade, removeBlueSky]))
}

How to get action of button in Swift MacOS

I am trying to set up zoom for a game where you click on a button to zoom in, and another to zoom out (which will be part of the UI).
I am having problems getting the input of the buttons to the code. I can read that the button is not pressed, but I cannot figure out how to read if it is pressed.
Looking through the API reference gave me the idea to try using the "state" of the button, but it always returns 0, even when the button is pressed. This could be because the update function does not update as fast as the button's state changes.
Here is my code:
class GameScene: SKScene {
override func sceneDidLoad() {
cam = SKCameraNode()
cam.xScale = 1
cam.yScale = 1
self.camera = cam
self.addChild(cam)
cam.position = CGPoint(x: 0, y: 0)
setUpUI()
}
func setUpUI(){
let button1Rect = CGRect(x: 20, y: 80, width: 80, height: 40)
let zoomIn = NSButton(frame: button1Rect) //place a button in the Rect
zoomIn.setButtonType(NSMomentaryPushInButton)
zoomIn.title = "Zoom In"
zoomIn.alternateTitle = "Zoom In"
zoomIn.acceptsTouchEvents = true
view?.addSubview(zoomIn) //put button on screen
let button2Rect = CGRect(x: 20, y: 30, width: 80, height: 40)
let zoomOut = NSButton(frame: button2Rect) //place a button in the Rect
zoomOut.setButtonType(NSMomentaryPushInButton)
zoomOut.title = "Zoom Out"
zoomOut.alternateTitle = "Zoom Out"
zoomOut.acceptsTouchEvents = true
view?.addSubview(zoomOut) //put button on screen
if zoomIn.state == 1{ //this loop is never true no matter how many times I press the button
print("zoom")
}
}
}
I did cut out some of the code involving the mouse as it is not relevant.
Answer is from TheValyreanGroup.
Simply define the button outside of the setUpUI() function (outside of the GameScene or within it works, outside of the GameScene is easier).

Swift : Animate SKEmitterNode

I am trying to create an explosion effect using SKEmitterNode, I followed some of this tutorial (http://www.waveworks.de/kill-your-characters-animating-explosions-with-skanimations-in-sprite-kit/), but it didn't seem to work. Here is what i have:
var superDabParticle = SKEmitterNode(fileNamed: "superDabParticle.sks")
func setUpEmiterNode(){
superDabParticle?.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)
let superDabParticleEffectNode = SKEffectNode()
superDabParticle?.zPosition = 1
superDabParticle?.setScale(0)
superDabParticleEffectNode.addChild(superDabParticle!)
self.addChild(superDabParticleEffectNode)
}
func animateEmiterNode(){
let birth = SKAction.runBlock { self.superDabParticle?.particleBirthRate = 0 }
superDabParticle!.runAction(SKAction.sequence([SKAction.waitForDuration(0.1), SKAction.scaleBy(1.5, duration: 0.1), birth]))
}
So i need to call setUpEmiterNode() when the app first launches up, then when the user taps a button, call animateEmiterNode to have the particles fly from the bottom of the screen up to about 75% of the screen, then fall back down; giving a sort of explosion under water effect. Im using the SPARK emitter effect. If you know my issue or have any other ways that are better to do this, please assist!!

Endless scrolling background

I am trying to get my background to move endless from right to left.
My let:
let background = SKSpriteNode(imageNamed: "background")
let background2 = SKSpriteNode(imageNamed: "background")
my didMoveToView
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
background.zPosition = 2
background2.position = CGPointMake(CGRectGetMidX(self.frame)+(background.position.x/2),CGRectGetMidY(self.frame))
background2.zPosition = 2
background.setScale(2)
background2.setScale(2)
self.addChild(background)
self.addChild(background2)
var backgroundMovement = SKAction.moveByX(background.size.width, y: 0, duration: 1)
background.runAction(backgroundMovement, completion: {() -> Void in
self.background.position = CGPointZero
})
var backgroundMovement2 = SKAction.moveByX(background2.size.width, y: 0, duration: 1)
background2.runAction(backgroundMovement2, completion: {() -> Void in
self.background2.position = CGPointZero
})}
My update func is empty.
I have uploaded a picture of how it looks like when running on device: http://s18.postimg.org/kbn83tvmx/i_OS_Simulator_Screen_Shot_09_Aug_2015_23_33_39.png
The image is still on half of the screen, and the image does not move now either.
The reason your background only takes up half of the screen is because you are using the regular size of the image in pixels. You need to edit the xScale and yScale properties in order to make it make it bigger. What you need is:
background.setScale(2)
Next, to move the background sprites, use SKAction instead since you have more control over timing. The motion within update won't be consistant because, unless you have an algorithm to control exactly when update: is called, you will see that the movement speeds up or slows down. To move the background, use code that looks something like this after your didMoveToView method:
var backgroundMovement = SKAction.moveByX(background.size.x, y: 0, duration: someDuration)
background.runAction(background, completion: {() -> Void in
//place background image at start again
background.position = ...
})
Loop this code if you want the background to move continuously and edit it in any way you'd like to make it look better (like having both backgrounds move with SKAction). Hope this helps
I'm going to copy and paste my code from another game I've made. This code moves a background from right-left forever. I'll do best to explain this code.
func createBackground () {
var backgroundTexture = SKTexture(imageNamed: "bg")
var moveBackgroundByX = SKAction.moveByX(-backgroundTexture.size().width, y: 0, duration: backgroundSpeed)
var replaceBackground = SKAction.moveByX(backgroundTexture.size().width, y: 0, duration: 0)
var moveBackgroundForever = SKAction.repeatActionForever(SKAction.sequence([moveBackgroundByX, replaceBackground]))
for var i:CGFloat = 0; i < 3; i++ {
background = SKSpriteNode(texture: backgroundTexture)
background.position = CGPoint(x: backgroundTexture.size().width/2 + (backgroundTexture.size().width * i), y: CGRectGetMidY(self.frame))
background.size.height = self.frame.height
background.runAction(moveBackgroundForever)
movingObjects.addChild(background)
}
}
What you need to do is:
Move background (moveBackgroundByX). This moves the background in the X direction. You need to set a duration.
Replace background1 (replaceBackground).
Create an ACTION forever that moves background1, then replaces it automatically with NO delay.
Run a LOOP that decides how many backgrounds you will need. Maybe you might need more than 3.
Inside that loop, adjust the background.position.
Call runAction on your SKSpriteNode instance.
Add the new SKSpriteNode into your another SKView.
If you have any questions please let me know.