Move SKAction.animate in SpriteKit - swift

func addRocket(rocketNode: SKSpriteNode, atPosition position: CGPoint){
rocket = SKSpriteNode(texture: rocketTex)
rocketAnimArray = [SKTexture(imageNamed: "rocket1.png"), SKTexture(imageNamed: "rocket2.png"), SKTexture(imageNamed: "rocket3.png"), SKTexture(imageNamed: "rocket4.png"), SKTexture(imageNamed: "rocket5.png"), SKTexture(imageNamed: "rocket6.png"), SKTexture(imageNamed: "rocket7.png"), SKTexture(imageNamed: "rocket8.png"), SKTexture(imageNamed: "rocket9.png"), SKTexture(imageNamed: "rocket10.png"), SKTexture(imageNamed: "rocket11.png"), SKTexture(imageNamed: "rocket12.png"), SKTexture(imageNamed: "rocket13.png"), SKTexture(imageNamed: "rocket14.png"), SKTexture(imageNamed: "rocket15.png"), SKTexture(imageNamed: "rocket16.png"), SKTexture(imageNamed: "rocket17.png"), SKTexture(imageNamed: "rocket18.png"), SKTexture(imageNamed: "rocket19.png"), SKTexture(imageNamed: "rocket20.png"), SKTexture(imageNamed: "rocket21.png"), SKTexture(imageNamed: "rocket22.png"), SKTexture(imageNamed: "rocket23.png"), SKTexture(imageNamed: "rocket24.png"), SKTexture(imageNamed: "rocket25.png"), SKTexture(imageNamed: "rocket26.png"), SKTexture(imageNamed: "rocket27.png"), SKTexture(imageNamed: "rocket28.png"), SKTexture(imageNamed: "rocket29.png"), SKTexture(imageNamed: "rocket30.png"), SKTexture(imageNamed: "rocket31.png"), SKTexture(imageNamed: "rocket32.png"), SKTexture(imageNamed: "rocket33.png"), SKTexture(imageNamed: "rocket34.png"), SKTexture(imageNamed: "rocket35.png"), SKTexture(imageNamed: "rocket36.png")]
let rocketAnim = SKAction.animate(with: rocketAnimArray, timePerFrame: 0.016)
let rocketAnimForever = SKAction.repeatForever(rocketAnim)
rocket.position = position
rocket.size.height = 26
rocket.size.width = 64
let moveRocket = SKAction.moveBy(x: -rocketTex.size().width*1.7, y: 0, duration: 3)
rocket.run(SKAction.sequence([rocketAnimForever,moveRocket, SKAction.removeFromParent()]),withKey:"rocketFly")
rocketObject.addChild(rocket)
}
I create animation of rocket with this code, and a make SKAction.moveBy that works with simple textures, but dont works with animation. Can you help me how to move SKAction.animate?

In this line:
rocket.run(SKAction.sequence([rocketAnimForever,moveRocket, SKAction.removeFromParent()]),withKey:"rocketFly")
You are telling the sprite node to run an action forever (rocketAnimForever) and after that action finishes, move the rocket and remove it from parent. Since the first action carries on forever, you will never reach the other two actions.
To fix this, you need to run the rocketAnimForever action at the same time as the move and remove from parent action sequence.
First, we can use sequence to create a sequence of the last two actions:
let moveAndRemoveSequence = SKAction.sequence([moveRocket, SKAction.removeFromParent()])
Then, we use the group method to group the animation action and the action sequence together so that they run at the same time:
let wholeAction = SKAction.group([rocketAnimForever, moveAndRemoveSequence])
Now you can run the wholeAction:
rocket.run(wholeAction, withKey: "rocketFly")

Related

Change SKTextureFilteringMode for all SKTextures

