如上图为状态机的例子
而在我们自己做的项目中,可以通过创建以下文件来实现状态机管理效果
- player
row 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Player : MonoBehaviour
{
[ ]
public Vector2[] attackMovement;
public bool isBusy { get; private set; }
[ ]
public float moveSpeed = 12f;
public float jumpForce;
[ ]
public float DashSpeed;
public float DashDuration;
public float dashDir { get; private set; }
[private float dashCoolDown; ]
private float dashUsageTimer;
[ ]
[private Transform groundCheck; ]
[private float groundCheckDistance; ]
[private Transform wallChcek; ]
[private float wallCheckDistance; ]
[private LayerMask whatIsGround; ]
public Animator animator { get; private set; }
public PlayerStateMachine StateMachine { get; private set; }
public PlayerIdleState StateIdle { get; private set; }
public PlayerMoveState MoveState { get; private set; }
public PlayerJumpState JumpState { get; private set; }
public PlayerAirState AirState { get; private set; }
public PlayerDashState DashState { get; private set; }
public PlayerWallSlideState WallSlide { get; private set; }
public PlayerWallJumpState WallJumpState { get; private set; }
public PlayerPrimaryAttackState PrimaryAttack { get; private set; }
public int facingDir { get; private set; } = 1;
private bool facingRight = true;
public Rigidbody2D rb { get; private set; }
private void Awake()
{
StateMachine = new PlayerStateMachine();
StateIdle = new PlayerIdleState(this,StateMachine,"Idle");
MoveState = new PlayerMoveState(this, StateMachine, "Move");
JumpState = new PlayerJumpState(this, StateMachine, "Jump");
AirState = new PlayerAirState(this, StateMachine, "Jump");
DashState = new PlayerDashState(this, StateMachine, "Dash");
WallSlide = new PlayerWallSlideState(this, StateMachine, "WallSlide");
WallJumpState = new PlayerWallJumpState(this, StateMachine, "Jump");
PrimaryAttack = new PlayerPrimaryAttackState(this, StateMachine, "Attack");
}
public void Start()
{
animator = GetComponentInChildren<Animator>();
StateMachine.Initialize(StateIdle);
rb = GetComponent<Rigidbody2D>();
}
public void Update()
{
StateMachine.currentState.Update();
CheckForDashInput();
}
public IEnumerator BusyFor(float _seconds)
{
isBusy = true;
yield return new WaitForSeconds(_seconds);
isBusy = false;
}
public void CheckForDashInput()
{
if (IsWallDetected())
return;
dashUsageTimer -= Time.deltaTime;
if (Input.GetKeyDown(KeyCode.LeftShift) && dashUsageTimer < 0)
{
dashUsageTimer = dashCoolDown;
dashDir = Input.GetAxisRaw("Horizontal");
if(dashDir == 0)
{
dashDir = facingDir;
}
StateMachine.ChangeState(DashState);
}
}
public bool IsGroundDetected() => Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, whatIsGround);
public bool IsWallDetected() => Physics2D.Raycast(wallChcek.position, Vector2.right * facingDir, wallCheckDistance, whatIsGround);
public void SetVelocity(float _xVelocity, float _yVelocity)
{
rb.velocity = new Vector2(_xVelocity, _yVelocity);
FlipController(_xVelocity);
}
public void ZeroVelocity() => rb.velocity = new Vector2(0, 0);
public void Flip()
{
facingDir *= -1;
facingRight = !facingRight;
transform.Rotate(0, 180, 0);
}
public void FlipController(float _x)
{
if (_x>0 && !facingRight)
{
Flip();
}
else if(_x<0 && facingRight)
{
Flip();
}
}
public void AnimationTrigger () => StateMachine.currentState.AnimationFinishTrigger();
}
Player 为玩家类,创建各种状态实体并管理 - PlayerState
row 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerState
{
protected PlayerStateMachine stateMachine;
protected Player player;
protected Rigidbody2D rb;
public float xInput;
public float yInput;
private string animBoolName;
protected float stateTimer;
protected bool triggerCalled;
public PlayerState(Player _player,PlayerStateMachine _stateMachine, string _animBoolName)
{
this.player = _player;
this.stateMachine = _stateMachine;
this.animBoolName = _animBoolName;
}
public virtual void Enter()
{
player.animator.SetBool(animBoolName,true);
rb = player.rb;
triggerCalled = false;
}
public virtual void Update()
{
stateTimer -= Time.deltaTime;
xInput = Input.GetAxisRaw("Horizontal");
yInput = Input.GetAxisRaw("Vertical");
if (player != null && player.animator != null && rb != null)
player.animator.SetFloat("yVelocity", rb.velocity.y);
}
public virtual void Exit() {
player.animator.SetBool(animBoolName,false);
}
public virtual void AnimationFinishTrigger()
{
triggerCalled = true;
}
}
如上代码,所有的类都分为 Enter、Update、Exit 三个阶段,而后续所有的类都继承自 PlayerState 类,所以所有状态都基于这三个过程进行。
3. 示例:playerIdleState
1 | using System.Collections; |
所有的继承类都具有 PlayerState 的构造函数和三个过程,基于这三个过程对玩家进行操作。