SKAction not executing - swift

let bag = SKSpriteNode(imageNamed: "Content/bag")
holder.addChild(bag)
bag.name = "bag"
bag.zPosition = 5
bag.position = CGPoint(x: -3, y: (holder.size.height / 2) + (bag.size.height / 2) - 6)
bag.setScale(0.5)
print(bag.parent)
bag.runAction(SKAction.playSoundFileNamed("Content/wrap.wav", waitForCompletion: true))
bag.runAction(SKAction.scale(to: 1.0, duration: 1.0, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0)) {
bag.physicsBody = SKPhysicsBody(rectangleOfSize: bag.size)
bag.physicsBody!.dynamic = false
bag.physicsBody!.categoryBitMask = CollisionTypes.Bag.rawValue
bag.physicsBody!.collisionBitMask = CollisionTypes.Ingredients.rawValue
}
print(bag.parent)
The above code gets executed whenever the user taps the "holder" which is just a sprite already on the scene. It should create a new "bag" sprite, add it to the holder, and scale it up from 0.5 to 1.0 after running a sound effect.
The problem is that neither the sound effect or the scale action are being run. I searched this problem and it seems like the case is that the node hasn't been added but that's not the case here. I print the bag's parent before and after the actions and neither is nil. Also, the bag IS being added because I see it on the screen at 0.5 scale. How are neither of these actions being ran?

Related

Entity disappears at the end of the animation

I'm trying to animate the movement of an entity but at the end of the animation the entity disappears. It occurs if you animate the scale or translation but not rotation. I'm not sure if it's a bug or expected behaviour but I would like to find a way to stop it.
let transform = Transform(scale: simd_float3.one,
rotation: simd_quatf(),
translation: [0.05, 0, 0])
let animationDefinition = FromToByAnimation<Transform>(by: transform,
duration: 1.0,
bindTarget: .transform)
if let animationResource = try? AnimationResource.generate(with: animationDefinition) {
entity.playAnimation(animationResource)
}
I know you can use entity.move() and that works fine but I want to explore other ways to animate entities.
This transform animation works as expected. Fix the opacity of your model, if it has translucent materials (for that use USDZ Python Tools commands fixOpacity and usdARKitChecker). Also, check if any transformation ​​are applied to the entity on which you are running the transform animation.
let boxScene = try! Experience.loadBox()
boxScene.children[0].scale *= 3
arView.scene.anchors.append(boxScene)
let entity = boxScene.children[0].children[0]
let transform = Transform(scale: simd_float3.init(2, 2, 2),
rotation: simd_quatf.init(angle: .pi, axis: [1, 1, 1]),
translation: [0.4, 0, 0])
let animationDefinition = FromToByAnimation<Transform>(by: transform,
duration: 2.0,
bindTarget: .transform)
if let anime = try? AnimationResource.generate(with: animationDefinition) {
entity.playAnimation(anime)
}
As you can see from this example, after applying the animation, the entity does not disappear.

Understanding Spritekit run block, variable not as expected

I'm looking for some help understanding why my speedToPoint variable is always 1 when it gets to the wait action.
This is part of an SKSpriteNode extension i wrote for making a bird fly to a random point in a predefined rectangle. The speedToPoint is also randomized between 1 and 4 and used as the duration for the moveTo action. However, i also need to use that TimeInterval for my wait block in the action sequence.
speedToPoint is indeed being randomized in the run block (i've confirmed). How can i use that same randomized number in the wait block in the next part of the sequence?
var speedToPoint:TimeInterval = 1
self.run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run{
speedToPoint = TimeInterval(Globals.sharedInstance.randomF(min: 1, max: 4))
var pointX = Globals.sharedInstance.randomF(min: left,max: right)
let pointY = Globals.sharedInstance.randomF(min: top,max:bottom)
while abs(self.position.x.distance(to: pointX)) < 200 {
pointX = Globals.sharedInstance.randomF(min: left,max: right)
}
self.xScale = pointX < self.position.x ? -1 : 1
self.run(SKAction.move(to: CGPoint(x:pointX,y:pointY),duration: speedToPoint))
},
SKAction.wait(forDuration: speedToPoint)])
),withKey: "inFrame")
To clarify, what i'm really tring to do is have the bird fly to a point, once it's arrived at that point, fly to another point. I'm still wrapping my heard around action sequences and whether or not they actually wait for completion to move on. Which from what i've read, they do, but not for any move actions. That's why the wait is in there. Perhaps there is another way?
An SKAction, once created, can't be modified, and it is meant to be reused eg. you can't modify the duration parameter, or change other passed parameters. This means that you have to re-create it if you need it changed. Of course you can change the speed property of an existing action, or you can pause the action but that's pretty much it when it comes to modifying the existing action.
To solve your issue, you could do next:
1) Create an action which moves a sprite to a specific location
2) Once the action is completed, you create a new one which does the same
you can do this using recursion, like this (just copy & paste the code to see how it works):
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
private var bird = SKSpriteNode(color: .purple, size: CGSize(width: 100, height: 100))
override func didMove(to view: SKView) {
addChild(bird)
recursive()
}
func recursive(){
let sequence = SKAction.sequence([
SKAction.move(to: self.randomPoint(inRect: self.frame), duration: TimeInterval(self.random(between: 1, and: 3))),
SKAction.run({[unowned self] in NSLog("Block executed"); self.recursive()})
])
self.bird.run(sequence, withKey: "aKey")
}
func random(between minimum: CGFloat, and maximum: CGFloat) -> CGFloat{
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(minimum - maximum) + min(minimum, maximum)
}
func randomPoint(inRect rect:CGRect)->CGPoint{
let x = random( between: -rect.size.width / 2.0 , and: rect.origin.x + rect.size.width/2.0)
let y = random(between: -rect.size.height / 2.0 , and: rect.origin.y + rect.size.height/2.0)
return CGPoint(x: x, y: y)
}
}
To stop this action, remove the key associated with it.

