284 lines
8.1 KiB
GDScript
284 lines
8.1 KiB
GDScript
extends CharacterBody3D
|
|
class_name Player
|
|
|
|
var speed = 5.0
|
|
const JUMP_VELOCITY = 12
|
|
const throw_strength = 50
|
|
var speeds = [5.0, 2.5, 1.5, 1.0]
|
|
var animation_player_speeds = [1.5, 1.0, 0.7, 0.5]
|
|
var counter_speed := 0
|
|
|
|
enum PlayerMode {
|
|
NORMAL,
|
|
AIM
|
|
}
|
|
|
|
var mode = PlayerMode.NORMAL
|
|
var xform : Transform3D
|
|
var grabbed_item : Grabbable_Object
|
|
var dialogueActive : bool
|
|
var weight: float = 5.0
|
|
|
|
# --- Camera ---
|
|
var camera_pitch := 0.0
|
|
var zoom := 5.0
|
|
|
|
@export var min_zoom := 1
|
|
@export var max_zoom := 10.0
|
|
@export var zoom_speed := 0.5
|
|
@export var min_pitch := deg_to_rad(-80)
|
|
@export var max_pitch := deg_to_rad(0)
|
|
@export var mouse_sensitivity:float = 0.0007
|
|
|
|
@onready var camera_3d: Camera3D = $Camera_Controller/Camera_Pivot/Camera3D
|
|
@onready var crosshair: Control = $Crosshair
|
|
@onready var spring_arm: SpringArm3D = $Camera_Controller/Camera_Pivot
|
|
@onready var interact_ray: ShapeCast3D = $InteractRay
|
|
@onready var chatbot = $Chatbot
|
|
@onready var env = $".."
|
|
|
|
var rock_scene: PackedScene = preload("res://Resources/Objects/rock.tscn")
|
|
|
|
signal inventory_opened
|
|
signal inventory_closed
|
|
signal chatbot_opened
|
|
|
|
func _ready() -> void:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
$Camera_Controller.position = position
|
|
$Armature/Skeleton3D/CharacterMesh.mesh = load(Global.mesh_resource_player)
|
|
|
|
camera_pitch = $Camera_Controller/Camera_Pivot.rotation.x
|
|
zoom = spring_arm.spring_length
|
|
if DialogueState.currentTask > 1:
|
|
$AnimationPlayer.play('helper_visible')
|
|
if Global.balloon_collected == true:
|
|
print(Global.resource_balloon)
|
|
_on_balloon_balloon_chosen(Global.resource_balloon)
|
|
|
|
func _process(delta: float) -> void:
|
|
if Global.chatbot_opened:
|
|
return
|
|
if Input.is_action_just_pressed("help"):
|
|
if DialogueState.is_dialogue_open == false:
|
|
DialogueState.is_dialogue_open = true
|
|
DialogueManager.show_chosen_dialogue_balloon(load("res://Interact/dialogue/helper.dialogue"), "/game_balloons/game_balloon_v_1.tscn", "start", [self, $Player/helper])
|
|
|
|
|
|
func _input(event):
|
|
if event is InputEventMouseMotion and mode == PlayerMode.NORMAL:
|
|
$Camera_Controller.rotate_y(-event.relative.x * mouse_sensitivity)
|
|
|
|
camera_pitch -= event.relative.y * mouse_sensitivity
|
|
camera_pitch = clamp(camera_pitch, min_pitch, max_pitch)
|
|
|
|
$Camera_Controller/Camera_Pivot.rotation.x = camera_pitch
|
|
|
|
if event is InputEventMouseButton and event.pressed:
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
zoom -= zoom_speed
|
|
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
zoom += zoom_speed
|
|
|
|
zoom = clamp(zoom, min_zoom, max_zoom)
|
|
spring_arm.spring_length = zoom
|
|
print(spring_arm.spring_length)
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
if Global.chatbot_opened or $Inventory.visible:
|
|
return
|
|
dialogueActive = DialogueState.is_dialogue_open
|
|
var thisTime = Time.get_unix_time_from_system()
|
|
|
|
# --- DROP / THROW ---
|
|
if Input.is_action_just_pressed("drop") and grabbed_item:
|
|
grabbed_item.release(self)
|
|
$AnimationPlayer.play_backwards("pickup")
|
|
play_sound('drop')
|
|
|
|
if Input.is_action_just_pressed("throw") and grabbed_item:
|
|
grabbed_item.release(self, true)
|
|
play_sound('drop')
|
|
|
|
elif Input.is_action_just_pressed("throw") and not grabbed_item:
|
|
if mode == PlayerMode.NORMAL:
|
|
mode = PlayerMode.AIM
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
else:
|
|
mode = PlayerMode.NORMAL
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
# --- AIM THROW ---
|
|
elif Input.is_action_just_pressed("click") and mode == PlayerMode.AIM and not dialogueActive and not $Inventory.visible:
|
|
var mouse_pos = get_viewport().get_mouse_position()
|
|
|
|
var ray_origin = camera_3d.project_ray_origin(mouse_pos)
|
|
var ray_direction = camera_3d.project_ray_normal(mouse_pos)
|
|
|
|
var ray_length = 1000
|
|
var space_state = get_world_3d().direct_space_state
|
|
var query = PhysicsRayQueryParameters3D.create(
|
|
ray_origin,
|
|
ray_origin + ray_direction * ray_length
|
|
)
|
|
|
|
query.exclude = [self]
|
|
|
|
#Exclude Boundary Layer (Layer 7)
|
|
query.collision_mask = ~(1 << 6)
|
|
var result = space_state.intersect_ray(query)
|
|
|
|
var target_position: Vector3
|
|
if result.size() > 0:
|
|
target_position = result.position
|
|
else:
|
|
target_position = ray_origin + ray_direction * ray_length
|
|
|
|
var from = global_transform.origin + Vector3(0, 1.5, 0)
|
|
var throw_direction = (target_position - from).normalized()
|
|
|
|
var rock_instance = rock_scene.instantiate()
|
|
get_tree().current_scene.add_child(rock_instance)
|
|
|
|
var forward_dir = -camera_3d.global_transform.basis.z.normalized()
|
|
rock_instance.global_transform.origin = from + forward_dir * 1.0
|
|
|
|
rock_instance.freeze = false
|
|
rock_instance.sleeping = false
|
|
rock_instance.gravity_scale = 0.0
|
|
rock_instance.linear_velocity = throw_direction * throw_strength
|
|
|
|
$AnimationPlayer.play("jump")
|
|
$audio_throw.play()
|
|
|
|
# --- GRAVITY ---
|
|
if not is_on_floor():
|
|
velocity += get_gravity() * delta
|
|
|
|
# --- JUMP ---
|
|
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
|
var deltaTime = thisTime - DialogueState.time_since_dialoge_open
|
|
|
|
if not dialogueActive and (deltaTime > 0.5):
|
|
$audio_jump.play()
|
|
velocity.y = JUMP_VELOCITY
|
|
$AnimationPlayer.stop()
|
|
$AnimationPlayer.play("jump")
|
|
await get_tree().create_timer(0.4).timeout
|
|
$AnimationPlayer.play_backwards("jump")
|
|
|
|
# --- MOVEMENT ---
|
|
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
|
|
|
|
if dialogueActive or $Inventory.visible:
|
|
input_dir = Vector2.ZERO
|
|
|
|
var direction : Vector3 = ($Camera_Controller.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
|
|
|
if input_dir != Vector2.ZERO:
|
|
self.rotation_degrees.y = $Camera_Controller.rotation_degrees.y - rad_to_deg(input_dir.angle()) - 90
|
|
|
|
# --- FLOOR ALIGN ---
|
|
if is_on_floor() and input_dir != Vector2.ZERO:
|
|
align_with_floor($RayCast3D.get_collision_normal())
|
|
global_transform = global_transform.interpolate_with(xform, 0.3)
|
|
elif not is_on_floor():
|
|
align_with_floor(Vector3.UP)
|
|
global_transform = global_transform.interpolate_with(xform, 0.3)
|
|
|
|
# --- VELOCITY ---
|
|
if direction:
|
|
velocity.x = direction.x * speed
|
|
velocity.z = direction.z * speed
|
|
|
|
if grabbed_item:
|
|
$AnimationPlayer.play("pickup_walk")
|
|
else:
|
|
$AnimationPlayer.play("walk")
|
|
else:
|
|
velocity.x = move_toward(velocity.x, 0, speed)
|
|
velocity.z = move_toward(velocity.z, 0, speed)
|
|
|
|
move_and_slide()
|
|
|
|
$Camera_Controller.position = lerp($Camera_Controller.position, position, 0.15)
|
|
|
|
|
|
func align_with_floor(floor_normal):
|
|
xform = global_transform
|
|
xform.basis.y = floor_normal
|
|
xform.basis.x = -xform.basis.z.cross(floor_normal)
|
|
xform.basis = xform.basis.orthonormalized()
|
|
|
|
|
|
func _on_fall_zone_body_entered(body: Node3D) -> void:
|
|
get_tree().reload_current_scene()
|
|
|
|
func openChatBot():
|
|
chatbot_opened.emit()
|
|
chatbot.visible = true
|
|
Global.chatbot_opened = true
|
|
chatbot._prompt_edit.grab_focus()
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
env.quiet_down_music()
|
|
|
|
|
|
func get_weight():
|
|
return weight
|
|
|
|
|
|
func _on_interact_ray_grabbed() -> void:
|
|
$AnimationPlayer.play("pickup")
|
|
|
|
func set_mode(mode_new: String) -> void:
|
|
if mode_new == "aim":
|
|
mode = PlayerMode.AIM
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
elif mode_new == "normal":
|
|
mode = PlayerMode.NORMAL
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
func toggle_inventory() -> void:
|
|
if $Inventory.visible:
|
|
$Inventory.visible = false
|
|
set_mode("normal")
|
|
inventory_closed.emit()
|
|
else:
|
|
$Inventory.visible = true
|
|
set_mode("aim")
|
|
inventory_opened.emit()
|
|
|
|
|
|
func _on_balloon_balloon_chosen(mesh: String) -> void:
|
|
$Balloon.visible = true
|
|
$Balloon.set_mesh(mesh)
|
|
Global.resource_balloon = mesh
|
|
Global.balloon_collected = true
|
|
|
|
func slow_down() -> void:
|
|
if counter_speed < len(speeds)-1:
|
|
counter_speed += 1
|
|
speed = speeds[counter_speed]
|
|
|
|
func reset_speed() -> void:
|
|
counter_speed = 0
|
|
speed = 5.0
|
|
|
|
|
|
func _on_animation_player_animation_started(anim_name: StringName) -> void:
|
|
if anim_name == 'walk' or anim_name == 'pickup_walk':
|
|
$AnimationPlayer.speed_scale = animation_player_speeds[counter_speed]
|
|
else:
|
|
$AnimationPlayer.speed_scale = animation_player_speeds[1]
|
|
|
|
func play_sound(sound_name: String) -> void:
|
|
if sound_name == 'pickup':
|
|
$audio_pickup.play()
|
|
elif sound_name == 'drop':
|
|
$audio_pickup.play()
|
|
|
|
func toggle_music() -> void:
|
|
env.toggle_music()
|