1 制作击中动画

添加击中动画,另存为hit_effect.tsc

2 将击中动画添加到hurtbox.gd

hurtbox 通用的effect的脚本,预加载

一旦检测到受击,实例化保存了击中动画的场景,添加为子节点

1
2
3
4
5
6
7
8
9
10
11
12
13
extends Area2D

const HIT_EFFECT = preload("res://Effects/hit_effect.tscn")

func _on_area_entered(area: Area2D) -> void:
var effect = HIT_EFFECT.instantiate()

#不使用get_parent().add_child()实例化,因为parent会被free()
var main = get_tree().current_scene

main.add_child(effect)
effect.global_position = global_position

3 由此产生的bug

草也使用effect.gd脚本播放动画,但不需要这个击中动画,怎么处理?

方案一:添加开关按钮解决,后面会优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extends Area2D

+ @export var show_hit:bool = true

const HIT_EFFECT = preload("res://Effects/hit_effect.tscn")

func _on_area_entered(area: Area2D) -> void:
+ if show_hit:
var effect = HIT_EFFECT.instantiate()

#不使用get_parent().add_child()实例化,因为parent会被free()
var main = get_tree().current_scene

main.add_child(effect)
effect.global_position = global_position

4 蝙蝠状态机

使用状态机控制蝙蝠状态的切换

1
2
3
4
5
enum{
IDLE,
WANDER,
CHASE
}

初始状态为IDLE

1
var state = IDLE

在状态机的IDLE里设置蝙蝠速度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
match state:
IDLE:
# 蝙蝠的击退速度
velocity=velocity.move_toward(Vector2.ZERO,FRICTION * delta)
seek_player()

WANDER:
pass

CHASE:
pass

move_and_slide()

func seek_player():
pass

5 检测玩家进入

新建Area2d节点,命名为PlayerDetectionZone,添加碰撞形状,新建并挂载脚本player_detection_zone.gd,检测玩家进入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extends Area2D

var player=null

#能否看到玩家
func can_see_player():
return player != null

#检测玩家进入
func _on_body_entered(body):
player=body

func _on_body_exited(body):
player=null

6 调整Bat碰撞层

怎样确保进入的是玩家?通过碰撞层区分。

打开Bat节点,引用侦测区域,添加碰撞形状

image-20240606051306388

调整侦测层级,PlayerDetectionZone的mask只勾选play

image-20240606062329298

7 完善追赶状态

调整追赶过程中,蝙蝠的朝向,

playerDetectionZone侦测区域不为null,

Bat.gd的CHASE部分:

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
	match state:
IDLE:
# 蝙蝠的击退速度
velocity=velocity.move_toward(Vector2.ZERO,FRICTION * delta)
seek_player()

WANDER:
pass

CHASE:

+ var player = playerDetectionZone.player
+ print(player)
+ if player != null:

+ var direction = (player.global_position - global_position).normalized()
+ velocity = velocity.move_toward(direction * MAX_SPEED ,ACCELERATION * delta)
+ else :
#避免离开时追赶方向停不下来
+ state = IDLE

#调整追赶过程中,蝙蝠的朝向
sprite.flip_h = velocity.x < 0
move_and_slide()
#这里的逻辑有得研究,这里seek_player() 放在match语句前执行就好,IDLE和CHASE都需要状态转换,而且它CHASE的那个判断很迷,就是等于seekplayer

func seek_player():
+ if playerDetectionZone.can_see_player():
+ state = CHASE