Как заменить изображение SKSpriteNode на время действия, а затем вернуть его в исходный цикл атласа текстуры

Я пытаюсь сделать базовую игру «беги и прыгай» в SpriteKit.

Когда представление загружается, я хочу, чтобы узел спрайта был Run с использованием изображений из атласа текстур. Это мне удалось сделать.

При касании экрана я хочу, чтобы это изображение изменилось на другое изображение в атласе текстур под названием Jump.

Когда персонаж возвращается на землю, я хочу, чтобы он вернулся к исходной петле текстурного атласа.

До сих пор я закодировал следующее:

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.

Затем я хочу, чтобы атлас текстур вернулся к анимации после вызова действия, завершающего касание.

Любая помощь будет принята с благодарностью.

Обновлять:

Я реализовал то, что вы предложили, но это все еще работает не совсем корректно. Герой меняется на изображение прыжка, но на самом деле не прыгает и застревает в образе прыжка.

Я создал JumpImages.atlas и добавил изображение «Jump» в эту папку.

Я изменил код на следующее:

импортировать UIKit импортировать SpriteKit

класс 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()
    }

}

}

}

Есть ли что-то очевидное, что я делаю неправильно? Спасибо за вашу помощь.


person Fiducial13    schedule 15.09.2015    source источник
comment
Более привычно писать комментарий прямо перед кодом.   -  person WangYudong    schedule 16.09.2015
comment
Спасибо, я тоже поменял.   -  person Fiducial13    schedule 16.09.2015
comment
Я посмотрю позже.   -  person WangYudong    schedule 17.09.2015


Ответы (1)


Поскольку вы уже заставили свой спрайт бегать, прыгать не составит труда. Просто замените текстуру анимации бега на текстуру анимации прыжка в нужном месте.

Во-первых, я оборачиваю код анимации бега для последующего повторного использования.

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. Для демонстрации я просто добавляю анимацию одного кадра для прыжков. Добавьте эти строки после создания textureAtlas и spriteArray для Run.

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.

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

Теперь вы должны получить результат ниже. Если у вас возникли проблемы с кодом, просто дайте мне знать.

введите здесь описание изображения

person WangYudong    schedule 16.09.2015
comment
@ Fiducial13 Вы пропустили две строки в методе update в отредактированном коде. Это self.velocityY += self.gravity и self.Hero.position.y -= velocityY, которые заставляют спрайт прыгать. - person WangYudong; 17.09.2015