SKSpriteNode UserInteractionEnabled Not Working - ios

I've looked everywhere but nothing works. Thought I would just ask the question myself. I'm creating a little game in iOS 9 using SpriteKit. My game is going to have left and right controller buttons to move the player sprite. I add the SKSpriteNodes for the directional pads as follows
At the top of the main scene I put:
private var leftDirectionalPad = SKSpriteNode(imageNamed: "left")
private var rightDirectionalPad = SKSpriteNode(imageNamed: "right")
Then I run a method called prepareDirectionalPads
func prepareDirectionalPads() {
// left
self.leftDirectionalPad.position.x = self.size.width * directionalPadLeftXPositionMultiplier
self.leftDirectionalPad.position.y = self.size.height*directionalPadYPosition
self.leftDirectionalPad.size.width = self.leftDirectionalPad.size.width/directionalPadSizeReductionMultiple
self.leftDirectionalPad.size.height = self.leftDirectionalPad.size.height/directionalPadSizeReductionMultiple
self.leftDirectionalPad.name = "leftDirectionalPad"
self.leftDirectionalPad.alpha = directionalPadAlphaValue
self.leftDirectionalPad.zPosition = 1
self.addChild(leftDirectionalPad)
self.leftDirectionalPad.userInteractionEnabled = true
// right
self.rightDirectionalPad.position.x = self.leftDirectionalPad.position.x*directionalPadSpacingMultiple
self.rightDirectionalPad.position.y = self.size.height*directionalPadYPosition
self.rightDirectionalPad.size.width = self.rightDirectionalPad.size.width/directionalPadSizeReductionMultiple
self.rightDirectionalPad.size.height = self.rightDirectionalPad.size.height/directionalPadSizeReductionMultiple
self.rightDirectionalPad.name = "rightDirectionalPad"
self.rightDirectionalPad.alpha = directionalPadAlphaValue
self.rightDirectionalPad.zPosition = 1
self.addChild(rightDirectionalPad)
self.rightDirectionalPad.userInteractionEnabled = true
}
I clearly set userInteractionEnabled for each SKSpriteNode to true. Then, in touches began I wrote...
override func touchesBegan(let touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
var touch = touches.first! as UITouch
var location = touch.locationInView(self.view)
var node = nodeAtPoint(location)
print("Touched")
}
Note: I have also tried var location = touch.locationInNode(self) but that doesnt work either.
I then run the app (either on my xCode Simulator or iPhone 6). If I touch on the SKNodes, nothing happens. Nothing is printed to the console. However, if I touch anywhere else on the screen, I get "touched" printed to the screen.
What am I doing wrong? I want to detect the touch on the pads so I can move the player sprite accordingly. It might be something really stupid I'm forgetting to do. Thanks for your time and patience. Much appreciated.

Figured it out. So apparently self.leftDirectionalPad.userInteractionEnabled = true does not work. It needs to be self.leftDirectionalPad.userInteractionEnabled = false, which is very counter-intuitive. I don't get it but it works now. touchesBegan responds to when the user touches the SKSpriteNode.
let touch = touches.first! as UITouch
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if(node.name == leftDirectionalPad.name)
{
print("left")
}
else if (node.name == rightDirectionalPad.name)
{
print("right")
}

Related

does SKSpriteNode recognize gesture?

