@tool extends CharacterBody3D class_name Mecha const STEP_MOVE_DISPLACEMENT = 3 const RECOIL_STRENGHT = 0.5 const MOUSE_SENSIVITY = 0.01 const ZOOM_SENSIVITY = 1. const MAX_ZOOM = 60. const MIN_ZOOM = 15. const MAX_HP : float = 50. signal died @export var hp : float = MAX_HP @export var max_speed : float = 15. @export var turn_speed : float = 5. var destination := Vector2() @onready var legs : Array[MechaLeg] = [ %Leg1, %Leg2, %Leg3, %Leg4, ] var turn_normal : Vector2 = Vector2.UP var selected_item = 0 var current_recoil = 0. func _ready(): for l in legs: l.step.connect(next_leg_can_step) func next_leg_can_step(): for l in legs: l.can_step = false await get_tree().create_timer(MechaLeg.STEP_DURATION / len(legs)).timeout for l in legs: l.can_step = true func _process(delta): if not Engine.is_editor_hint(): var target = calculate_target_position() %Target.global_position = target var target_turn = (Vector2(position.x,position.z) - Vector2(target.x,target.z)).normalized() turn_normal = lerp( turn_normal, target_turn, min(turn_speed * delta, 1.) ) var speed = 0. var item_used = false for i in range(len(%Inventory.get_children())): var item = %Inventory.get_children()[i] if item is Weapon: var used = item.process_fire( delta, self, selected_item == i and Input.is_action_pressed("fire") ) if used: item_used = true if not item_used and Input.is_action_pressed("move_to"): speed = max_speed var front_factor = 1 - (turn_normal - target_turn).length() / 2. velocity = position.direction_to(target) * speed * front_factor %Model.rotation.y = - turn_normal.angle() # Recoil %Model.position = Vector3(turn_normal.x, 0, turn_normal.y) * current_recoil * RECOIL_STRENGHT current_recoil = lerp(current_recoil, 0., 0.5) %StepTargets.position.x = lerp( 0, -STEP_MOVE_DISPLACEMENT, speed/max_speed ) %Camera3D.look_at(self.position) move_and_slide() func calculate_target_position() -> Vector3: var camera : Camera3D = get_viewport().get_camera_3d() if camera: var ray_normal := camera.project_ray_normal(get_viewport().get_mouse_position()) var ray_origin := camera.project_ray_origin(get_viewport().get_mouse_position()) var plane = Plane(Vector3.UP, 0) var intersection = plane.intersects_ray(ray_origin, ray_normal) if intersection: return intersection return global_position func get_target_angle() -> float: return - turn_normal.angle() + PI / 2 func get_projectile_spwan_point() -> Vector3: return global_position + Vector3.UP * 2. func add_recoil(recoil : = 1.): current_recoil += recoil func hit(damage = 1.): hp = max(0, hp - damage) if hp == 0: die() func die(): died.emit() func _unhandled_input(event): if Input.is_action_just_pressed("zoom_in"): %Camera3D.position.z = max(MIN_ZOOM, %Camera3D.position.z - ZOOM_SENSIVITY) if Input.is_action_just_pressed("zoom_out"): %Camera3D.position.z = min(MAX_ZOOM, %Camera3D.position.z + ZOOM_SENSIVITY) if event is InputEventMouseMotion and Input.is_action_pressed("turn_camera") and Input.mouse_mode == Input.MOUSE_MODE_VISIBLE: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE %CameraPivot.rotation.y -= event.relative.x * MOUSE_SENSIVITY %CameraPivot.rotation.x -= event.relative.y * MOUSE_SENSIVITY if %CameraPivot.rotation.x > deg_to_rad(-20): %CameraPivot.rotation.x = deg_to_rad(-20) if %CameraPivot.rotation.x < deg_to_rad(-80): %CameraPivot.rotation.x = deg_to_rad(-80)