extends CharacterBody3D class_name Player3D const POINTER_TEXTURE = preload("res://common/icons/focus.svg") const POINTER_ACTION_TEXTURE = preload("res://common/icons/hand-finger.svg") @export var pointer_texture_rect : TextureRect @export var speed := 4.0 const MOUSE_SENSIVITY = 0.002 const RAY_LENGTH = 10. const PUSH_FORCE = 0.6 var action_hovered : Interactable3D = null var query_mouse := false @export var controlling_player = true func _ready(): Dialogic.timeline_started.connect( func(): Input.mouse_mode = Input.MOUSE_MODE_VISIBLE controlling_player = false ) Dialogic.timeline_ended.connect( func(): Input.mouse_mode = Input.MOUSE_MODE_CAPTURED controlling_player = true ) %MoveTutorial.visible = not "3d_move" in GameInfo.game_data.tutorials_done %InteractTutorial.visible = false func _input(event): if controlling_player: if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * MOUSE_SENSIVITY) %Camera3D.rotate_x(-event.relative.y * MOUSE_SENSIVITY) %Camera3D.rotation.x = clampf($Camera3D.rotation.x, -deg_to_rad(70), deg_to_rad(70)) query_mouse = true if event.is_action_pressed("action") and action_hovered and action_hovered.interactable: if %InteractTutorial.visible: var tween = create_tween() tween.tween_property(%InteractTutorial, "modulate:a", 0., 0.8) GameInfo.game_data.tutorials_done.append("3d_action") action_hovered.click() func _physics_process(delta): if controlling_player: if query_mouse: update_mouse_hovered_actions() %PointerTexture.texture = ( POINTER_ACTION_TEXTURE if action_hovered != null and action_hovered.interactable else POINTER_TEXTURE ) query_mouse = false # 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("move_left", "move_right", "move_up", "move_down") if Input.is_action_pressed("move_pointer"): input_dir.y = -1 var 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 %MoveTutorial.visible and direction.length(): var tween = create_tween() tween.tween_property(%MoveTutorial, "modulate:a", 0., 0.8) GameInfo.game_data.tutorials_done.append("3d_move") else : velocity = Vector3.ZERO # Add the gravity. if not is_on_floor(): velocity += get_gravity() * delta move_and_slide() for i in get_slide_collision_count(): var collision = get_slide_collision(i) if collision.get_collider() is RigidBody3D: collision.get_collider().apply_central_impulse( -collision.get_normal() * PUSH_FORCE ) func update_mouse_hovered_actions() -> void: var space_state = get_world_3d().direct_space_state var middle_screen = get_viewport().get_visible_rect().size / 2 var from = %Camera3D.project_ray_origin(middle_screen) var to = from + %Camera3D.project_ray_normal(middle_screen) * RAY_LENGTH var query = PhysicsRayQueryParameters3D.create(from, to) query.collide_with_areas = true var result = space_state.intersect_ray(query) if result and result.collider and result.collider is Interactable3D: if action_hovered != result.collider: if action_hovered and action_hovered != result.collider: action_hovered._on_mouse_exited() action_hovered = result.collider action_hovered._on_mouse_entered() if not "3d_action" in GameInfo.game_data.tutorials_done: %InteractTutorial.visible = true %InteractTutorial.modulate.a = 0. var tween = create_tween() tween.tween_property(%InteractTutorial, "modulate:a", 1., 0.2) else : if action_hovered: action_hovered._on_mouse_exited() action_hovered = null