Add patrolling enemies and link level 1 to level 2
New walker prefab (mushroom_red sprite) patrols a platform, turns at walls and ledges, drains a heart on contact and dies when stomped, bouncing the player up. Three are placed in level2. The level 2 spawn point is set to cell (7,11) so the player starts standing on the floor instead of falling in from mid-air, and level 1's LevelClear now loads level2.tscn.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user