SKSpritenodes stop moving when given physics body

When i give two nodes in my game a physics body, they stop doing what i want them to do. I have two bars at the bottom of the scene,one starts on the left, and the other is on the right, and they continuously go to meet at the middle then move back to there starting spot, like a floor opening up. Without a physics body, they do exactly this, but when i give them a physics body,when they both meet in the middle, they stop there and don't move back out.
Here are the bars:
bar.position = CGPoint(x:-self.size.width * 0.2, y:(self.size.height * 0.03));
bar.physicsBody = SKPhysicsBody(texture: text, size: text.size())
bar.physicsBody?.categoryBitMask = PhysicsCategory.bar
bar.physicsBody?.contactTestBitMask = PhysicsCategory.ball
bar.physicsBody?.collisionBitMask = PhysicsCategory.bar
self.addChild(bar)
bar1.position = CGPoint(x:self.size.width * 1.2, y:(self.size.height * 0.03));
bar1.physicsBody = SKPhysicsBody(texture: text, size: text.size())
bar1.physicsBody?.categoryBitMask = PhysicsCategory.bar
bar1.physicsBody?.contactTestBitMask = PhysicsCategory.ball
bar1.physicsBody?.collisionBitMask = PhysicsCategory.bar
self.addChild(bar1)
And this is how they move. This is in the update method:
if (bar.position.x == -self.size.width * 0.2)
{
let move = SKAction.moveToX(self.size.width * 0.012, duration: 1);
bar.runAction(move);
} else if (bar.position.x == self.size.width * 0.012) {
let move = SKAction.moveToX(-self.size.width * 0.2, duration: 1)
bar.runAction(move)
}
if (bar1.position.x == self.size.width * 1.2)
{
let move = SKAction.moveToX(self.size.width * 0.988, duration: 1);
bar1.runAction(move);
} else if (bar1.position.x == self.size.width * 0.988) {
let move = SKAction.moveToX(self.size.width * 1.2, duration: 1)
bar1.runAction(move)
}
What could be causing them to stick together at the middle when i give them a physics body.

Does Sprite Kit SKAction with time duration Slow Function Execution?

