This commit is contained in:
Reed 2025-12-29 14:36:00 +08:00
parent 4334f4a4b0
commit b306abb739
19 changed files with 370 additions and 8 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,44 @@
'''
'''
class_name PlayerTriggerVolumn
extends Area2D
@export var debug_print: bool = false
signal player_entered(body:CharacterBody2D)
signal player_exit(body:CharacterBody2D)
var _cached_player : Player
func _ready() -> void:
self.body_entered.connect(_on_body_enter)
self.body_exited.connect(_on_body_exit)
func _on_body_enter(body:Node2D) -> void:
if not body.is_in_group("PLAYER"):
return
var p = body as Player
if not p: return
if debug_print:
print("[TiggerVolumn]: Player Entered")
_cached_player = p
player_entered.emit(p)
func _on_body_exit(body:Node2D) -> void:
if not _cached_player: return
if not body.is_in_group("PLAYER"):
return
var p = body as Player
if not p: return
if debug_print:
print("[TiggerVolumn]: Player Exited")
_cached_player = null
player_exit.emit(p)

View File

@ -0,0 +1 @@
uid://c25ea2nypjah7

View File

@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://bonrls3iuhdqb"]
[ext_resource type="Script" uid="uid://c25ea2nypjah7" path="res://_props/tools/player_trigger_volumn.gd" id="1_qrafk"]
[node name="PlayerTriggerVolumn" type="Area2D"]
editor_description = "此类在检测到玩家时会发出signal可以与其他的需要检测玩家的scene组合使用。
"
collision_layer = 0
collision_mask = 2
script = ExtResource("1_qrafk")

117
_props/tools/rock.gd Normal file
View File

@ -0,0 +1,117 @@
class_name Rock
extends CharacterBody2D
## ===== 配置 =====
@export var falling_gravity: float = 2000.0
@export var max_fall_speed: float = 3000.0
@export var kill_y: float = 10000000.0
@export var shake_x := 2.0
@export var shake_y := 2.0
@export var step_time := 0.034
@export var binded_rock_texture: Node2D
## ===== 常量 =====
const NO_TARGET_Y: float = 1e20
## ===== 状态 =====
var is_falling: bool = false
var fall_target_y: float = NO_TARGET_Y
## ===== 抖动量 =====
var _shake_tween: Tween
var _shake_origin_pos: Vector2
##岩石开始抖动
func start_shaking() -> void:
var sprite := $Sprite2D
if binded_rock_texture: sprite = binded_rock_texture
if not sprite:
return
# 防止重复启动
if _shake_tween and _shake_tween.is_running():
return
_shake_origin_pos = sprite.position
_shake_tween = create_tween()
_shake_tween.set_loops() # 无限循环
_shake_tween.set_trans(Tween.TRANS_SINE)
_shake_tween.set_ease(Tween.EASE_IN_OUT)
# 左上 → 右下 → 左下 → 右上(循环更自然)
_shake_tween.tween_property(
sprite,
"position",
_shake_origin_pos + Vector2(-shake_x, -shake_y),
step_time
)
_shake_tween.tween_property(
sprite,
"position",
_shake_origin_pos + Vector2(shake_x, shake_y),
step_time
)
_shake_tween.tween_property(
sprite,
"position",
_shake_origin_pos + Vector2(-shake_x, shake_y),
step_time
)
_shake_tween.tween_property(
sprite,
"position",
_shake_origin_pos + Vector2(shake_x, -shake_y),
step_time
)
##岩石结束抖动
func stop_shaking() -> void:
var sprite := $Sprite2D
if not sprite:
return
if _shake_tween:
_shake_tween.kill()
_shake_tween = null
# 强制回到原位,防止残留偏移
sprite.position = _shake_origin_pos
## 开始下落(可指定目标)
func start_falling(target_y: float = NO_TARGET_Y) -> void:
is_falling = true
fall_target_y = target_y
velocity = Vector2.ZERO
func _physics_process(delta: float) -> void:
if not is_falling:
return
_update_fall(delta)
func _update_fall(delta: float) -> void:
## 速度积分
velocity.y += falling_gravity * delta
velocity.y = min(velocity.y, max_fall_speed)
## 预测下一帧位置
var next_y: float = global_position.y + velocity.y * delta
## 到达目标 / kill
var limit_y: float = min(fall_target_y, kill_y)
if next_y >= limit_y:
global_position.y = limit_y
_on_fall_finished()
return
move_and_slide()
func _on_fall_finished() -> void:
is_falling = false
queue_free() # 或者变成平台 / 播动画

1
_props/tools/rock.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://hme2aiy2gff7

10
_props/tools/rock.tscn Normal file
View File

@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="CharacterBody2D"]
collision_layer = 4
collision_mask = 4
script = ExtResource("1_60pcp")
falling_gravity = 400.0
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
[node name="rock" type="AnimatableBody2D"]
collision_layer = 4
collision_mask = 4
sync_to_physics = false
script = ExtResource("1_60pcp")
falling_gravity = 400.0
kill = null
max_fall_speed = 600.0

View File

