抱起物品
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
@tool
|
||||
class_name Carryable
|
||||
extends RigidBody3D
|
||||
## 可抱起的物品。**只有带这个脚本(并进了 carryable 组)的东西才抱得起来** —— 这就是
|
||||
## 「仅特定物品可抱」的实现方式:门槛不在玩家那边,而在物品自己身上。
|
||||
##
|
||||
## 和 Zipline 一样,手感参数放物品这一侧:不同物品可以有不同的抱持偏移、不同的投掷速度,
|
||||
## 玩家只负责「找到它、把它摆到手上、扔出去」,不定义手感。
|
||||
##
|
||||
## 用法:把这个脚本挂在物品根节点(RigidBody3D)上即可,别的什么都不用配。
|
||||
## 参考示例见 res://world/items/carryable_box.tscn。
|
||||
##
|
||||
## 标了 @tool 是为了能在编辑器里跑测试(非 @tool 脚本在编辑器里是 placeholder,方法调不动);
|
||||
## 运行时行为完全一样。
|
||||
|
||||
## 所有可抱物品都进这个组,玩家靠它找物品
|
||||
const GROUP: StringName = &"carryable"
|
||||
|
||||
@export_group("抱持")
|
||||
## 被抱时相对抱持点的偏移(米)。物品大小不同,靠它对准手心
|
||||
@export var hold_offset: Vector3 = Vector3.ZERO
|
||||
## 被抱时的朝向(度)
|
||||
@export var hold_rotation_deg: Vector3 = Vector3.ZERO
|
||||
## 抱起来时冻结物理、并清掉碰撞层 —— 不清的话物品会把抱着它的人顶飞
|
||||
@export var freeze_while_carried: bool = true
|
||||
|
||||
@export_group("投掷")
|
||||
## 长按蓄满力后的出手速度(米/秒)
|
||||
@export var throw_speed_max: float = 14.0
|
||||
## 轻点时最低出手速度(米/秒)
|
||||
@export var throw_speed_min: float = 5.0
|
||||
|
||||
## 现在被谁抱着。空 = 没人抱
|
||||
var carried_by: Node3D = null
|
||||
|
||||
var _saved_collision_layer: int = 1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(GROUP)
|
||||
_saved_collision_layer = collision_layer
|
||||
|
||||
|
||||
func can_be_carried() -> bool:
|
||||
return carried_by == null
|
||||
|
||||
|
||||
## 被抱起来:冻结物理、退出碰撞,之后由持有者每帧摆位置
|
||||
func begin_carry(holder: Node3D) -> void:
|
||||
carried_by = holder
|
||||
if freeze_while_carried:
|
||||
freeze = true
|
||||
collision_layer = 0
|
||||
|
||||
|
||||
## 放下 / 扔出:恢复物理并继承一个初速度
|
||||
func end_carry(velocity: Vector3) -> void:
|
||||
carried_by = null
|
||||
if freeze_while_carried:
|
||||
freeze = false
|
||||
collision_layer = _saved_collision_layer
|
||||
linear_velocity = velocity
|
||||
|
||||
|
||||
## 把自己摆到抱持点上。持有者每物理帧调一次 —— 偏移和朝向由物品自己决定,玩家不用管。
|
||||
func apply_hold_transform(socket: Node3D) -> void:
|
||||
var socket_basis := socket.global_basis
|
||||
global_position = socket.global_position + socket_basis * hold_offset
|
||||
global_basis = socket_basis * Basis.from_euler(hold_rotation_deg * PI / 180.0)
|
||||
|
||||
|
||||
## 按蓄力比例算出手速度(0 = 轻点,1 = 蓄满)
|
||||
func throw_speed(charge: float) -> float:
|
||||
return lerpf(throw_speed_min, throw_speed_max, clampf(charge, 0.0, 1.0))
|
||||
@@ -0,0 +1 @@
|
||||
uid://bdo6ee5tmvnc2
|
||||
@@ -0,0 +1,24 @@
|
||||
[gd_scene load_steps=5 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/items/carryable.gd" id="1_carryable"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_body"]
|
||||
size = Vector3(0.6, 0.6, 0.6)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_box"]
|
||||
albedo_color = Color(0.92, 0.6, 0.25, 1)
|
||||
roughness = 0.7
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_body"]
|
||||
size = Vector3(0.6, 0.6, 0.6)
|
||||
|
||||
[node name="CarryableBox" type="RigidBody3D"]
|
||||
mass = 2.0
|
||||
script = ExtResource("1_carryable")
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("BoxMesh_body")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_box")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("BoxShape3D_body")
|
||||
Reference in New Issue
Block a user