godot4制作2D游戏09———创建简单敌人(一)
创建一个敌人
- 新建一个Enemies文件夹
- 在下面创建Scripts文件夹
- 创建一个Slime文件夹,里面是史莱姆的相关文件
- 从网站下载Slime.png放入Slime文件夹
- 创建一个CharacterBody2D节点的场景,用来保存Slime相关的数据
- 在这下面创建一个Sprite2D节点,保存Slime图像
- 再创建一个Sprite2D节点,放置阴影
- 创建一个CollisionShape2D节点,自己在9层,mask为5层,可以和Wall交互
- 创建Slime动画
- 创建idle的up、down、side
- 创建walk的up、down、side
- 创建一个enemy.gd脚本,挂载到Slime节点上
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
55class_name Enemy extends CharacterBody2D
signal DirectionChanged(dir: Vector2)
signal EnemyDamaged()
const DIR_ARR: Array[Vector2] = [Vector2.RIGHT, Vector2.DOWN, Vector2.LEFT, Vector2.UP]
var direction: Vector2 = Vector2.ZERO
var cardinal_direction: Vector2 = Vector2.DOWN
var player: Player
var invulnerable: bool = false
func _ready() -> void:
state_machine.Initialize(self)
player = PlayerManager.player
pass
func _process(_delta: float) -> void:
pass
func _physics_process(delta: float) -> void:
move_and_slide()
pass
func SetDirection(_direction: Vector2) -> bool:
direction = _direction
if direction == Vector2.ZERO:
return false
var direction_id: int = int(round((direction + cardinal_direction * 0.1).angle() / TAU * DIR_ARR.size()))
var new_dir = DIR_ARR[direction_id]
if cardinal_direction == direction:
return false
cardinal_direction = new_dir
DirectionChanged.emit(new_dir)
sprite.scale.x = -1 if cardinal_direction == Vector2.LEFT else 1
return true
func UpdateAnimation(state: String) -> void:
animation_player.play(state + "_" + AnimationDirection())
func AnimationDirection() -> String:
if cardinal_direction == Vector2.DOWN:
return "down"
elif cardinal_direction == Vector2.UP:
return "up"
else:
return "side" - 创建一个enemy_state.gd脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class_name EnemyState extends Node
var enemy: Enemy
var state_machine: EnemyStateMachine
func init() -> void:
pass
func Enter() -> void:
pass
func Exit() -> void:
pass
func Process(_delta: float) -> EnemyState:
return null
func PhysicsProcess(_delta: float) -> EnemyState:
return null - 创建一个enemy_state_machine.gd脚本,并创建一个EnemyStateMachine状态机节点,并将脚本挂载上去
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
42class_name EnemyStateMachine extends Node
var states: Array[ EnemyState ]
var prev_state: EnemyState
var current_state: EnemyState
func _ready() -> void:
process_mode = Node.PROCESS_MODE_DISABLED
pass
func _process(delta: float) -> void:
ChangeState(current_state.Process(delta))
pass
func _physics_process(delta: float) -> void:
ChangeState(current_state.PhysicsProcess(delta))
pass
func Initialize(enemy: Enemy) -> void:
for c in get_children():
if c is EnemyState:
states.append(c)
for s in states:
s.enemy = enemy
s.state_machine = self
s.init()
if states.size() > 0:
ChangeState(states[0])
process_mode = Node.PROCESS_MODE_INHERIT
func ChangeState(new_state: EnemyState) -> void:
if new_state == null || new_state == current_state:
return
if current_state:
current_state.Exit()
prev_state = current_state
current_state = new_state
current_state.Enter() - 创建一个global_player_manager.gd脚本并配置Autoload
- 在enemy.gd初始化时引用player
- 在player.gd初始化时设置PlayerManager
- 在EnemyStateMachine下创建Idle状态机
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
32class_name EnemyStateIdle extends EnemyState
var timer: float = 0.0
func init() -> void:
pass
func Enter() -> void:
enemy.velocity = Vector2.ZERO
timer = randf_range(state_duration_min, state_duration_max)
enemy.UpdateAnimation(anmi_name)
pass
func Exit() -> void:
pass
func Process(_delta: float) -> EnemyState:
timer -= _delta
if timer <= 0:
return after_idle_state
return null
func PhysicsProcess(_delta: float) -> EnemyState:
return null - 在EnemyStateMachine下创建Wander状态机
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
37class_name EnemyStateWander extends EnemyState
var timer: float = 0.0
func init() -> void:
pass
func Enter() -> void:
timer = randi_range(state_cycle_min, state_cycle_max) * state_animation_duration
var direction_id = randi_range(0, 3)
var direction = enemy.DIR_ARR[direction_id]
enemy.velocity = direction * wander_speed
enemy.SetDirection(direction)
enemy.UpdateAnimation(anmi_name)
pass
func Exit() -> void:
pass
func Process(_delta: float) -> EnemyState:
timer -= _delta
if timer <= 0:
return next_state
return null
func PhysicsProcess(_delta: float) -> EnemyState:
return null
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Have a nice day!!