Add Station move handle has ghost

This commit is contained in:
JonShard
2026-08-02 12:19:57 +02:00
parent 2e670129a5
commit 10bb7cd5bf
2 changed files with 103 additions and 16 deletions
+2 -2
View File
@@ -47,7 +47,7 @@ properties/2/spawn = true
properties/2/replication_mode = 1
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
size = Vector3(0.6, 1, 0.6)
size = Vector3(0.5, 1, 0.5)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vlqg6"]
transparency = 1
@@ -247,7 +247,7 @@ script = ExtResource("15_trny8")
[node name="MoveGhost" type="Area3D" parent="." unique_id=2098037388]
visible = false
collision_layer = 0
collision_mask = 589831
collision_mask = 524295
[node name="CollisionShape3D" type="CollisionShape3D" parent="MoveGhost" unique_id=486115686]
shape = SubResource("BoxShape3D_vlqg6")
+101 -14
View File
@@ -7,11 +7,15 @@ extends Node
@export var station: StaticBody3D
var move_handle_rigid: RigidBody3D
var original_collision_layer
var original_y_pos: float
var original_collision_layer: int = 0
var original_y_pos: float = 0.0
var original_station_transform: Transform3D = Transform3D.IDENTITY
var moving: bool = false
var ghost_materials: Array[StandardMaterial3D] = []
const GHOST_COLOR_VALID: Color = Color(0, 1, 0, 0.35)
const GHOST_COLOR_INVALID: Color = Color(1, 0, 0, 0.35)
# TODO: Reject placing station in occupied spot.
# TODO: Make ghost version of station that is displayed instead of model.
# TODO: public toggle to disable handle in build mode.
# TODO: If game exits build mode, drop the handle before disabling it.
@@ -19,28 +23,111 @@ var original_y_pos: float
func _ready() -> void:
if not station:
push_error("StationMovement is missing referece to station")
if not move_handle:
push_error("StationMovement is missing reference to move_handle")
if not move_ghost:
push_error("StationMovement is missing reference to move_ghost")
move_handle_rigid = move_handle as RigidBody3D
original_collision_layer = station.collision_layer
original_y_pos = move_handle.transform.origin.y
original_station_transform = station.global_transform
move_handle.picked_up.connect(_handle_pickup)
move_handle.dropped.connect(_handle_drop)
move_ghost.monitoring = true
move_ghost.visible = false
_cache_ghost_materials()
_set_ghost_color(GHOST_COLOR_VALID)
func _handle_pickup(_by):
func _cache_ghost_materials() -> void:
var combiner = move_ghost.get_node_or_null("CSGCombiner3D")
if not combiner:
return
_collect_ghost_materials(combiner)
func _collect_ghost_materials(node: Node) -> void:
if node is CSGCombiner3D:
# Combiner nodes do not expose a material property to modify.
for child in node.get_children():
_collect_ghost_materials(child)
return
if node is CSGShape3D:
var material = node.material
if material and material is StandardMaterial3D:
var instance = material.duplicate() as StandardMaterial3D
instance.transparency = material.transparency
instance.albedo_color = material.albedo_color
node.material = instance
ghost_materials.append(instance)
for child in node.get_children():
_collect_ghost_materials(child)
func _set_ghost_color(color: Color) -> void:
for material in ghost_materials:
material.albedo_color = color
func _handle_pickup(_by: Node) -> void:
print("StationMovement handle pickup")
station.collision_layer = 0
func _handle_drop(_by):
moving = true
move_ghost.visible = true
station.visible = false
station.collision_layer = 0
original_station_transform = station.global_transform
move_ghost.global_transform = original_station_transform
func _handle_drop(_by: Node) -> void:
print("StationMovement handle drop")
moving = false
move_ghost.visible = false
station.visible = true
station.collision_layer = original_collision_layer
if _is_move_position_valid():
station.global_transform = move_ghost.global_transform
else:
station.global_transform = original_station_transform
move_handle.global_position = station.global_position + Vector3(0, original_y_pos, 0)
move_handle.rotation = station.rotation
func _process(_delta: float) -> void:
station.global_position.x = snappedf(move_handle.global_position.x, snap_grid_size)
station.global_position.z = snappedf(move_handle.global_position.z, snap_grid_size)
station.global_rotation_degrees.y = snappedf(move_handle.global_rotation_degrees.y, 90)
if not moving:
return
var target_transform: Transform3D = move_handle.global_transform
target_transform.origin.x = snappedf(target_transform.origin.x, snap_grid_size)
target_transform.origin.z = snappedf(target_transform.origin.z, snap_grid_size)
target_transform.origin.y = original_station_transform.origin.y
var target_yaw: float = snappedf(move_handle.global_rotation_degrees.y, 90)
target_transform.basis = Basis(Vector3.UP, deg_to_rad(target_yaw))
move_ghost.global_transform = target_transform
if _is_move_position_valid():
_set_ghost_color(GHOST_COLOR_VALID)
else:
_set_ghost_color(GHOST_COLOR_INVALID)
func _is_move_position_valid() -> bool:
for body in move_ghost.get_overlapping_bodies():
print("Overlapping body: ", body)
if body == move_handle:
continue
if body == station:
continue
return false
for area in move_ghost.get_overlapping_areas():
print("Overlapping area: ", area)
if area == move_ghost:
continue
return false
return true