1 全局变量stats

新建场景player_stats.tscn,挂载脚本stats.gd,作为全局变量,全局自动加载

image-20240606145853008

//WARN,有更好的方法

2 no_health回调

获取PlayStats,一旦接收到no_health信号,回调queue_free

1
2
var stats = PlayerStats
stats.connect("no_health",queue_free)

3 玩家属性

  • player节点引入hurtbox,给碰撞形状和碰撞层

image-20240606154746616

  • 实现player生命属性
1
2
3
func _on_hurtbox_area_entered(area: Area2D) -> void:

stats.health -= 1
  • 给蝙蝠hitbox,给碰撞形状,给层级

4 show_hit优化

show_hit有更好的方法优化,断开hurtbox的信号,把他抽取成函数

1
2
3
4
5
6
7
8
9
10
func create_hit_effect():

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

5 实现玩家短暂无敌

目前能实现碰撞受伤,但有bug,不离开碰撞检测区域,比如在角落里,就不会再次受伤,解决方法,给hurtbox短暂的无敌时刻。

无敌时间的逻辑

1
2
3
4
5
6
7
var invincible  = false:set = set_invincible

signal invincibility_started
signal invincibility_ended

func set_invincible(value):
invincible = value

将它和持续时间联系起来

在hurtbox节点下,新建一个Timer节点,连接timeout信号

1
2
3
4
5
6
func start_invincibility(duration):
#开始无敌就把无敌状态置为true
self.invincible = true
#无敌开始就开启计时器,duration就是计时器的时间

timer.start(duration)

②时间到,调用信号,把无敌置为false

1
2
3
func _on_timer_timeout() -> void:
#必须加self,因为上面有invincible
self.invincible = false

梳理下流程:

  • ①调用start_invincibility,会设置invincible,开始计时器,

  • ②timer计时器结束就会把无敌置为false

  • ①②发生的同时,会设置invincible,那就会自动调用set_invincible方法,方法里面会发送对应的信号

这样能解决频繁进入玩家的hurtbox时,对玩家快速造成伤害,但是还有个bug,就是在区域里不能触发信号的问题

使用Monitoring和Monitorable为 true 时,该区域能够检测到进入和退出该区域的实体或区域,ing也就是对应启用检测mask,-able反之,搭配无敌检测,就解决了

1

使用2个信号,对mask

1
2
3
4
5
#开始的时候,禁用mask检测,之后再开启
func _on_invincibility_started() -> void:
monitoring = false
func _on_invincibility_ended() -> void:
monitoring = true

//WARN,这里不该使用信号,这样的写法不妥

给player开启无敌和击中

1
2
3
4
5
func _on_hurtbox_area_entered(area: Area2D) -> void:
stats.health -= 1
#开启无敌
hurtbox.start_invincibility(0.5)
hurtbox.create_hit_effect()

也给bat

1
hurtbox.create_hit_effect()

//WARN直接设置collisionShape的disable呢?

复杂了,直接在hurtbox里改状态就行了,不用信号,export时间出去,以后再优化