extends CharacterBody2D ## 小怪:在平台上左右巡逻,碰到玩家扣一颗心; ## 被玩家从上方踩到就死,并且把玩家弹起来。 ## 走到平台边缘会自动掉头,所以不会掉下去。 @export var speed: float = 28.0 @export var damage: int = 1 ## 被踩死时把玩家往上弹的速度 @export var stomp_bounce: float = -150.0 ## 巡逻方向:-1 向左,1 向右 @export var start_direction: int = -1 ## 掉头后的冷却时间:防止贴着墙时每帧都掉头、结果原地抖动 @export var turn_cooldown: float = 0.25 var direction: int = -1 var dead: bool = false var _turn_timer: float = 0.0 @onready var sprite: Sprite2D = $Sprite @onready var floor_probe: RayCast2D = $FloorProbe @onready var touch_area: Area2D = $TouchArea func _ready() -> void: add_to_group("enemy") direction = -1 if start_direction < 0 else 1 _apply_direction() touch_area.body_entered.connect(_on_touch) func _physics_process(delta: float) -> void: if dead: return if _turn_timer > 0.0: _turn_timer -= delta if not is_on_floor(): velocity += get_gravity() * delta velocity.x = float(direction) * speed # 撞到墙 或 前方脚下没有地板 -> 掉头(带冷却,掉头后先走一段再说) if _turn_timer <= 0.0: if is_on_wall() or (is_on_floor() and not floor_probe.is_colliding()): direction = -direction _turn_timer = turn_cooldown _apply_direction() move_and_slide() func _apply_direction() -> void: if sprite != null: sprite.flip_h = direction > 0 if floor_probe != null: floor_probe.position.x = float(direction) * 6.0 func _on_touch(body: Node2D) -> void: if dead or not body.has_method("hurt"): return # 玩家从上往下踩到 -> 小怪死,玩家弹一下 var p := body as CharacterBody2D if p != null and p.velocity.y > 0.0 and p.global_position.y < global_position.y - 3.0: p.velocity.y = stomp_bounce _die() return body.hurt(damage) func _die() -> void: dead = true velocity = Vector2.ZERO touch_area.set_deferred("monitoring", false) set_deferred("collision_layer", 0) set_deferred("collision_mask", 0) # 被踩扁 + 淡出 var tw := create_tween() tw.set_parallel(true) tw.tween_property(sprite, "scale", Vector2(1.35, 0.2), 0.12) tw.tween_property(sprite, "modulate:a", 0.0, 0.3) tw.chain().tween_callback(queue_free)