2024-09-08 22:06:34 +02:00
|
|
|
class_name BuildSystem
|
|
|
|
extends Node
|
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
const CAMERA_SPEED = 4.0
|
2024-10-11 13:09:44 +02:00
|
|
|
const COLLISION_MASK_WORLD = 1
|
|
|
|
const COLLISION_MASK_STRUCTURES = 32
|
2024-09-14 12:45:42 +02:00
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
@onready var build_preview = %BuildPreview
|
2024-09-08 22:06:34 +02:00
|
|
|
@onready var player = %Player
|
2024-09-10 22:26:26 +02:00
|
|
|
@onready var built_structures = %BuiltStructures
|
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
@onready var camera:Camera3D = %Camera
|
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
@export var build_item:Item = null
|
2024-09-08 22:06:34 +02:00
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
var camera_velocity:Vector3 = Vector3.ZERO
|
|
|
|
var is_active:bool = false
|
2024-10-11 13:09:44 +02:00
|
|
|
var hovered_existing_structure:StaticBody3D = null
|
2024-09-08 22:06:34 +02:00
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
func update_build_preview_item() -> void:
|
2024-10-11 13:09:44 +02:00
|
|
|
hovered_existing_structure = null
|
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
for child in build_preview.get_children():
|
|
|
|
if build_item == null or child.scene_file_path != build_item.scene.resource_path:
|
|
|
|
child.get_parent().remove_child(child)
|
|
|
|
child.queue_free()
|
|
|
|
|
|
|
|
if build_preview.get_child_count() == 0 and build_item != null:
|
2024-10-11 13:09:44 +02:00
|
|
|
var build_preview_scene = build_item.scene.instantiate() as StaticBody3D
|
|
|
|
if build_preview_scene == null:
|
|
|
|
push_error("Cannot create build preview: item scene not derived from StaticBody3D for item: ", build_item)
|
|
|
|
return
|
|
|
|
|
|
|
|
# ensure we do not detect the preview object when querying for destroyable structures
|
|
|
|
build_preview_scene.collision_layer = 0
|
|
|
|
build_preview.add_child(build_preview_scene)
|
2024-09-10 22:26:26 +02:00
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
|
|
|
|
func move_build_camera(delta):
|
|
|
|
var input_dir = Input.get_vector("walk_left", "walk_right", "walk_forward", "walk_back")
|
|
|
|
var direction = (camera.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
|
|
|
if direction:
|
|
|
|
camera_velocity.x = direction.x * CAMERA_SPEED
|
|
|
|
camera_velocity.z = direction.z * CAMERA_SPEED
|
|
|
|
else:
|
|
|
|
camera_velocity.x = move_toward(camera_velocity.x, 0, CAMERA_SPEED)
|
|
|
|
camera_velocity.z = move_toward(camera_velocity.z, 0, CAMERA_SPEED)
|
|
|
|
|
|
|
|
camera_velocity.y = 0
|
|
|
|
|
|
|
|
camera.global_position = camera.global_position + camera_velocity * delta
|
|
|
|
|
|
|
|
|
|
|
|
func update_build_preview():
|
|
|
|
var mouse_view_coords = get_viewport().get_mouse_position() # / get_viewport().get_visible_rect().size
|
|
|
|
var mouse_ray_origin = camera.project_ray_origin(mouse_view_coords)
|
|
|
|
var mouse_ray_normal = camera.project_ray_normal(mouse_view_coords)
|
|
|
|
|
|
|
|
var world_space_state = camera.get_world_3d().direct_space_state
|
|
|
|
var ray_query:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(mouse_ray_origin, mouse_ray_origin + mouse_ray_normal * 100)
|
2024-10-11 13:09:44 +02:00
|
|
|
ray_query.collision_mask = COLLISION_MASK_WORLD | COLLISION_MASK_STRUCTURES
|
2024-09-14 12:45:42 +02:00
|
|
|
var ray_result:Dictionary = world_space_state.intersect_ray(ray_query)
|
|
|
|
|
2024-10-11 13:09:44 +02:00
|
|
|
if not ray_result.is_empty():
|
|
|
|
var grid_map_object = ray_result.collider as GridMap
|
|
|
|
var collision_body_3d = ray_result.collider as CollisionObject3D
|
|
|
|
|
|
|
|
if not collision_body_3d and not grid_map_object:
|
|
|
|
print ("Invalid collision object found. Object has no collision object: ", ray_result.collider)
|
|
|
|
return
|
|
|
|
|
|
|
|
if collision_body_3d:
|
|
|
|
if collision_body_3d.collision_layer & COLLISION_MASK_STRUCTURES != 0:
|
|
|
|
hovered_existing_structure = collision_body_3d as StaticBody3D
|
|
|
|
if hovered_existing_structure == null:
|
|
|
|
print ("Invalid structure found. Object is not derived from StaticBody3D: ", ray_result.collider)
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
hovered_existing_structure = null
|
|
|
|
|
|
|
|
if grid_map_object != null and Vector3.UP.dot(ray_result["normal"]) > 0.9:
|
|
|
|
var build_location:Vector3 = ray_result["position"]
|
|
|
|
build_location = Vector3(roundf(build_location.x * 4), build_location.y, roundf(build_location.z * 4)) * 0.25
|
|
|
|
build_preview.global_position = build_location
|
2024-09-14 12:45:42 +02:00
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
func _physics_process(_delta):
|
2024-09-14 12:45:42 +02:00
|
|
|
if not is_active:
|
|
|
|
return
|
|
|
|
|
2024-09-10 22:26:26 +02:00
|
|
|
update_build_preview_item()
|
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
#move_build_camera(delta)
|
|
|
|
|
|
|
|
update_build_preview()
|
2024-09-10 22:26:26 +02:00
|
|
|
|
2024-09-27 18:09:30 +02:00
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
2024-09-14 12:45:42 +02:00
|
|
|
if not is_active:
|
|
|
|
build_preview.hide()
|
|
|
|
return
|
|
|
|
|
|
|
|
build_preview.show()
|
|
|
|
|
2024-09-27 18:09:30 +02:00
|
|
|
if event.is_action_pressed("rotate_clockwise"):
|
2024-09-14 12:45:42 +02:00
|
|
|
build_preview.global_basis = build_preview.basis.rotated(Vector3.UP, deg_to_rad(45))
|
2024-10-11 13:09:44 +02:00
|
|
|
get_viewport().set_input_as_handled()
|
|
|
|
return
|
|
|
|
|
2024-09-27 18:09:30 +02:00
|
|
|
if event.is_action_pressed("rotate_counter_clockwise"):
|
2024-09-14 12:45:42 +02:00
|
|
|
build_preview.global_basis = build_preview.basis.rotated(Vector3.UP, -deg_to_rad(45))
|
2024-09-27 18:09:30 +02:00
|
|
|
get_viewport().set_input_as_handled()
|
2024-10-11 13:09:44 +02:00
|
|
|
return
|
|
|
|
|
2024-09-27 18:09:30 +02:00
|
|
|
if build_item != null and event.is_action_pressed("interaction"):
|
|
|
|
var new_structure:Node3D = build_item.scene.instantiate()
|
|
|
|
new_structure.transform = build_preview.transform
|
|
|
|
built_structures.add_child(new_structure)
|
|
|
|
get_viewport().set_input_as_handled()
|
|
|
|
return
|
2024-10-11 13:09:44 +02:00
|
|
|
|
|
|
|
var mouse_button_event = event as InputEventMouseButton
|
|
|
|
if hovered_existing_structure and mouse_button_event and mouse_button_event.pressed and mouse_button_event.button_index == MOUSE_BUTTON_MIDDLE:
|
|
|
|
hovered_existing_structure.get_parent().remove_child(hovered_existing_structure)
|
|
|
|
hovered_existing_structure.queue_free()
|
|
|
|
get_viewport().set_input_as_handled()
|
|
|
|
return
|