Is there a way to assign the filteringMode attribute to SKTextureFilteringMode.nearest for ALL SKTextures? Other than assigning to each texture individually. The following works fine, but I'd rather that I didn't have to iterate over the textures, but just set a default for the filtering mode. Is this possible?
func walk () -> SKAction {
let walkTexture1 = SKTexture(imageNamed: "walk1.png")
let walkTexture2 = SKTexture(imageNamed: "walk2.png")
let walkTexture3 = SKTexture(imageNamed: "walk3.png")
let walkTexture4 = SKTexture(imageNamed: "walk4.png")
let walkTexture5 = SKTexture(imageNamed: "walk5.png")
let animationTextures: [SKTexture] = [walkTexture1, walkTexture2, walkTexture3, walkTexture4, walkTexture5]
for texture in animationTextures {
texture.filteringMode = SKTextureFilteringMode.nearest
}
let walkAnimation = SKAction.animate(with: animationTextures, timePerFrame: 0.3/5)
return walkAnimation
Create textures and set properties in the same loop
let textures = (1...5).map {
let texture = SKTexture(imageNamed: "walk\($0).png")
texture.filteringMode = SKTextureFilteringMode.nearest
return texture
}
or just set properties using forEach
textures.forEach {
$0.filteringMode = .nearest
}
You could perhaps make an extension to SKTexture, something like this:
extension SKTexture {
class func pixeled(imageNamed imageName: String) -> SKTexture {
let texture = SKTexture(imageNamed: imageName)
texture.filteringMode = .nearest
return texture
}
}
Then you'll simply have
let walkTexture1 = SKTexture.pixeled(imageNamed: "walk1.png")
etc.

SpriteNode animation is failing

I have been trying to have a sprite with more than one texture so that it looks as if it was moving. I was looking at other questions and nothing they have done has fixed my issue, this is my code:
var textures = [SKTexture]()
for x in 0...2 {
let texture = SKTexture(imageNamed: "peng_" + String(x))
textures.append(texture)
print("pen_" + String(x))
}
let pen = SKSpriteNode(imageNamed: "peng_0")
self.addChild(pen)
let action = SKAction.animate(withNormalTextures: textures, timePerFrame: 0.1, resize: false, restore: true)
pen.run(SKAction.repeatForever(action))
When I run the simulation, the sprite stays still with the "peng_0" texture, but I want it to iterate the other textures every 0.1s
Does anyone know what am I doing wrong, thanks.
Here you go set your code like this
var array = ["R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8"]
var textures:[SKTexture] = []
for i in 0 ..< array.count{
let texture: SKTexture = SKTexture(imageNamed: array[i])
textures.insert(texture, at:i)
}
let pen = SKSpriteNode(imageNamed: "R1")
self.addChild(pen)
let animation = SKAction.animate(with: textures, timePerFrame: 8/60, resize: true , restore:false )
pen.run = SKAction.repeatForever(animation)

Make explosion animation SKaction and remove

I want to make a animation to my game when two sprite nodes have a collision. So i create this function :
func contactEntreMeteorites(Meteorites : SKSpriteNode , Meteorites2 : SKSpriteNode){
Meteorites.removeFromParent()
Meteorites2.removeFromParent()
let ExplosionTexture1 = SKTexture(imageNamed: "Explosion1.png")
let ExplosionTexture2 = SKTexture(imageNamed: "Explosion2.png")
let ExplosionTexture3 = SKTexture(imageNamed: "Explosion3.png")
let ExplosionTexture4 = SKTexture(imageNamed: "Explosion4.png")
let ExplosionTexture5 = SKTexture(imageNamed: "Explosion5.png")
let ExplosionTexture6 = SKTexture(imageNamed: "Explosion6.png")
let ExplosionTexture7 = SKTexture(imageNamed: "Explosion7.png")
let ExplosionTexture8 = SKTexture(imageNamed: "Explosion8.png")
let ExplosionTexture9 = SKTexture(imageNamed: "Explosion9.png")
let ExplosionTexture10 = SKTexture(imageNamed: "Explosion10.png")
let ExplosionTexture11 = SKTexture(imageNamed: "Explosion11.png")
let ExplosionTexture12 = SKTexture(imageNamed: "Explosion12.png")
let animateExplosion = SKAction.sequence([
SKAction.waitForDuration(0, withRange: 0),
SKAction.animateWithTextures([ExplosionTexture1,ExplosionTexture2,ExplosionTexture3,ExplosionTexture4,ExplosionTexture5,ExplosionTexture6,ExplosionTexture7,ExplosionTexture8,ExplosionTexture9,ExplosionTexture10,ExplosionTexture11,ExplosionTexture12 ], timePerFrame: 0.1)
])
Explosion = SKSpriteNode(texture: ExplosionTexture1)
Explosion.position = CGPointMake(Meteorites.position.x, Meteorites.position.y)
Explosion.runAction(animateExplosion)
self.addChild(Explosion)
}
This code works perfectly but I don't know how can I delete the SpriteNode "Explosion" when my SKAction sequence animateExplosion is finished.
Thanks for helping :) And sorry for my english i'm french ;)
You've implemented the wrong method. Instead of runAction:, implement runAction:completion:. The completion method will be called on completion! So that is the place to remove the explosion node.
So this is the solution :
Explosion = SKSpriteNode(texture: ExplosionTexture1)
Explosion.position = CGPointMake(Meteorites.position.x, Meteorites.position.y)
self.addChild(Explosion)
Explosion.runAction(animateExplosion, completion : {self.Explosion.removeFromParent()})

Swift - how to fix when adding a Physics Body removes sprite node from scene

