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

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

Related

SKSpriteNode UserInteractionEnabled Not Working

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")
}

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!

Removing a sprite in an if statement with SpriteKit

I want to make a game where every time a user touches, it switches between one of two "states". In order to keep track of touches, I made a variable called userTouches, which changes from true to false each time a user touches. I want to make it so that if numberOfTouches is true, it updates the texture to state0; if it's false, it updates the texture to state1. Pretty much just toggling between state0 and state1 for each touch.
var userTouches: Bool = true
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
userTouches = !userTouches
}
let centered = CGPoint(x: size.width/2, y: size.height/2)
let state0 = SKTexture(imageNamed:"state0")
let state1 = SKTexture(imageNamed:"state1")
var activeState: SKSpriteNode = SKSpriteNode(texture: state0)
//Add new state0 if it's odd, remove old state0 if it's not.
if userTouches == true {
activeState.texture = state0
println("IT'S TRUE")
} else {
activeState.texture = state1
println("IT'S FALSE")
}
self.addChild(activeState)
activeState.name = "state0"
activeState.xScale = 0.65
activeState.yScale = 0.65
activeState.position = centered
}
When I run the code, the new textures are added according to the conditions, but the old ones are still there. They are being added as new spritenodes in the scene. I do not want this. I was expecting it to simply switch between the textures (state0 and state1) of the activeState spritenode depending on my boolean variable. How can I have my code toggle between textures each time a user taps, instead of piling new spritenodes on top of one another?
Each time you create a new object, change its texture (a new object`s texture, but not the texture of object which was set up last time) and add it to the scene. That's why new objects are added and nothing happens with the old objects.
Do this and it will solve your problem:
Create textures and SKSpriteNode object outside the touchesBegan function
If you have no init at your scene, create SKSpriteNode object at didMoveToView function for example and add it to scene
Then in touchesBegan function only set texture to SKSpriteNode object
it would look something like this:
class GameScene: SKScene {
...
let state0 = SKTexture(imageNamed:"state0")
let state1 = SKTexture(imageNamed:"state1")
var activeState: SKSpriteNode?
...
override func didMoveToView(view: SKView) {
let centered = CGPoint(x: size.width/2, y: size.height/2)
activeState = SKSpriteNode(texture: state0)
self.addChild(activeState!)
activeState!.name = "state0"
activeState!.xScale = 0.65
activeState!.yScale = 0.65
activeState!.position = centered
}
...
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if userTouches {
activeState!.texture = state0
} else {
activeState!.texture = state1
}
}
...
}

iOS Spritekit intersectsnode does not work for SKShapeNode

I am using the iOS SpriteKit Game Swift template on iOS8.3. I am trying to use the function func intersectsNode(_ node: SKNode) -> Bool to detect overlap of two circles created as SKShapeNodes. Turns out the function does not detect the intersection if its SKShapeNodes. But on further troubleshooting, it turns out the function works if I use the default Spaceship sprite of the template. Here is the code which works:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite.xScale = 0.3
sprite.yScale = 0.3
sprite.position = location
self.circles.append(sprite)
self.addChild(sprite)
if circles.count == 1 {
println("One circle")
} else {
for var index = 0; index < circles.count-1; ++index {
if sprite.intersectsNode(circles[index]) {
println(circles[index].frame)
println("Circle intersects another")
}
}
}
}
}
When two sprites overlap in the above code the function returns YES and prints the intersection string. Here is the code which does NOT work:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let sprite = SKShapeNode(circleOfRadius: 50)
sprite.position = location
self.circles.append(sprite)
self.addChild(sprite)
if circles.count == 1 {
println("One circle")
} else {
for var index = 0; index < circles.count-1; ++index {
if sprite.intersectsNode(circles[index]) {
println(circles[index].frame)
println("Circle intersects another")
}
}
}
}
}
As you can see the code blocks are completely identical except in one case its an SKSpriteNode and the other case its SKShapeNode. I also printed the frames of the SKShapeNode Circles and I can see they have have valid frames. So I am puzzled by this as I would like to use SKShapeNodes in my code for now but I cannot use the intersectNode function as it does not work.
The documentation for intersectsNode says this:
The two nodes are considered to intersect if their frames intersect. The children of both nodes are ignored in this test.
Which means you won't get the result you want when using circles.
However, checking if two circles overlap is as easy as checking if the distance between their centers is less than the sum of their radiuses.

Removing sprites/labels slow in swift (removeallchildren)

I am adding sklabelnodes and skspritenodes to the scene with these functions:
var levelnode = SKSpriteNode()
var labelLevel = SKLabelNode(fontNamed: "Courier-Bold")
func addlevels(){
var level = score + 1
if (level > 0){
sprite()
levelnode.position = CGPointMake(frame.size.width / 2.2, -frame.size.height/15.6 - frame.size.height/17.6)
levelnode.name = "1"
addChild(levelnode)
sklabel()
labelLevel.text = ("1")
labelLevel.position.x = levelnode.position.x - (levelnode.size.width/40)
labelLevel.position.y = levelnode.position.y - (levelnode.size.width/6)
labelLevel.name = "1"
addChild(labelLevel)
}
if (level > 1){
sprite()
levelnode.position = CGPointMake(frame.size.width / 1.42 - frame.size.width/100, -frame.size.height/10 - frame.size.height/17.6)
levelnode.name = "2"
addChild(levelnode)
sklabel()
labelLevel.text = ("2")
labelLevel.position.x = levelnode.position.x - (levelnode.size.width/40)
labelLevel.position.y = levelnode.position.y - (levelnode.size.width/6)
labelLevel.name = "2"
addChild(labelLevel)
}
// this goes on and on till level 25
}
func sprite(){
levelnode = SKSpriteNode(imageNamed: "levelnode")
levelnode.size.width = frame.size.width / 8
levelnode.size.height = levelnode.size.width
levelnode.zPosition = 1
}
func sklabel(){
labelLevel = SKLabelNode(fontNamed: "Courier-Bold")
labelLevel.zPosition = 2
labelLevel.fontColor = SKColor.blackColor()
labelLevel.fontSize = frame.size.height / 35
}
When I am changing the scene, the sprites and labels are removed from the willmovefromview function:
override func willMoveFromView(view: SKView) {
removeAllChildren()
}
but this is taking too slow if I compare it with other scenes where even more skspritenodes are added..
I think It has to do with the functions where I add the sprites and labels, but what is wrong about it?
EDIT:
the function that takes me back too the menu:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
errint = false
for touch: AnyObject in touches {
let location: CGPoint! = touch.locationInNode(self)
let nodeAtPoint = self.nodeAtPoint(location)
if (nodeAtPoint.name != nil) {
if nodeAtPoint.name == "menu" {
removeallAction()
removeAllChildren()
var scene1 = GameMenuScene(size: self.size)
scene1.button = self.button
scene1.button2 = self.button2
scene1.button3 = self.button3
scene1.viewController = self.viewController
let transition = SKTransition.moveInWithDirection(SKTransitionDirection.Left, duration: 0.75)
self.view?.presentScene(scene1, transition: transition)
}
}
}
}
Doesn't transitioning to another scene deallocate the current scene?
And if that scene is deallocated, then there's no need for the nodes and such to be removed...
Could you do me a favor, and transition out without removing the children and actions, then transition back in and see if it matters??
Anyway, speed is trivial if you're testing on the simulator... the simulator really only simulates opengl, the core of SpriteKit.
Please try it on your device.
BTW, I'm not sure of stuff but nobody seemed to have answered you so I tried...
EDIT:
HOLY MOTHER OF GOD WHY DIDN'T I SEE THE TIMESTAMP IT WAS ASKED TWO MONTHS AGO.
Too late now I guess... but to anybody reading this, don't answer questions at 2 am.

Resources