美文网首页
玩家状态机-使用GameplayKit管理不同的状态和动画

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

作者: iOSDevLog | 来源:发表于2019-02-28 17:54 被阅读4次

    在本节中,我们将了解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

    相关文章

      网友评论

          本文标题:玩家状态机-使用GameplayKit管理不同的状态和动画

          本文链接:https://www.haomeiwen.com/subject/hbskuqtx.html