I'm fairly new to programming and can't seem to figure out this Physics World issue. When I add a physics body to my sprite node, i can no longer see the sprite node in the scene.
Code:
func createBird() {
let randomSpawn = Int(arc4random_uniform(2))
if randomSpawn == 1 {
let newX = Int(-20)
let newY = Int(arc4random_uniform(500) + 300)
var p = CGPoint(x: newX, y: newY)
var destination = CGPoint(x:Int(self.frame.width+21), y:newY)
var moverSpeed = Int(arc4random_uniform(5) + 3)
let birdRight = SKSpriteNode (imageNamed: "bird-right1")
birdRight.xScale = 0.6
birdRight.yScale = 0.6
birdRight.position = p
birdRight.zPosition = 2
//birdRight.physicsBody = SKPhysicsBody(rectangleOfSize: birdRight.size)
birdRight.physicsBody?.dynamic = true
birdRight.physicsBody?.categoryBitMask = birdCategory
birdRight.physicsBody?.contactTestBitMask = ballCategory
birdRight.physicsBody?.collisionBitMask = 0
let birdMoveRight = SKAction.animateWithTextures([
SKTexture(imageNamed: "bird-right1"),
SKTexture(imageNamed: "bird-right2"),
SKTexture(imageNamed: "bird-right3"),
SKTexture(imageNamed: "bird-right4"),
SKTexture(imageNamed: "bird-right5"),
SKTexture(imageNamed: "bird-right6"),
SKTexture(imageNamed: "bird-right7"),
SKTexture(imageNamed: "bird-right8"),
SKTexture(imageNamed: "bird-right9"),
SKTexture(imageNamed: "bird-right10")
], timePerFrame: 0.05)
let foreverAction = SKAction.repeatActionForever(birdMoveRight)
birdRight.runAction(foreverAction)
let duration = NSTimeInterval(moverSpeed)
let action = SKAction.moveTo(destination, duration: duration)
birdRight.runAction(action)
addChild(birdRight)
}
else {
let newX = Int(self.frame.width+20)
let newY = Int(arc4random_uniform(500) + 300)
var p = CGPoint(x: newX, y: newY)
var destination = CGPoint(x:-21, y:newY)
var moverSpeed = Int(arc4random_uniform(5) + 3)
let birdLeft = SKSpriteNode(imageNamed: "bird-left1")
birdLeft.xScale = 0.6
birdLeft.yScale = 0.6
birdLeft.position = p
birdLeft.zPosition = 2
let birdMoveLeft = SKAction.animateWithTextures([
SKTexture(imageNamed: "bird-left1"),
SKTexture(imageNamed: "bird-left2"),
SKTexture(imageNamed: "bird-left3"),
SKTexture(imageNamed: "bird-left4"),
SKTexture(imageNamed: "bird-left5"),
SKTexture(imageNamed: "bird-left6"),
SKTexture(imageNamed: "bird-left7"),
SKTexture(imageNamed: "bird-left8"),
SKTexture(imageNamed: "bird-left9"),
SKTexture(imageNamed: "bird-left10")
], timePerFrame: 0.05)
birdLeft.physicsBody = SKPhysicsBody(rectangleOfSize: birdLeft.size)
birdLeft.physicsBody?.dynamic = false
birdLeft.physicsBody?.categoryBitMask = birdCategory
birdLeft.physicsBody?.contactTestBitMask = ballCategory
birdLeft.physicsBody?.collisionBitMask = 0
let foreverAction = SKAction.repeatActionForever(birdMoveLeft)
birdLeft.runAction(foreverAction)
let duration = NSTimeInterval(moverSpeed)
let action = SKAction.moveTo(destination, duration: duration)
birdLeft.runAction(action)
addChild(birdLeft)
}
}
Maybe it is affected by gravity and get dragged all the way down before you even see the object on your screen?
Try this:
birdRight.physicsBody?.affectedByGravity = false

SpriteKit: 'String' is not convertible to 'DictionaryIndex<String, SKTexture>'

whilst programming a SKAction.animateWithTextures(...) I came across this error ('String'is not convertible to 'DictionaryIndex') when I used the String keys of my 'states' to retrieve the SKTexture relevant. Can someone explain what might be the cause of the error?
import SpriteKit
class Player {
let states: Dictionary<String, SKTexture> = [
"standing": SKTexture(imageNamed: "standing"),
"right1": SKTexture(imageNamed: "right1"),
"right2": SKTexture(imageNamed: "right2"),
"right3": SKTexture(imageNamed: "right3"),
"left1": SKTexture(imageNamed: "left1"),
"left2": SKTexture(imageNamed: "left2"),
"left3": SKTexture(imageNamed: "left3")
]
let LEFT: UInt32 = 1 << 0
let FRONT: UInt32 = 1 << 1
let RIGHT: UInt32 = 1 << 2
var node: SKSpriteNode!
var status: UInt32!
let delay = SKAction.waitForDuration(NSTimeInterval(0.1))
var runLeft: SKAction!
var runRight: SKAction!
init(){
for state in states {
state.1.filteringMode = .Nearest
}
node = SKSpriteNode(texture: states["standing"])
node.physicsBody = SKPhysicsBody(rectangleOfSize: node.size)
node.physicsBody.dynamic = false
status = FRONT
runLeft = SKAction.animateWithTextures([states["left1"], states["left2"], states["left1"], states["left3"]]!, timePerFrame: 0.1)
runRight = SKAction.animateWithTextures([states["right1"], states["right2"], states["right1"], states["right3"]]!, timePerFrame: 0.1)
}
}
Dictionary lookups return optionals because the key might not exist. You need to unwrap each of the lookups since they are type SKTexture!:
runLeft = SKAction.animateWithTextures([states["left1"]!, states["left2"]!, states["left1"]!, states["left3"]!], timePerFrame: 0.1)
runRight = SKAction.animateWithTextures([states["right1"]!, states["right2"]!, states["right1"]!, states["right3"]!], timePerFrame: 0.1)