如何在动作持续期间替换 SKSpriteNode 的图像,然后 return 将其替换为原始纹理图集循环

How do I replace an image of an SKSpriteNode for the duration of an action then return it to it's original texture atlas loop

我正在尝试在 SpriteKit 中制作一个基本的 运行 和跳跃游戏。

当视图加载时,我希望精灵节点 Run 使用来自纹理图集的图像。我做到了。

当屏幕被触摸时,我希望这张图片变成纹理图集中另一张名为 Jump 的图片。

当角色return落地时我希望它回到原来的纹理图集循环。

到目前为止,我已经编写了以下代码:

import UIKit
import SpriteKit

class Level1: SKScene {
    var Hero : SKSpriteNode!
    //Creates an object for the Hero character.

    let textureAtlas = SKTextureAtlas(named:"RunImages.atlas")
    //Specifies the image atlas used.

    var spriteArray = Array<SKTexture>();
    //Creates a variable for the image atlas of him running.

    var HeroBaseLine = CGFloat (0)
    //This is where the Hero character sits on top of the ground.

    var onGround = true
    //Creates a variable to specify if Hero is on the ground.

    var velocityY = CGFloat (0)
    //Creates a variable to hold a three decimal point specification for velocity in the Y axis.

    let gravity = CGFloat (0.6)
    //Creates a non variable setting for gravity in the scene.

    let movingGround = SKSpriteNode (imageNamed: "Ground")
    //Creates an object for the moving ground and assigns the Ground image to it.

    var originalMovingGroundPositionX = CGFloat (0)
    //Sets a variable for the original ground position before it starts to move.

    var MaxGroundX = CGFloat (0)
    //Sets a variable for the maximum

    var groundSpeed = 4
    //Sets the ground speed.  This number is how many pixels it will move the ground to the left every frame.

    override func didMoveToView(view: SKView) {
        //Misc setup tasks.

        backgroundColor = (UIColor.blackColor())
        //Sets the background colour when the view loads.

        //Ground related tasks.

        self.movingGround.anchorPoint = CGPointMake(0, 0.5)
        //Positions the Ground image hard left in the X axis.

        self.movingGround.position = CGPointMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame) + (self.movingGround.size.height / 2))
        //Positions the Ground image at the bottom of the screen relative to half the height of the image.

        self.addChild(self.movingGround)
        //Creates an instance of the Ground image that follows the parameters set in the lines above when the view loads.

        self.originalMovingGroundPositionX = self.movingGround.position.x
        //Sets the starting position for the ground image in the x before it start to move.

        self.MaxGroundX = self.movingGround.size.width - self.frame.size.width
        //Sets the maximum ground size minus the width of the screen to create the loop point in the image.

        self.MaxGroundX *= -1
        //This multiplies the size of the ground by itself and makes the max ground size a negative number as the image is moving towards the left in x which is negative.

        //Hero related tasks.

        spriteArray.append(textureAtlas.textureNamed("Run1"));
        spriteArray.append(textureAtlas.textureNamed("Run2"));
        spriteArray.append(textureAtlas.textureNamed("Run3"));
        spriteArray.append(textureAtlas.textureNamed("Run2"));

        Hero = SKSpriteNode(texture:spriteArray[0]);

        self.HeroBaseLine = self.movingGround.position.y + (self.movingGround.size.height / 2) + 25

        //self.Hero.position = CGPointMake(CGRectGetMinX(self.frame) + 50, self.HeroBaseLine)

        self.Hero.position = CGPointMake(CGRectGetMinX(self.frame) + 50, self.HeroBaseLine)
        //Sets where the character will appear exactly.

        self.Hero.xScale = 0.15
        self.Hero.yScale = 0.15

        addChild(self.Hero);
        //Adds an instance of Hero to the screen.

        let animateAction = SKAction.animateWithTextures(self.spriteArray, timePerFrame: 0.15);
        let moveAction = SKAction.moveBy(CGVector(dx: 0,dy: 0), duration: 0.0);
        //Although currently set to 0, the above line controls the displacement of the character in the x and y axis if required.
        let group = SKAction.group([ animateAction,moveAction]);
        let repeatAction = SKAction.repeatActionForever(group);
        self.Hero.runAction(repeatAction);
        //Animation action to make him run.  Here we can affect the frames and x, y movement, etc.
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if self.onGround {
            self.velocityY = -18
            self.onGround = false
        }
    }
    //This block specifies what happens when the screen is touched.

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if self.velocityY < -9.0 {
            self.velocityY = -9.0
        }
    }
    //This block prevents Hero from jumping whilst already jumping.

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */

        if self.movingGround.position.x <= MaxGroundX {
            self.movingGround.position.x = self.originalMovingGroundPositionX
        }
        //This is how the ground is positioned at the beginning of each update (each frame refresh)

        movingGround.position.x -= CGFloat (self.groundSpeed)
        //This is how the ground is moved relative to the ground speed variable set at the top.  The number in the variable is how many pixels the frame is being moved each frame refresh.

        self.velocityY += self.gravity
        self.Hero.position.y -= velocityY

        if self.Hero.position.y < self.HeroBaseLine {
            self.Hero.position.y = self.HeroBaseLine
            velocityY = 0.0
            self.onGround = true
        }
        //This is the code for making Hero jump in accordance to the velocity and gravity specified at the top of the class in relation to the base line.
    }
}

