玩家状态机-使用GameplayKit管理不同的状态和动画

在本节中,我们将了解GameplayKit状态机,然后我们将让我们的玩家跳转并给他一些其他动画,所以扣紧并为这一知识的骑行做好准备。

下载PlayerState Machine 玩家状态机

要学习本教程,您将需要Xcode 9,您可以下载最终项目,以帮助您与自己的进度进行比较。

GameplayKit状态机

首先,我们需要了解玩家的所有不同状态,因为我们将把它们应用到我们的游戏中。

playerStateMachine

LandingState

LandingState是玩家接触地面的时间。

IdleState

IdleState是玩家静止时的动画。

WalkingState

WalkingState是玩家走路时的动画。

JumpingState

JumpingState是玩家跳跃和动作的动画。

StunnedState

最后,StunnedState是玩家被陷阱或敌人触碰时的动画。

状态

正如您在上图中所注意到的那样,所有状态都是相互连接的,这意味着所有状态都以不同的方式相关。

建立

让我们创建一个新的Swift文件,你可以按Command和N来创建新文件。将出现一个新窗口,确保您在iOS平台上并选择Swift File模板并单击Next。然后,我们将被要求命名该文件。我们将其称为“playerStateMachine”,我们将其保存在我们的初始文件夹ElonGame中并点击Create。

GameplayKit

现在,我们需要研究游戏的逻辑,所以我们需要调用GameplayKit框架。GameplayKit与游戏的逻辑更相关,因为SpriteKit用于游戏的视觉部分。让我们将GameplayKit导入我们的新文档。

为玩家状态导入玩家动画和类

接下来,我们将调用所有玩家动画,稍后,我们将为PlayerState创建一个类。在能够接收状态之前必须初始化玩家。我们将添加的所有代码将在导入GameplayKit后立即生效

我们正在使用名称characterAnimationKey重新组合所有动画。在PlayerState类中,我们将playerNode初始化为SKNode,并使他能够接收动画和动作状态。这些状态仅适用于playerNode。

跳跃状态 Jumping State 类

我们将添加一个跳跃状态类JumpingState来管理跳跃动作。在这个类中,我们需要创建两个函数。第一个isValidNextState是一个指示器,它将告诉我们当前状态是否允许转换到下一个状态。我们现在将默认返回值设置为true。第二个函数didEnter将帮助我们在玩家进入跳跃状态时执行一些动作。当他这么做的时候,我们正在给他施加75牛顿的重力,持续时间为0.1秒。此持续时间决定了玩家跳跃的速度。显然,在跳转期间,hasFinishedJumping的值设置为false。最后,我们将添加一个Timer这将有助于我们限制跳跃动作,主要是阻止玩家同时跳跃多次,试图像Flappy Bird一样在空中飞行。这将确保初始跳跃已完成,然后再次重复。一旦玩家登陆,hasFinishedJumping就变为真实。

游戏场景设置

我们需要为Player State定义一些变量,让我们在Sprite Engine之后添加声明。

didMove设置

didMove方法内部,在joystickKnob = joystick?.childNode(withName:“knob”)之后,让我们添加将保持玩家不同状态的playerStateMachine数组。

touchesBegan

让我们去touchesBegan并在的大括号内!如果!(操纵杆?.contains(位置))!,让我们开始跳跃动作。

现在,让我们运行模拟器。除了使用操纵杆左右控制玩家之外,如果点击屏幕,玩家会通过跳跃进行响应。

玩家状态

让我们回到playerStateMachine.swift和文档的底部,让我们创建更多班的其余State我们的玩家

着陆状态类

让我们为着陆状态创建一个新类。在这个类中,我们将添加相同的** isValidNextState 函数作为跳转类。但是,我们将使用Switch**语句作为控制流。它类似于if语句,除了它运行某个代码块,具体取决于匹配的多个值而不是true或false。我们在跳转状态类中选择了Switch语句而不是if语句,因为稍后我们会添加更多的情况。在这个课程中,我们正在检查玩家是处于着陆状态还是处于跳跃状态。如果任一条件为假,则不要进入空闲状态。

class LandingState : PlayerState {
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {

        switch stateClass {
        case is LandingState.Type, is JumpingState.Type: return false
        default: return true
        }
    }

    override func didEnter(from previousState: GKState?) {

        stateMachine?.enter(IdleState.self)
    }
}

空闲状态类

LandingState类一样,我们需要为IdleState创建一个类,并再次验证我们是否可以使用** isValidNextState 函数进入下一个状态。然后,我们将使用表示可应用于节点的图像的SKTexture对象声明变量纹理。作为参数,我们将应用图像玩家/ 0以使玩家在空闲状态期间保持静止。最后,我们将声明一个操作,将图像附加到我们之前选择的玩家。的动作变量被存储为懒惰避免被RAN直到必要被称为首次这是在当didEnter**功能,以及删除任何以前的动画后的功能。使用惰性属性进行声明的目的是节省处理时间并优化内存。

class IdleState : PlayerState {
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {

        switch stateClass {
        case is LandingState.Type, is IdleState.Type: return false
        default: return true
        }
    }

    let textures = SKTexture(imageNamed: "player/0")
    lazy var action = { SKAction.animate(with: [textures], timePerFrame: 0.1)} ()

    override func didEnter(from previousState: GKState?) {

        playerNode.removeAction(forKey: characterAnimationKey)
        playerNode.run(action, withKey: characterAnimationKey)
    }
}

