我正在使用SpriteKit在Swift中制作一个简单的RPG。我写了一个字符类来帮助我处理所有的动画,我在动画方面遇到了一些麻烦。
角色等级:
class Character: SKSpriteNode {
var walkSouthArray = [SKTexture]()
var walkNorthArray = [SKTexture]()
var walkEastArray = [SKTexture]()
var walkWestArray = [SKTexture]()
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: nil, color: UIColor.clear, size: CGSize(width: 100, height: 150))
self = CGSize(width: 100, height: 150)
self.position = CGPoint(x: 0, y: 0)
self.texture = SKTexture(imageNamed: "walk_south_1")
let northAtlas = SKTextureAtlas(named: "walk_north")
var northFrames:[SKTexture] = []
for index in 1 ... 8 {
let textureName = "walk_north_\(index)"
let texture = northAtlas.textureNamed(textureName)
northFrames.append(texture)
walkNorthArray = northFrames
}
let southAtlas = SKTextureAtlas(named: "walk_south")
var southFrames:[SKTexture] = []
for index in 1 ... 8 {
let textureName = "walk_south_\(index)"
let texture = southAtlas.textureNamed(textureName)
southFrames.append(texture)
walkSouthArray = southFrames
}
let eastAtlas = SKTextureAtlas(named: "walk_east")
var eastFrames:[SKTexture] = []
for index in 1 ... 8 {
let textureName = "walk_east_\(index)"
let texture = eastAtlas.textureNamed(textureName)
eastFrames.append(texture)
walkEastArray = eastFrames
}
let westAtlas = SKTextureAtlas(named: "walk_west")
var westFrames:[SKTexture] = []
for index in 1 ... 8 {
let textureName = "walk_\(index)"
let texture = westAtlas.textureNamed(textureName)
westFrames.append(texture)
walkWestArray = westFrames
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func walkNorth() {
self.run(SKAction.repeatForever(SKAction.animate(with: walkNorthArray, timePerFrame: 0.2)))
}
func walkSouth() {
self.run(SKAction.repeatForever(SKAction.animate(with: walkSouthArray, timePerFrame: 0.2)))
}
func walkEast() {
self.run(SKAction.repeatForever(SKAction.animate(with: walkEastArray, timePerFrame: 0.2)))
}
func walkWest() {
self.run(SKAction.repeatForever(SKAction.animate(with: walkWestArray, timePerFrame: 0.2)))
}
}
尚未绘制Walk West的框架
游戏场景类:
class GameScene: SKScene {
var v = CGVector()
var xJoystickDelta = CGFloat()
var yJoystickDelta = CGFloat()
var UINode = SKNode()
var WorldNode = SKNode()
var character = Character()
var DPad = SKSpriteNode()
var thumbNode = SKSpriteNode()
var isTracking:Bool = false
override func didMove(to view: SKView) {
DPad = SKSpriteNode(texture: SKTexture(imageNamed: "base"))
DPad.size = CGSize(width: 150, height: 150)
DPad.position = CGPoint(x: -200, y: -100)
DPad.zPosition = 3
UINode.addChild(DPad)
thumbNode = SKSpriteNode(texture: SKTexture(imageNamed: "stick"))
thumbNode.size = CGSize(width: 50, height: 50)
thumbNode.position = CGPoint(x: -200, y: -100)
thumbNode.zPosition = 4
UINode.addChild(thumbNode)
self.addChild(UINode)
self.addChild(character)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if isTracking == false && DPad.contains(location) {
isTracking = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location: CGPoint = touch.location(in: self)
if isTracking == true {
v = CGVector(dx: location.x - DPad.position.x, dy: location.y - DPad.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / Double.pi)
let Length:CGFloat = DPad.frame.size.height / 2
let xDist: CGFloat = sin(angle - 1.57079633) * Length
let yDist: CGFloat = cos(angle - 1.57079633) * Length
xJoystickDelta = location.x - DPad.position.x
yJoystickDelta = location.y - DPad.position.y
if DPad.contains(location) {
thumbNode.position = location
} else {
thumbNode.position = CGPoint(x: DPad.position.x - xDist, y: DPad.position.y + yDist)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTracking = false
thumbNode.run(SKAction.move(to: CGPoint(x: -200, y: -100), duration: 0.01))
xJoystickDelta = 0
yJoystickDelta = 0
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if v.dx > abs(v.dy) {
// right
character.walkEast()
} else if v.dx < -abs(v.dy) {
// left
character.walkWest()
} else if v.dy > 0 {
// up
character.walkNorth()
} else if v.dy < 0 {
// down
character.walkSouth()
}
}
}
它以这样的方式设置,所以我所要做的就是调用动画的函数。当我打电话给他们时,我得到的是一张静止图像(Atlas中的第一张图片)
据我所知,我的地图集已正确设置:
我单击“+”按钮并选择“New Sprite Atlas”然后将我的图像拖放到新文件夹中并重命名。
答案 0 :(得分:1)
在更新周期中做事时要小心。
对于大多数设备,此操作默认以60 FPS运行,因此其中的任何命令都将以该速率触发。
在您的特定情况下,您在每次更新时都添加了一个新的动画操作,因此就应用程序而言,它正在绘制动画,但您继续添加新的开始动画。
因为你没有&#34; X-Ray&#34;视觉,你无法透过最顶层的动画层来注意下面绘制的其他动画。 (这只是概念,当然,系统并没有真正将层叠在一起)
我建议您更改代码,以便只调用一次动画,并将其从更新周期中删除。
我喜欢住的好规则就是:
如果每帧都没有发生变化,那么不要在更新功能中包含处理它的代码
这意味着如果然后检查if v.dx > abs(v.dy)
,则删除浪费时间,因为如果v.dx
&gt;不需要检查每一帧v.dy
,我们只需要在dx
或dy
更改时进行检查。
在您的情况下,这发生在touchedMoved
事件期间。
在此功能中更改v后,请执行更新功能中的代码以运行动画。
当然,您还需要删除其他移动动作,这样您就不会加倍动作。
您的代码应如下所示:
class GameScene: SKScene {
enum Direction
{
case none
case up
case down
case left
case right
}
var charDir = Direction.none
var v = CGVector()
var xJoystickDelta = CGFloat()
var yJoystickDelta = CGFloat()
var UINode = SKNode()
var WorldNode = SKNode()
var character = Character()
var DPad = SKSpriteNode()
var thumbNode = SKSpriteNode()
var isTracking:Bool = false
override func didMove(to view: SKView) {
DPad = SKSpriteNode(texture: SKTexture(imageNamed: "base"))
DPad.size = CGSize(width: 150, height: 150)
DPad.position = CGPoint(x: -200, y: -100)
DPad.zPosition = 3
UINode.addChild(DPad)
thumbNode = SKSpriteNode(texture: SKTexture(imageNamed: "stick"))
thumbNode.size = CGSize(width: 50, height: 50)
thumbNode.position = CGPoint(x: -200, y: -100)
thumbNode.zPosition = 4
UINode.addChild(thumbNode)
self.addChild(UINode)
self.addChild(character)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if isTracking == false && DPad.contains(location) {
isTracking = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location: CGPoint = touch.location(in: self)
if isTracking == true {
v = CGVector(dx: location.x - DPad.position.x, dy: location.y - DPad.position.y)
var newDirection = Direction.none
if v.dx > abs(v.dy) {
// right
newDirection = .right
} else if v.dx < -abs(v.dy) {
// left
newDirection = .left
} else if v.dy > 0 {
// up
newDirection = .up
} else if v.dy < 0 {
// down
newDirection = .down
}
if charDir != newDirection
{
charDir = newDirection
character.removeAllActions()
switch charDir{
case .right: character.walkEast()
case .left: character.walkWest()
case .up: character.walkNorth()
case .down: character.walkSouth()
default: break
}
}
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / Double.pi)
let Length:CGFloat = DPad.frame.size.height / 2
let xDist: CGFloat = sin(angle - 1.57079633) * Length
let yDist: CGFloat = cos(angle - 1.57079633) * Length
xJoystickDelta = location.x - DPad.position.x
yJoystickDelta = location.y - DPad.position.y
if DPad.contains(location) {
thumbNode.position = location
} else {
thumbNode.position = CGPoint(x: DPad.position.x - xDist, y: DPad.position.y + yDist)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTracking = false
thumbNode.run(SKAction.move(to: CGPoint(x: -200, y: -100), duration: 0.01))
xJoystickDelta = 0
yJoystickDelta = 0
}
override func update(_ currentTime: TimeInterval) {
}
}
如果您的角色正在进行其他操作,您可能需要考虑为动画分配一个键。