159 lines
4.3 KiB
GDScript
159 lines
4.3 KiB
GDScript
class_name PlayerInput extends Node
|
|
|
|
enum Device {
|
|
Unknown,
|
|
KeyboardMouse,
|
|
Gamepad
|
|
}
|
|
|
|
class GameAction:
|
|
static var Run = 'run'
|
|
static var Interact = 'interact'
|
|
static var Ready = 'ready'
|
|
static var Fire = 'fire'
|
|
|
|
class UIAction:
|
|
static var Accept = 'ui_accept'
|
|
static var Select = 'ui_select'
|
|
static var Cancel = 'ui_cancel'
|
|
static var FocusNext = 'ui_focus_next'
|
|
static var FocusPrev = 'ui_focus_prev'
|
|
static var Left = 'ui_left'
|
|
static var Right = 'ui_right'
|
|
static var Up = 'ui_up'
|
|
static var Down = 'ui_down'
|
|
static var PageUp = 'ui_page_up'
|
|
static var PageDown = 'ui_page_down'
|
|
static var Home = 'ui_home'
|
|
static var End = 'ui_end'
|
|
|
|
signal walk
|
|
signal run
|
|
signal interact
|
|
signal ready_weapon
|
|
signal unready_weapon
|
|
signal fire
|
|
|
|
@export_flags_3d_physics var ground_collision_mask: int = 0
|
|
|
|
var last_known_device: Device = Device.Unknown
|
|
|
|
var _is_running: bool = false
|
|
var is_running: bool:
|
|
get: return _is_running
|
|
set(value):
|
|
if _is_running != value:
|
|
_is_running = value
|
|
if value: run.emit()
|
|
else: walk.emit()
|
|
|
|
var _is_interacting: bool = false
|
|
var is_interacting: bool:
|
|
get: return _is_interacting
|
|
set(value):
|
|
if _is_interacting != value:
|
|
_is_interacting = value
|
|
if value: interact.emit()
|
|
|
|
var _is_weapon_ready: bool = false
|
|
var is_weapon_ready: bool:
|
|
get: return _is_weapon_ready
|
|
set(value):
|
|
if _is_weapon_ready != value:
|
|
_is_weapon_ready = value
|
|
if value: ready_weapon.emit()
|
|
else: unready_weapon.emit()
|
|
|
|
var _is_firing: bool = false
|
|
var is_firing: bool:
|
|
get: return _is_firing
|
|
set(value):
|
|
if _is_firing != value:
|
|
_is_firing = value
|
|
if value: fire.emit()
|
|
|
|
var movement_dir: Vector2:
|
|
get: return Input.get_vector(
|
|
'move_left', 'move_right',
|
|
'move_up', 'move_down'
|
|
).normalized()
|
|
|
|
var _active_camera: Camera3D:
|
|
get: return get_viewport().get_camera_3d()
|
|
|
|
var _mouse_position: Vector2:
|
|
get: return get_viewport().get_mouse_position()
|
|
|
|
var _analog_dir: Vector2:
|
|
get: return Input.get_vector(
|
|
'look_left', 'look_right',
|
|
'look_up', 'look_down'
|
|
).normalized()
|
|
|
|
func _process(_delta: float) -> void:
|
|
is_running = Input.is_action_pressed(GameAction.Run)
|
|
|
|
func _get_device(event: InputEvent) -> Device:
|
|
if event is InputEventMouse or event is InputEventKey:
|
|
return Device.KeyboardMouse
|
|
elif event is InputEventJoypadButton or event is InputEventJoypadMotion:
|
|
return Device.Gamepad
|
|
else:
|
|
return Device.Unknown
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
last_known_device = _get_device(event)
|
|
|
|
if event.is_action_pressed(GameAction.Interact):
|
|
is_interacting = true
|
|
|
|
if event.is_action_released(GameAction.Interact):
|
|
is_interacting = false
|
|
|
|
if event.is_action_pressed(GameAction.Ready):
|
|
is_weapon_ready = true
|
|
|
|
if event.is_action_released(GameAction.Ready):
|
|
is_weapon_ready = false
|
|
|
|
if event.is_action_pressed(GameAction.Fire):
|
|
is_firing = true
|
|
|
|
if event.is_action_released(GameAction.Fire):
|
|
is_firing = false
|
|
|
|
func next_velocity(speed: float, dir: Vector2 = movement_dir) -> Vector3:
|
|
return Vector3(dir.x, 0, dir.y) * speed
|
|
|
|
func get_mouse_look() -> Vector3:
|
|
var cam: Camera3D = _active_camera
|
|
|
|
if not cam:
|
|
return Vector3.ZERO
|
|
|
|
var mouse_pos = _mouse_position
|
|
|
|
var ray_origin = cam.project_ray_origin(mouse_pos)
|
|
var ray_direction = cam.project_ray_normal(mouse_pos)
|
|
|
|
var plane_normal = Vector3.UP
|
|
var plane_d = 1.5 # make this read from the weapon transform, or at least export it
|
|
var denominator = plane_normal.dot(ray_direction)
|
|
if abs(denominator) < 0.0001:
|
|
return Vector3(ray_origin.x, 1.5, ray_origin.z)
|
|
|
|
var t = (plane_d - plane_normal.dot(ray_origin)) / denominator
|
|
var intersection_point = ray_origin + ray_direction * t
|
|
|
|
return intersection_point
|
|
|
|
func get_look_target(position: Vector3) -> Option:
|
|
match last_known_device:
|
|
Device.KeyboardMouse:
|
|
return Option.some(get_mouse_look())
|
|
Device.Gamepad:
|
|
var pos = _analog_dir
|
|
if pos.is_zero_approx():
|
|
return Option.none
|
|
return Option.some(Vector3(pos.x, 0, pos.y) + position)
|
|
_: return Option.none
|