i build a wall and the bricks are not moving but i need to have one of them calling some info. this code below is inside a function may be should have this brick global
let brk = SKSpriteNode(imageNamed: imgName)
if (imgName == "brickinfo"){
brk.name = "brickinfo"
}
brk.position = CGPoint(x:CGRectGetMinX(self.frame)+brkx, y: CGRectGetMinY(self.frame)+brky)
if (imgName == "brickinfo"){
let singleTap = UITapGestureRecognizer(target: self, action: Selector("ShowInfo"))
singleTap.numberOfTapsRequired = 1
brk.userInteractionEnabled = true
//brk.addGestureRecognizer(ShowInfo) //do not exist
}
brk.xScale = 0.2
brk.yScale = 0.2
addChild(brk)
i am using the same code for other moving images which mean they have SKAction so when i click on them, touches began is fired. they both using the same code, add a name, addchild().
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
//675
//30
print(self.nodeAtPoint(location).name)
if let theName = self.nodeAtPoint(location).name {
but the name of "brickinfo" is always coming back nil.
Can this brick image fired touchesbegan?
Thank you
ok i was not looking for gesture, i thought i needed to add gesture to trigger the image, but i only needed to have this image responding with its name. After 3-4 days looking at many different ways to do it, i found the solution and it is pretty easy, the zposition was not set up for this specific brick. Now of course this bring its own problem. Sorry for the title of the question. Does xcode comes with a zposition layer view in 3D?
Thank you

Sprite issue when responding to touch event in SpriteKit Swift

I have loaded two checkbox sprites on the screen. The image to load the sprite initially in an unchecked checkbox. Then I expect to click on one checkbox and replace the image with another checked checkbox image. The code I have written behaves very strangely where the checked checkbox image never appears.
I have two class properties:
var check1: SKSpriteNode = SKSpriteNode (imageNamed: "unchecked.png")
var check2: SKSpriteNode = SKSpriteNode (imageNamed: "unchecked.png")
I am calling generateCheckboxex() method from didMoveToView(view: SKView)
func generateCheckboxes()
{
self.check1.position = CGPointMake(self.size.width * 0.75, self.size.height * 0.84)
self.check1.setScale(0.15)
self.check1.name = "check1"
self.addChild(self.check1)
self.check2.position = CGPointMake(self.size.width * 0.75, self.size.height * 0.75)
self.check2.setScale(0.15)
self.check2.name = "check2"
self.addChild(self.check2)
}
This is my touchBegan method code:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch = touches as! Set<UITouch>
var location = touch.first!.locationInNode(self)
var node = self.nodeAtPoint(location)
// If next button is touched, start transition to second scene
if node.name == "check1" {
//self.check1.texture = SKTexture(imageNamed: "checked.png")
var texAction = SKAction.setTexture(SKTexture(imageNamed: "checked.png"))
self.check1.runAction(texAction)
//self.check2.texture = SKTexture(imageNamed: "checked.png")
self.check2.runAction(texAction)
}
if node.name == "check2" {
self.check1.texture = SKTexture(imageNamed: "unchecked.png")
self.check2.texture = SKTexture(imageNamed: "checked.png")
}
}
Please help me and let me know if I'm approaching it in the wrong manner, thanks.
EDIT: Admins please close this question, this exact same code works for me now. Maybe it was an issue with the sprites themselves. Thanks!

Swift Sprite-kit: Contact not registered after user interaction to move object