我已尝试在 touchesBegan 部分添加代码,以将精灵节点的图像纹理更改为我的图像图集中名为 Jump 的另一幅图像。

然后我希望纹理图集 return 在调用触摸结束操作后进行动画处理。

如有任何帮助,我们将不胜感激。

更新:

我已经实施了您的建议,但仍然无法正常工作。英雄正在切换为跳跃画面,但实际上并没有跳跃,卡在了跳跃画面中

我创建了一个 JumpImages.atlas 并将 "Jump" 图片添加到该文件夹​​。

我修改了代码如下:

导入 UIKit 导入 SpriteKit

class Level1: SKScene {

//Creates an object for the Hero character.    

var Hero : SKSpriteNode!

//Specifies the image atlas used.

let textureAtlas = SKTextureAtlas(named:"RunImages.atlas")

//Creates a variable for the image atlas of him running.

var spriteArray = Array<SKTexture>();




var jumpArray = Array<SKTexture>();

let jumpAtlas = SKTextureAtlas(named:"JumpImages.atlas")

//jumpArray.append(jumpAtlas.textureNamed("Jump"))  Didn't work in this area, moved it to the did move to view.




//This is where the Hero character sits on top of the ground.

var HeroBaseLine = CGFloat (0)

//Creates a variable to specify if Hero is on the ground.

var onGround = true

//Creates a variable to hold a three decimal point specification for velocity in the Y axis.

var velocityY = CGFloat (0)

//Creates a non variable setting for gravity in the scene.

let gravity = CGFloat (0.6)




//Creates an object for the moving ground and assigns the Ground image to it.    

let movingGround = SKSpriteNode (imageNamed: "Ground")

//Sets a variable for the original ground position before it starts to move.

var originalMovingGroundPositionX = CGFloat (0)

//Sets a variable for the maximum

var MaxGroundX = CGFloat (0)

//Sets the ground speed.  This number is how many pixels it will move the ground to the left every frame.

var groundSpeed = 4




override func didMoveToView(view: SKView) {

    //Misc setup tasks.

    //Sets the background colour when the view loads.        

    backgroundColor = (UIColor.blackColor())




    //Ground related tasks.

    //Positions the Ground image hard left in the X axis.

    self.movingGround.anchorPoint = CGPointMake(0, 0.5)

    //Positions the Ground image at the bottom of the screen relative to half the height of the image.

    self.movingGround.position = CGPointMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame) + (self.movingGround.size.height / 2))

    //Creates an instance of the Ground image that follows the parameters set in the lines above when the view loads.

    self.addChild(self.movingGround)

    //Sets the starting position for the ground image in the x before it start to move.

    self.originalMovingGroundPositionX = self.movingGround.position.x

    //Sets the maximum ground size minus the witdth of the screen to create the loop point in the image.

    self.MaxGroundX = self.movingGround.size.width - self.frame.size.width

    //This multiplies the size of the ground by itself and makes the max ground size a negative number as the image is moving towards the left in x which is negative.

    self.MaxGroundX *= -1





    //Hero related tasks.

    spriteArray.append(textureAtlas.textureNamed("Run1"));
    spriteArray.append(textureAtlas.textureNamed("Run2"));
    spriteArray.append(textureAtlas.textureNamed("Run3"));
    spriteArray.append(textureAtlas.textureNamed("Run2"));

    Hero = SKSpriteNode(texture:spriteArray[0]);

    self.HeroBaseLine = self.movingGround.position.y + (self.movingGround.size.height / 2) + 25

    //Sets where the character will appear exactly.

    self.Hero.position = CGPointMake(CGRectGetMinX(self.frame) + 50, self.HeroBaseLine)

    //Scales the image to an appropriate size.

    self.Hero.xScale = 0.15
    self.Hero.yScale = 0.15

    //Adds an instance of Hero to the screen.

    addChild(self.Hero);




    //Added this here as it didn't appear to work in the place recommended.

    jumpArray.append(jumpAtlas.textureNamed("Jump"));




    //I added this so that he runs when the view loads.

    if self.onGround {
        run()
    }

}

    //Animation function to make him run.  Here we can affect the frames and x, y movement, etc.

    func run() {
        let animateAction = SKAction.animateWithTextures(self.spriteArray, timePerFrame: 0.15);
        //Although currently set to 0, the above line controls the displacement of the character in the x and y axis if required.
        let moveAction = SKAction.moveBy(CGVector(dx: 0,dy: 0), duration: 0.0);
        let group = SKAction.group([animateAction,moveAction]);
        let repeatAction = SKAction.repeatActionForever(group);
        self.Hero.runAction(repeatAction);
    }




    //Animation function to make him jump.

    func jump() {

        self.velocityY = -18
        self.onGround = false

        let jumpAnimation = SKAction.animateWithTextures(jumpArray, timePerFrame: 0.15)
        self.Hero.runAction(SKAction.repeatActionForever(jumpAnimation))
    }