行走状态类

现在,让我们定义walkingState类。其中的代码与IdleState非常相似。然而,纹理变量是一个数组,其中包含我们玩家的不同帧,因此当他走路时,他的动画就好像他的腿和手臂在现实生活中一样移动。这个动作一直在运行,直到我们另一个状态中断行走。

class WalkingState : PlayerState {
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {

        switch stateClass {
        case is LandingState.Type, is WalkingState.Type : return false
        default: return true
        }
    }

    let textures : Array<SKTexture> = (0..<6).map({ return "player/\($0)"}).map(SKTexture.init)
    lazy var action = { SKAction.repeatForever(.animate(with: textures, timePerFrame: 0.1))} ()

    override func didEnter(from previousState: GKState?) {

        playerNode.removeAction(forKey: characterAnimationKey)
        playerNode.run(action, withKey: characterAnimationKey)
    }
}

眩晕状态类

我们将首先声明** StunnedState**类,但暂时将其留空。我们将在后面的部分完成。

class StunnedState : PlayerState {

}

约束跳跃

让我们回到JumpingState类来限制跳跃,这样当我们的玩家完成跳跃并降落在地面上时,他才能再次跳跃。在函数isValidNextState内部和返回true之前,添加以下条件。此外,让我们改变返回true,以返回false**。

if hasFinishedJumping && stateClass is LandingState.Type { return true }

return false

跳跃动画

isValidNextState函数的正下方,让我们将变量纹理声明为数组类型,用于存储跳跃动画的图像。同样,我们将运行一个动作来使用这些图像为玩家设置动画,就像在行走动画中一样。

let textures : Array<SKTexture> = (0..<2).map({ return "jump/\($0)"}).map(SKTexture.init)
lazy var action = { SKAction.animate(with: textures, timePerFrame: 0.1)} ()

删除并运行操作

在下面的didEnter函数中,让我们在** hasFinishedJumping = false **上方添加remove和run操作。

playerNode.removeAction(forKey: characterAnimationKey)
playerNode.run(action, withKey: characterAnimationKey)

完成State

让我们回到GameScene.swift文档,然后查找didMove函数。在JumpingState(playerNode:player!),之后,让我们在数组** playerStateMachine中添加其余的玩家状态**。

WalkingState(playerNode: player!),
IdleState(playerNode: player!),
LandingState(playerNode: player!),
StunnedState(playerNode: player!),

默认玩家为空闲状态

现在,我们需要在游戏开始时将玩家默认为处于空闲状态。在playerStateMachine = GKStateMachine之后,添加这行代码。

playerStateMachine.enter(IdleState.self)

positivePosition

现在我们已经设置了所有玩家状态,让玩家在用户移动旋钮时进入行走状态。为此,请转到Game Loop标记下的更新功能,并在声明xPosition 之后,让我们创建一个名为 positivePosition的新变量。这将为旋钮的x位置存储正值。

let positivePosition = xPosition < 0 ? -xPosition : xPosition

if floor(positivePosition) != 0 {
    playerStateMachine.enter(WalkingState.self)
} else {
    playerStateMachine.enter(IdleState.self)
}

当我们声明positivePosition时,我们正在测试xPosition是否为负数。如果这是真的,那就让它变得积极。然后,我们使用floor函数将该值四舍五入为最接近的整数。如果最终结果不为0,表示旋钮不在操纵杆的中心,请让玩家走动动画。否则,让他进入空闲状态。

设置行走状态

如果您运行应用程序并点击屏幕,您将看到当我们的玩家跳跃时,他会进入跳跃动画。然而,即使他登陆后,他仍然处于跳跃状态。为了解决这个问题,我们需要修改行走状态,原因是我们还没有应用与地面的碰撞。让我们回到playerStateMachine.swift文件,并在JumpingState类,注释掉这种情况下 ,如果hasFinishedJumping && stateClass是LandingState.Type {返回true} 。同样,让我们​​改变返回false返回true。由于我们尚未应用碰撞,因此行走和跳跃状态现在发生冲突。

// if hasFinishedJumping && stateClass is LandingState.Type { return true }

return true

现在再次运行模拟器并执行跳转。这次,当我们左右移动操纵杆时,我们的玩家实际上正在行走。此外,由于我们刚刚删除约束,他可以连续跳转我们垃圾邮件的次数。如果我们放开旋钮,玩家将停止所有的行走和跳跃。

https://dl.dropboxusercontent.com/s/32b6nqb40lkiqft/2.playerStateMachine-SettingUptheWalking%20state.mp4?dl=0

结论

在本节中,我们了解了GKStateMachine,为我们的玩家分配了不同的状态,并对何时进入和退出这些状态应用了某些条件。最重要的是,我们为它们添加了动画并应用它们。

原文: https://designcode.io/playerstate-machine

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 6,153评论 1 38
  • 冬儿子的幸福生活之——上大学(2015.12.28) 健健到冬冬家来玩,大家谈起将来上大学的事情! 健健是个目标明...
    项晓丹珠宝鉴定师阅读 177评论 0 1
  • ------------文/小皮 她,大连人,现在已是一个3岁的可爱孩子的母亲。她整天闷闷不乐。给我说的最多...
    郭小皮阅读 432评论 2 2
  • 首先 ,从自己来说吧,这个你,可以不是真实存在的,谁,没个念想呢,这是我很久以前写的一篇,今天说给你听。 # ...
    朱砂颜阅读 283评论 0 1