class_name Player extends CharacterBody3D const SPEED = 3.0 const JUMP_VELOCITY = 3.5 @onready var geometry:Node3D = %Geometry @onready var actionable_detector = %ActionableDetector @onready var animation_tree:AnimationTree = $Geometry/Rogue/AnimationTree @onready var build_location:Node3D = %BuildLocation @onready var right_hand_attachement:Node3D = %RightHandAttachement # Get the gravity from the project settings to be synced with RigidBody nodes. var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") var inventory:Inventory = Inventory.new() var selected_tool_slot_index:int = 0 var current_tool:ItemResource = null var _direction:Vector3 = Vector3.ZERO var _look_direction:Vector3 = Vector3.BACK var _look_direction_damper:SpringDamper = SpringDamper.new(Vector3.ZERO) var is_conversation_active:bool = false signal trigger_message(message:String) func _process(_delta): if animation_tree.get("parameters/playback").get_current_node() == "Interact": animation_tree.set("parameters/conditions/interact", false) func _handle_input() -> void: # Get the input direction and handle the movement/deceleration. # As good practice, you should replace UI actions with custom gameplay actions. var input_dir = Input.get_vector("walk_left", "walk_right", "walk_forward", "walk_back") _direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() if _direction: velocity.x = _direction.x * SPEED velocity.z = _direction.z * SPEED else: velocity.x = move_toward(velocity.x, 0, SPEED) velocity.z = move_toward(velocity.z, 0, SPEED) if is_on_floor() and Input.is_action_just_pressed("jump"): velocity.y = JUMP_VELOCITY func _physics_process(delta): # Add the gravity. if not is_on_floor(): velocity.y -= gravity * delta if not is_conversation_active: _handle_input() move_and_slide() var ground_velocity:Vector2 = Vector2(velocity.x, velocity.z) var is_moving:bool = ground_velocity.length_squared() > 0.1 * 0.1 if is_moving: _look_direction = Vector3(ground_velocity.x, 0, ground_velocity.y).normalized() elif _direction.length_squared() > 0.1 * 0.1: _look_direction = _direction var damped_look_direction = _look_direction_damper.calc(global_basis.z, _look_direction, delta) animation_tree.set("parameters/conditions/running", is_moving) animation_tree.set("parameters/conditions/idle", not is_moving) geometry.look_at(position - damped_look_direction, Vector3.UP) func set_tool_slot_index(value:int) -> void: if inventory == null: return selected_tool_slot_index = value set_right_hand_item(inventory.get_tool_item_stacks()[selected_tool_slot_index].item) func on_item_picked_up(item:ItemResource): trigger_message.emit("Picked up a " + item.name) inventory.add_item(item) func get_actionable_global_transform() -> Vector3: return build_location.global_position func set_right_hand_item(item:ItemResource) -> void: for child in right_hand_attachement.get_children(): child.queue_free() current_tool = null if item != null and item.is_tool: right_hand_attachement.add_child(item.scene.instantiate()) current_tool = item animation_tree.set("parameters/Interact/conditions/tool_action_slice", false) animation_tree.set("parameters/Interact/conditions/tool_action_chop", false) match item.tool_action: 1: animation_tree.set("parameters/Interact/conditions/tool_action_chop", true) 2: animation_tree.set("parameters/Interact/conditions/tool_action_slice", true) func has_build_tool_active() -> bool: if current_tool and current_tool.resource_path == "res://data/items/hammer.tres": return true return false func handle_tool_slot_input_events(_event:InputEvent) -> bool: var key_event:InputEventKey = _event as InputEventKey if key_event and key_event.is_released(): if key_event.keycode >= KEY_1 and key_event.keycode <= KEY_9: set_tool_slot_index(key_event.keycode - KEY_1) return true if _event.is_action_released("item_next"): set_tool_slot_index((selected_tool_slot_index + 1) % (inventory.get_tool_item_stacks().size())) return true if _event.is_action_released("item_prev"): var tool_slot_size = inventory.get_tool_item_stacks().size() set_tool_slot_index((selected_tool_slot_index + tool_slot_size - 1) % (tool_slot_size)) return true return false func _unhandled_input(_event: InputEvent) -> void: if Input.is_action_just_pressed("ui_accept"): var actionables = actionable_detector.get_overlapping_areas() if actionables.size() > 0: _look_direction = (actionables[0].global_position - position).normalized() actionables[0].action() get_viewport().set_input_as_handled() return if Input.is_action_just_pressed("interaction"): animation_tree.set("parameters/conditions/interact", true) get_viewport().set_input_as_handled() return