Using 3D touch in Sprite Kit to measure pressure - ios

In my main app I'm trying to use 3D touch to activate a bullet fireing, but the results seem to be very inconsistant and it didn't always give my the write results. Also my iPhone 6S was crashing when I used this code, This is the code I used for a test.
for touch in touches {
let location = touch.locationInNode(self)
var force = touch.force * 10
var maxForce = touch.maximumPossibleForce
print ("The force is")
print (maxForce*4)
print (force*10000000)
if force != 0{
myLabel.text = "Force"
myLabel.fontSize = 45
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
self.addChild(myLabel)
myLabel.zPosition = 100000
}
else {
myLabel.removeFromParent()
}

I am a going to guess it is crashing because you add label to the parent multiple times (Your if condition is broken, no matter what function you call, (touchesBegan,touchesMoved,touchesEnded) only one of those conditions will always be true, in touchesBegan and touchesMoved, your force will always be > 0, in your touchEnded, your force should be 0. (I am going to assume this code is your touchMoved) Instead, add your label in the your viewDidLoad code, and use the .hidden field to show/hide your label on your moves. (Make sure on touchesEnded to hide it)

Related

SKActions Doesn't works sometimes, but if minimise the game and reopen it, It Works. How that could happen?

I'm having problem with 2 actions both of the actions are move to actions, that moves the pieces to empty node's position(Empty sknodes are added from sks file for). The problem only happens some times not always, in first one when player reaches loc:25 means wins it moves to empty node's position but it some times doesn't moves to there but the game goes on and if I minimise the game and open it they are already there where they should have moved previously.
Second problem this one is more important because with this skaction player moves to next Position. But very few times it doesn't works everything works fine but when it comes to execute that skaction it Stops totally, only touches works. but if I just minimise the game and open it, it moves to position and then game works fine. No issue then, How can this Happen?
I run the second skaction with sequence with 2 other actions and first one with skspritenode.run() action. and I don't have iOS device so I'm testing it on simulator.
Here are the both of SKActions that I use just the same thing nothing new :
for node in children {
if (node.name == String(nextSpace)) {
let moveAction:SKAction = SKAction.move(to: node.position, duration: 0.5)
moveAction.timingMode = .easeOut
let wait:SKAction = SKAction.wait(forDuration: 0.1)
let runAction:SKAction = SKAction.run({
if (self.movesRemaining == 1) {
self.KillHim(self.whosTurn, nextspace: nextSpace)
}
self.movesRemaining = self.movesRemaining - 1
self.setThePlayerSpace(space: nextSpace, player:self.whosTurn)
self.movePiece()
})
if whosTurn == .Player1 {
touchedNode.run(SKAction.sequence([moveAction, wait, runAction]))
} else {
playerPiece.run(SKAction.sequence([moveAction, wait, runAction]))
}
}
}
code for moving when player won :
if (currentSpacePlayer1Piece1 == 25) {
let loc:SKNode = childNode(withName: "c1")!
Player1Piece1.run(SKAction.move(to: loc.position, duration: 0.2))
currentSpacePlayer1Piece1 = 26
OneMoreMove += 1
} else if (currentSpacePlayer1Piece2 == 25) {
let loc:SKNode = childNode(withName: "c2")!
Player1Piece2.run(SKAction.move(to: loc.position, duration: 0.2))
currentSpacePlayer1Piece2 = 26
OneMoreMove += 1
}
is it could be happening because of using it in simulator?
As knightOfDragon said the node was being paused with some logic some times after removing, it works perfectly. If you have same issue search isPaused if you are using it somewhere not intended.

Automatic sprite rotation in SpriteKit

I am currently making an iPhone game using SpriteKit in which two archers fire arrows at each other in an attempt to take away all of their opponent's health. I've got the mechanism for firing the arrow when the user drags back on the screen, but am wondering if there is a way to make the arrow sprite rotate in mid air as it follows the arc (facing upwards immediately after release and facing downward immediately prior to landing) so that it actually looks as if it were fired from a bow in real life.
This is the piece of code that is ran when the user's touch ends. You can see where I apply the impulse but I am not sure how to go about implementing the rotation. I understand how I could get the initial rotation to match the angle of the trajectory line using simple trigonometry, but don't know how to make it rotate with its arc.
func touchUp(atPoint pos : CGPoint) {
if arrowFired == false && firstTouchMade == true && pointOne != nil {
//Set pointTwo
pointTwo = pos
//Define the vert/hor of the pull-back
let verticalLeg = ((pointOne?.y)! - (pointTwo?.y)!)
let horizontalLeg = ((pointOne?.x)! - (pointTwo?.x)!)
//Apply the impulse
arrow?.run(SKAction.applyImpulse(CGVector(dx: horizontalLeg / 9, dy: verticalLeg / 9), duration: 0.001))
arrow?.physicsBody?.affectedByGravity = true
let array = [trajectoryLine, trajectoryLabel] as [Any]
removeChildren(in: array as! [SKNode])
arrowFired = true
} else if firstTouchMade == false && zoomingIn == false {
zoomingIn = true
cameraNode.run(SKAction.move(to: (arrow?.position)!, duration: 1), completion: {
self.firstTouchMade = true
self.zoomingIn = false
})
cameraNode.run(SKAction.scale(by: 0.5, duration: 1))
}
}
Sorry if this is an obvious question, I am relatively new to programming, Swift, and SpriteKit especially.

Swift Game Scene alter vertically moving background with time?

I have a moving background which is 1500 x 600 pixels and constantly moves vertically down the screen using this code:
let bgTexture = SKTexture(imageNamed: "bg.png")
let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
var i: CGFloat = 0
while i < 3 {
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: bgTexture.size().height * i)
bg.size.width = self.frame.width
bg.zPosition = -2
bg.run(moveBGForever)
self.addChild(bg)
i += 1
}
I now want a new background to come onto the screen after x amount of time to give the feel the player is moving into a different part of the game.
Could I put this code into a function and trigger it with NSTimer after say 20 seconds but change the start position of the new bg to be off screen?
The trouble with repeatForever actions is you don't know where they are at a certain moment. NSTimers are not as precise as you'd like, so using a timer may miss the right time or jump in too early depending on rendering speeds and frame rate.
I would suggest replacing your moveBGForever with a bgAnimation as a sequence of your move & shift actions. Then, when you run bgAnimation action, you run it with a completion block of { self.cycleComplete = true }. cycleComplete would be a boolean variable that indicates whether the action sequence is done or not. In your scene update method you can check if this variable is true and if it is, you can run the sequence action once again. Don't forget to reset the cycleComplete var to false.
Perhaps it sounds more complex but gives you control of whether you want to run one more cycle or not. If not, then you can change the texture and run the cycle again.
Alternatively you may leave it as it is and only change the texture(s) after making sure the sprite is outside the visible area, e.g. its Y position is > view size height.
In SpriteKit you can use wait actions with completion blocks. This is more straightforward than using a NSTimer.
So, to answer your question - when using actions for moving the sprites on-screen, you should not change the sprite's position at any time - this is what the actions do. You only need to make sure that you update the texture when the position is off-screen. When the time comes, obviously some of the sprites will be displayed, so you can't change the texture of all 3 at the same time. For that you may need a helper variable to check in your update cycle (as I suggested above) and replace the textures when the time is right (sprite Y pos is off-screen).

Swift Collision Not Working After SKReferenceNode Scale

I have a weird problem where my SKReferenceNode does not collide properly after being scaled up. It collides well in the center, but it ignores collisions and contacts on the edges.
Here is the first photo of the scene. The SKReferenceNode was scaled up significantly, and as seen in this photo, does not collide correctly on the edges. The PhysicsBody appears to be correct (with showPhysics on), yet the ball refuses to collide.
The SKReferenceNode is using an alpha collision mask, because I need to change it to a larger sprite in the future to do animations and such. Additionally, non-scaled objects work completely fine. Finally, after the ball collides with the center, which does work, and the block is reset, collisions start working as expected again. The code to fix it is probably in the reset function, but I reset everything before the level is loaded, so this wouldn't make sense. Here is a part of my reset code:
func reset() {
physicsWorld.gravity = CGVectorMake(0, -9.8)
for grav in gravityBlock {
grav.reset()
}
gravity = -9.8
//Resets blocks
for blocks in destroyedBlocks { //the blocks are stored in destroyedBlocks when collided with
blocks.reset()
}
destroyedBlocks = []
/*Irrelevant code removed*/
}
Here's my blocks.reset() function:
override func reset() {
super.reset()
self.physicsBody?.categoryBitMask = 1
removeAllActions()
self.texture = self.text
shadow.hidden = false
self.alpha = 0
shadow.alpha = 0
let appear = SKAction(named: "Appear")!
self.runAction(appear)
shadow.runAction(SKAction.fadeInWithDuration(0.25))
}
Here is super.reset()
func reset() {
self.hidden = false
state = .NotBroken
}
Thanks so much!
When you scale the sprite you are just changing it's visual representation. The Physics Body stays the same. That's why you are getting the "strange" during the collisions.
You can see that showing the physics uses in your scene, just open GameViewController and add this line
skView.showsPhysics = true
inside viewDidLoad, just after this line
skView.showsNodeCount = true
Then run again your game, the physics boundaries now will be highlighted.

Move two paddles at same time in SpriteKit + Swift

I am making a simple Pong game using SpriteKit + Swift. It is a multiplayer game, so I want two people to be able to move the two paddles. I want to be able to move the paddles at the same time. When I run the code below, which is the touchesBegan function, I am only able to move each paddle when one finger is pressing the display. When I try to touch another paddle, while my finger is already on the screen, it does not respond.
let touch = touches.first as UITouch?
let touchLocation = touch?.locationInNode(self)
let body: SKPhysicsBody? = self.physicsWorld.bodyAtPoint(touchLocation!)
if body?.node!.name == PaddleCategoryName {
print("Paddle Touched!")
fingerIsOnPaddle = true
} else if body?.node!.name == PaddleCategoryName2 {
print("Paddle2 Touched!")
fingerIsOnPaddle2 = true
}
I know this is a bit late but if you still dont know the answer I believe you need to set this line in your viewController when loading your first scene
skView.multipleTouchEnabled = true

Resources