class_name Player extends CharacterBody3D const MOVE_SPEED := 5. static var instance: Player @export var shake_noise: FastNoiseLite var shake_duration := 0. @onready var camera_transform: Transform3D = %Camera3D.transform var damage_clock := 0. var aim_angle: float var health := 3: set(v): health = v if is_node_ready(): %HealthLabel.text = "Health: %d" % v func _init() -> void: instance = self func _ready() -> void: health = health func _process_movement() -> void: var input = Input.get_vector("move_left", "move_right", "move_up", "move_down") input.normalized() velocity = Vector3(input.x, 0., input.y) * MOVE_SPEED move_and_slide() func _process_aim() -> void: var viewport_mouse_pos := get_viewport().get_mouse_position() var r_origin: Vector3 = %Camera3D.project_ray_origin(viewport_mouse_pos) var r_dir: Vector3 = %Camera3D.project_ray_normal(viewport_mouse_pos) # y = mx + b # 0 = mx + b # -b / m = x var t := -r_origin.y / r_dir.y var world_mouse_pos = r_origin + r_dir * t var to_mouse_pos = world_mouse_pos - global_position var angle = Vector2(to_mouse_pos.x, -to_mouse_pos.z).angle() %Cannon.rotation.y = angle aim_angle = angle %Reticle.position = to_mouse_pos func _process_shoot() -> void: if Input.is_action_just_pressed("fire"): var dir := Vector3.RIGHT.rotated(Vector3.UP, aim_angle) var player_projectile: PlayerProjectile = preload("player_projectile.tscn").instantiate() player_projectile.init(dir) player_projectile.global_position = global_position + Vector3.UP * 0.5 add_sibling(player_projectile) func _process_cam_shake(delta: float) -> void: shake_duration -= delta %Camera3D.transform = camera_transform if shake_duration <= 0: return var x := shake_noise.get_noise_1d(shake_duration * 10000) var y := shake_noise.get_noise_1d(-shake_duration * 10000) var v := \ camera_transform.basis.x * x + \ camera_transform.basis.y * y print("v = ", v) %Camera3D.position += v * .5 func _process(delta: float) -> void: _process_movement() _process_aim() _process_shoot() _process_cam_shake(delta) damage_clock -= delta func damage() -> void: if damage_clock <= 0.: health -= 1 damage_clock = 3 shake_duration = .25 if health == 0: get_tree().reload_current_scene()