I have a function in my Sprite kit game where the game character dies and has a death animation. In this same method I set some attributes to let my update function know that the game is over so that the score can stop being incremented and some other things. But when this runs, the deathAnimation function seems to slow down the execution of the other variables that are being set. So the score keeps being incremented when it should stop for example. Why is this? is it something to do with my update function or does the animation with a time duration slow the entire method from being executed right away?
Thanks for the help in advance!
Here is my deathAnimation method
func deathAnimation() {
//set shield for death
self.yourDead = true
self.shield.position = CGPointMake(self.frame.maxX * 2, self.frame.maxY + self.ape.size.height * 10)
self.shield.hidden = true
self.shieldActivated = false
//set Ape image to default
self.ape.runAction(SKAction.setTexture(SKTexture(imageNamed: "Ape"), resize: true))
self.ape.zRotation = 0
//changes physicsBody values so He doesn't collide
self.ape.physicsBody?.dynamic = false
self.ape.physicsBody?.categoryBitMask = ColliderType.Asteroid.rawValue
self.ape.physicsBody?.contactTestBitMask = ColliderType.Ape.rawValue
self.ape.physicsBody?.collisionBitMask = ColliderType.Ape.rawValue
self.ape.zPosition = 10 //bring the ape to the front
let death = SKAction.sequence([
SKAction.group([
SKAction.scaleBy(4, duration: 0.5),
SKAction.moveTo(CGPointMake(self.frame.minX + ape.size.width * 2, self.frame.minY - ape.size.width * 2), duration: 2),
SKAction.repeatAction(SKAction.rotateByAngle(CGFloat(M_PI_4), duration: 0.2), count: 8)
]),
SKAction.runBlock({self.moveToGameOverView();})
])
ape.runAction(death) //run the animation sequence
}
Here is my code where I check if the player is Dead or not and this is within the update function. I didn't include all of the update function because it is probably more than you would care to look at.
//take Asteroids off the screen and increment score
enumerateChildNodesWithName("asteroid", usingBlock: {(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Void in
//move the asteroids off the screen
node.position = CGPointMake(node.position.x, node.position.y + self.gravity)
//if it is out of screen
if node.position.y > self.frame.size.height + self.largeAsteroid.size.width {
node.removeFromParent()
if !self.yourDead { //if your not dead
self.score++
self.scoreText.text = String(self.score)
//increase Asteroid speed
if self.score > 20 * self.tensCounter {
self.gravity++
self.tensCounter++
}
}
}
})
The code provided looks fine. However you could try checking a few things.
Make sure that you are not calling deathAnimation() over and over again.
Make sure you are not doing your enumerateChildNodesWithName before deathAnimation().
Make sure you aren't incrementing the score somewhere else.
Those are the only reasons I can think that your score would continue to go up after you set self.yourDead = true Hopefully that helps.

Why is my node slowing down when it collects a coin?

My game basically is a jumping game when you tap the screen the heroNode jumps and collects coins coming from the right part of the screen. When it collects the coin the hero node slows down and it goes out of the view. Why does this happen? Heres the code I have.
func coins() {
let moveToLeft = SKAction.moveByX(-self.size.width, y: 0, duration: 2.0)
let repeatMoveToLeft = SKAction.repeatActionForever(moveToLeft)
let removeFromScene = SKAction.removeFromParent()
let sequenceThisMoveAndRemove = SKAction.sequence([repeatMoveToLeft, removeFromScene])
goldCoins.position = CGPointMake(self.size.width / 0.6, self.size.height / 2)
goldCoins.zPosition = 15
goldCoins.setScale(0.9)
goldCoins.runAction(sequenceThisMoveAndRemove)
addChild(goldCoins)
goldCoins.physicsBody = SKPhysicsBody(circleOfRadius: 5)
goldCoins.physicsBody?.affectedByGravity = false
goldCoins.physicsBody?.allowsRotation = false
goldCoins.physicsBody?.categoryBitMask = GoldCoinCategory
goldCoins.physicsBody?.contactTestBitMask = HeroCategory
goldCoins.physicsBody?.collisionBitMask = 0
func addHero() {
let anim = SKAction.animateWithTextures([heroTextureOne, heroTextureTwo], timePerFrame: 0.2)
let run = SKAction.repeatActionForever(anim)
theHero = SKSpriteNode(texture: heroTextureOne)
theHero.runAction(run)
theHero.physicsBody = SKPhysicsBody(circleOfRadius: 50)
theHero.physicsBody?.affectedByGravity = true
theHero.physicsBody?.allowsRotation = false
theHero.physicsBody?.categoryBitMask = HeroCategory
theHero.setScale(0.5)
theHero.position = CGPointMake(self.size.width / 4.0, self.size.height / 2.0)
theHero.zPosition = 15
addChild(theHero)
}
if firstBody.categoryBitMask == HeroCategory && sixthBody.categoryBitMask == GoldCoinCategory {
sixthBody.node!.removeFromParent()
One possibility is that you're making a lot of gold coins that never get removed from the scene graph, and that's bogging down your performance.
Look at your first four lines of coins(). You create a forever-repeating action, and then create a sequence with the forever-repeating action and then the "remove from scene" action. A sequence performs the given actions in order, but a forever-repeating action will never end, so that "remove from scene" action will never be triggered.
So when you addChild( goldCoins ), those coins are never going to go away. And the only other way they can apparently be removed is with a collision. So if you play the game, and if a lot of goldCoins get added, then you're going to have an unbounded number of coins in play. After a while, having enough of those coins, all running actions, could cause your game to slow down.
Another possibility is that all you're removing is the sprite node and not the physics body from the simulation. This is suggested by that last line you included. If you remove the node, the coin will disappear, but the physics body will still be in play, still affecting other physics bodies. If you want to fully remove the coin - and its effect on the physics simulation - you'll need to remove its physics body, too.