So I am having an issue with Swift Sprite-kit. Contact is not being registered. This has something to do with my code for moving a row of objects. I have code in the touchesBegan method that finds the user's touch location, and then a block of code in the touchesMoved method that then recognises a drag on the screen and moves the row correspondingly. I know that the touchesMoved function works because the row moves when the user drags the screen.
Here is the code for my touchesBegan method:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
if gameOver == 0 {
var touch = touches.first as! UITouch
var touchLocation = touch.locationInNode(self)
if let body = physicsWorld.bodyAtPoint(touchLocation) {
if body.node == self {
//if touchLocation == blueBox.position {
isFingerOnScreen = true
}
}
And this is my code for the touchesMoved
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
// 1. Check whether user touched the screen
if isFingerOnScreen == true {
// 2. Get touch location
var touch = touches.first as! UITouch
var touchLocation = touch.locationInNode(self)
var previousLocation = touch.previousLocationInNode(self)
// 4. Calculate new position along x for objects
var blueBoxX = blueBox.position.x + (touchLocation.x - previousLocation.x)
var greenBoxX = greenBox.position.x + (touchLocation.x - previousLocation.x)
var redBoxX = redBox.position.x + (touchLocation.x - previousLocation.x)
var yellowBoxX = yellowBox.position.x + (touchLocation.x - previousLocation.x)
// 5. Limit x so that the objects won't leave screen to left or right (this code does not actually work for me)
/*
blueBoxX = max(blueBoxX, blueBox.size.width/2)
blueBoxX = min(blueBoxX, size.width - blueBox.size.width/2)
greenBoxX = max(greenBoxX, greenBox.size.width/2)
greenBoxX = min(greenBoxX, size.width - greenBox.size.width/2)
redBoxX = max(redBoxX, redBox.size.width/2)
redBoxX = min(redBoxX, size.width - redBox.size.width/2)
yellowBoxX = max(yellowBoxX, yellowBox.size.width/2)
yellowBoxX = min(yellowBoxX, size.width - yellowBox.size.width/2)
*/
// 6. Update object position
blueBox.position = CGPointMake(blueBoxX, blueBox.position.y)
blueBox.zPosition = 10
greenBox.position = CGPointMake(greenBoxX, greenBox.position.y)
greenBox.zPosition = 10
greenBox.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(greenBox.size.width, greenBox.size.height * 1/100))
greenBox.physicsBody!.dynamic = false
greenBox.physicsBody!.categoryBitMask = greenColourGroup
redBox.position = CGPointMake(redBoxX, redBox.position.y)
redBox.zPosition = 10
yellowBox.position = CGPointMake(yellowBoxX, yellowBox.position.y)
yellowBox.zPosition = 10
}
Now this is all good so far but my issue is that when this code is active, it for some reason stops the app from recognising contact between a ball and an object. Whereas when the code is commented out, the contact is recognised and the objects match. This makes no sense to me because as far as I can tell the only thing I am changing with the greenBox object (the only object I am testing with) is the position of the object in relation to the touchLocation.
My code for the contact is as follows:
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case greenColourGroup | ballColourGroup:
if contact.bodyA.categoryBitMask == greenColourGroup || contact.bodyB.categoryBitMask == greenColourGroup {
if ballColourGroup == greenColourGroup {
score++
scoreLabel.text = "\(score)"
ball.removeFromParent()
makeBall()
I am quite new to coding and am really struggling with this issue, so please help and if it involves code please include the necessary code needed to fix this issue.
Thanks
P.S: Just to confirm, the didBeginContact method works perfectly when the code for moving the objects is commented out, so I know that this code is ok. The issue is that the code within the touchesMoved method is stopping it from working

When the screen is touched, how do I make the game over?

I want a game over screen and the game to stop when the screen is touched during a specific animation.
let lightTexture = SKTexture(imageNamed: "green light.png")
let lightTexture2 = SKTexture(imageNamed: "red light.png")
let animateGreenLight = SKAction.sequence([SKAction.waitForDuration(2.0, withRange: 0.1), SKAction.animateWithTextures([lightTexture, lightTexture2], timePerFrame: 3)])
let changeGreenLight = SKAction.repeatActionForever(animateGreenLight)
let animateRedLight = SKAction.sequence([SKAction.waitForDuration(2.0, withRange: 0.1), SKAction.animateWithTextures([lightTexture, lightTexture2], timePerFrame: 3)])
let changeRedLight = SKAction.repeatActionForever(animateRedLight)
let greenLight = SKSpriteNode(texture: lightTexture)
greenLight.position = CGPointMake(CGRectGetMidX(self.frame), 650)
greenLight.runAction(changeGreenLight)
self.addChild(greenLight)
let redLight = SKSpriteNode(texture: lightTexture2)
redLight.position = CGPointMake(CGRectGetMidX(self.frame), 650)
redLight.runAction(changeRedLight)
self.addChild(redLight)
When the animation for the red light is on the screen, I want it to be game over. Do I have to make an if statement, and if so for what specifically?
Thank You in advance!
You can make yourself another node which has the same size and position as the red light. Additionally, that node is able to handle touch events. Then, add that node before the animation runs. This can be done with a sequence of actions, e.g.:
let addAction = SKAction.runBlock({ self.addChild(touchNode) })
let animationAction = SKAction.repeatActionForever(animateRedLight)
redLight.runAction(SKAction.sequence([ addAction, animationAction ]))
Update
Since you want the game to end when you touch anywhere, alter the code such that the block sets a variable which indicates that the animation is executed and implement touchesBegan which checks for that variable, e.g.
let addAction = SKAction.runBlock({ self.redLightAnimationRuns = true })
[...]
// In touchesBegan
if touched
{
if redLightAnimationRuns
{
endGame()
}
}
use the touchesBegan() function to call a GameOver() function when the red light is on the screen (which you can control with a variable).
So, when the red light comes on to the screen, variable redLightCurrent is set to true. in TouchesBegan(), when redLightCurrent is true, then call the gameOver() function where you can include what to do when the game is over. This will only occur when a touch has began on the screen.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
let array = Array(touches)
let touch = array[0] as UITouch
let touchLocation = touch.locationInNode(self)
if redLightCurrent {
gameOver()
}
}
This code works with the new xCode 7 and Swift 2.0

See if SKShapeNode touched?: How to Identify node?

I am doing a small for fun project in Swift Xcode 6. The function thecircle() is called at a certain rate by a timer in didMoveToView(). My question is how do I detect if any one of the multiple circle nodes on the display is tapped? I currently do not see a way to access a single node in this function.
func thecircle() {
let circlenode = SKShapeNode(circleOfRadius: 25)
circlenode.strokeColor = UIColor.whiteColor()
circlenode.fillColor = UIColor.redColor()
let initialx = CGFloat(20)
let initialy = CGFloat(1015)
let initialposition = CGPoint(x: initialx, y: initialy)
circlenode.position = initialposition
self.addChild(circlenode)
let action1 = SKAction.moveTo(CGPoint(x: initialx, y: -20), duration: NSTimeInterval(5))
let action2 = SKAction.removeFromParent()
circlenode.runAction(SKAction.sequence([action1, action2]))
}
There are many problems with this.
You shouldnt be creating any looping timer in your games. A scene comes with an update method that is called at every frame of the game. Most of the time this is where you will be checking for changes in your scene.
You have no way of accessing circlenode from outside of your thecircle method. If you want to access from somewhere else you need to set up circlenode to be a property of your scene.
For example:
class GameScene: BaseScene {
let circlenode = SKShapeNode(circleOfRadius: 25)
You need to use the method touchesBegan. It should have come with your spritekit project. You can detect a touch to your node the following way:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
// detect touch in the scene
let location = touch.locationInNode(self)
// check if circlenode has been touched
if self.circlenode.containsPoint(location) {
// your code here
}
}
}

Resources