override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    //This block specifies what happens when the screen is touched.

    if self.onGround {
        jump()
    }
}




override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    //This block prevents Hero from jumping whilst already jumping.

    if self.velocityY < -9.0 {
        self.velocityY = -9.0
    }
}




override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */


    //This is how the ground is positioned at the beginning of each update (each frame refresh)

    if self.movingGround.position.x <= MaxGroundX {
        self.movingGround.position.x = self.originalMovingGroundPositionX
    }


    //This is how the ground is moved relative to the ground speed variable set at the top.  The number in the variable is how many pixels the frame is being moved each frame refresh.

    movingGround.position.x -= CGFloat (self.groundSpeed)


    //This is the code for making Hero jump in accordance to the velocity and gravity specified at the top of the class in realation to the base line and run when he hits the ground.

    if self.Hero.position.y < self.HeroBaseLine {
        self.Hero.position.y = self.HeroBaseLine
        velocityY = 0.0
        if self.onGround == false {
            self.onGround = true

            run()
    }

}

}

}

有什么明显的我做错了吗?感谢您的帮助。

既然你已经制作了你的精灵运行,那么跳跃并不是一件难事。把运行动画的贴图替换成跳跃动画的贴图在合适的地方即可。

首先,我将运行动画的代码封装起来,以备后用。

func run() {
    let animateAction = SKAction.animateWithTextures(self.spriteArray, timePerFrame: 0.15);
    let moveAction = SKAction.moveBy(CGVector(dx: 0,dy: 0), duration: 0.0);
    let group = SKAction.group([animateAction,moveAction]);
    let repeatAction = SKAction.repeatActionForever(group);
    self.Hero.runAction(repeatAction);
}

下一步是 Jump 的纹理图集。为了演示,我只添加了一帧动画用于跳跃。在为 Run.

创建 textureAtlasspriteArray 后添加这些行
var jumpArray = Array<SKTexture>()
let jumpAtlas = SKTextureAtlas(named:"JumpImages.atlas")
jumpArray.append(jumpAtlas.textureNamed("Jump"))

写好函数jump()后,就可以在touchesBegan中调用了。

func jump() {
    self.velocityY = -18
    self.onGround = false
    println("jump over ground")

    let jumpAnimation = SKAction.animateWithTextures(jumpArray, timePerFrame: 0.15)
    self.Hero.runAction(SKAction.repeatActionForever(jumpAnimation))
}

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
    if self.onGround {
        jump()
    }
}

最后但同样重要的是,在 update 回到地面后恢复 运行ning 动画。

override func update(currentTime: CFTimeInterval) {
    ...

    if self.Hero.position.y < self.HeroBaseLine {
        self.Hero.position.y = self.HeroBaseLine
        velocityY = 0.0
        if self.onGround == false {
            self.onGround = true
            println("on the ground")

            run()
        }
    }
}

现在你应该得到下面的结果。如果您对代码有任何疑问,请告诉我。