@ -0,0 +1,54 @@
extends Node2D
@export var binded_rock: Rock
@export var binded_volumn: PlayerTriggerVolumn
var _rock : Rock
var _volumn : PlayerTriggerVolumn
func _ready() -> void:
_rock = binded_rock if binded_rock != null else _find_first_rock(self)
_volumn = binded_volumn if binded_volumn != null else _find_first_volumn(self)
if not _volumn or not _rock: return
_volumn.player_entered.connect(_on_rock_start_shake,CONNECT_ONE_SHOT)
func _on_rock_start_shake(player: Player) -> void:
if not _rock: return
_rock.start_shaking()
$Timer.start()
$Timer.timeout.connect(_on_rock_falling)
func _on_rock_falling() -> void:
_rock.stop_shaking()
_rock.start_falling()
## ================================
## 查找工具函数(强类型)
## ================================
func _find_first_rock(root: Node) -> Rock:
var found: Node = _find_first_child_matching(root, func(n: Node) -> bool: return n is Rock)
return found as Rock
func _find_first_volumn(root: Node) -> PlayerTriggerVolumn:
var found: Node = _find_first_child_matching(root, func(n: Node) -> bool: return n is PlayerTriggerVolumn)
return found as PlayerTriggerVolumn
func _find_first_child_matching(root: Node, predicate: Callable) -> Node:
for child: Node in root.get_children():
# predicate.call() 返回值在类型系统里可能是 Variant所以别用 := 推断
var ok: bool = bool(predicate.call(child))
if ok:
return child
var deeper: Node = _find_first_child_matching(child, predicate)
if deeper != null:
return deeper
return null

View File

@ -0,0 +1 @@
uid://b8yl6l3tlam86

View File

@ -0,0 +1,39 @@
[gd_scene load_steps=7 format=3 uid="uid://knrcnoedxvm6"]
[ext_resource type="PackedScene" uid="uid://bonrls3iuhdqb" path="res://_props/tools/player_trigger_volumn.tscn" id="1_mvp6g"]
[ext_resource type="PackedScene" uid="uid://cmjwk4gr1nfns" path="res://_props/tools/rock.tscn" id="1_nh18e"]
[ext_resource type="Script" uid="uid://b8yl6l3tlam86" path="res://_props/trigger_fall_rock/trigger_fall_rock.gd" id="1_vv0hj"]
[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="2_xilvp"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_vv0hj"]
size = Vector2(52, 51)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_mvp6g"]
size = Vector2(52, 108.5)
[node name="TriggerFallRock" type="Node2D"]
script = ExtResource("1_vv0hj")
[node name="rock" parent="." instance=ExtResource("1_nh18e")]
position = Vector2(0, -82)
falling_gravity = 100.0
[node name="Sprite2D" type="Sprite2D" parent="rock"]
scale = Vector2(0.4, 0.4)
texture = ExtResource("2_xilvp")
[node name="CollisionShape2D" type="CollisionShape2D" parent="rock"]
position = Vector2(0, -0.5)
shape = SubResource("RectangleShape2D_vv0hj")
debug_color = Color(0.99629647, 0, 0.19810504, 0.41960785)
[node name="PlayerTriggerVolumn" parent="." instance=ExtResource("1_mvp6g")]
debug_print = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="PlayerTriggerVolumn"]
position = Vector2(0, -54)
shape = SubResource("RectangleShape2D_mvp6g")
[node name="Timer" type="Timer" parent="."]
wait_time = 0.8
one_shot = true

View File

@ -81,7 +81,6 @@ func enable_movement() -> void:
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if !_can_move : if !_can_move :
return #不允许移动,直接停止退出 return #不允许移动,直接停止退出
print("Loco 更新中")
_update_movement(delta) #更新移动输入 _update_movement(delta) #更新移动输入
_update_gravity(delta) #更新重力 _update_gravity(delta) #更新重力

View File

@ -18,7 +18,16 @@ v0.1.3
v0.2.1 v0.2.1
- - 添加了全局的特效管理器添加了全局的特效层现在所有的特效在一个单独的Canvas Layer上播放。
- 添加了全局的音效管理器
v0.2.2
- 添加了基础的TriggerVolumn可以定向的检测Player的碰撞然后绑定到对应的组件上触发对应的效果
- 添加了落石的基础类,可以实现,开始抖动,结束抖动,移动,结束移动,移动到目标点等一系列操作
- 添加了一个落石的基础案例,可以在此案例的基础上对落石功能进行拓展和修改
## 更新计划 ## 更新计划
@ -53,11 +62,11 @@ V0.2
- [ ] 相机功能 - [ ] 相机功能
- [ ] 相机追随 - [ ] 相机追随
- [ ] 相机震动 - [ ] 相机震动
- [ ] 地图功能 - [ ] 地图功能
- [ ] 地图美术功能 - [ ] 地图美术功能
- [ ] 地图物件功能 - [ ] 地图物件功能
- [ ] 落石
- [ ] 移动跟随平台
- [ ] 玩家死亡和重生的逻辑 - [ ] 玩家死亡和重生的逻辑
- [ ] Room功能一个Level由n个Room组成Room存在一个Entrance玩家进入Entrance会让Entrance向上传输消息给Room并让镜头切换到对应的Room - [ ] Room功能一个Level由n个Room组成Room存在一个Entrance玩家进入Entrance会让Entrance向上传输消息给Room并让镜头切换到对应的Room
- [ ] entrance的对应不同的复活点从不同的entrance进入会让玩家死亡后在不同的复活点复活 - [ ] entrance的对应不同的复活点从不同的entrance进入会让玩家死亡后在不同的复活点复活
@ -71,11 +80,11 @@ V0.3
- [x] VFX Manager - [x] VFX Manager
- [x] 可以實現在場景中根據預設播放VFX - [x] 可以實現在場景中根據預設播放VFX
- [ ] 將所有的VFX放置在一個插件專屬的Layer - [x] 將所有的VFX放置在一個插件專屬的Layer
- [ ] SFX Manager - [x] SFX Manager
- [ ] 可以實現在場景中根據預設播放SFX - [ ] 可以實現在場景中根據預設播放SFX
- [ ] 可以播放一個隨機的SFX Asset - [x] 可以播放一個隨機的SFX Asset
- [ ] 不同的SFX預設 - [ ] 不同的SFX預設
- [ ] CameraShake Manager - [ ] CameraShake Manager