3

我正在尝试在 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.

然后,我希望纹理图集在调用 touches end 动作后返回动画。

任何帮助将不胜感激。

更新:

我已经实现了你的建议,但它仍然不能完全正确地工作。英雄正在切换到跳跃图像,但实际上并没有跳跃并且卡在跳跃图像中。

我创建了一个 JumpImages.atlas 并将“Jump”图像添加到该文件夹​​中。

我已将代码修改为以下内容:

导入 UIKit 导入 SpriteKit

级别 1: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()
    }

}

}

}

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

4

1 回答 1

4

既然你已经让你的精灵奔跑了,那么跳跃并不是一件难事。只需在适当的位置用跳跃动画的纹理替换跑步动画的纹理即可。

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

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. 对于演示,我只是添加一帧动画用于跳跃。在你创建textureAtlasspriteArrayfor之后添加这些行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()
        }
    }
}

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

在此处输入图像描述

于 2015-09-16T03:15:20.190 回答