game/player_controller.gd

209 lines
5.8 KiB
GDScript3
Raw Normal View History

2023-01-10 02:36:09 +01:00
class_name PlayerController extends Node3D
2023-01-28 01:13:49 +01:00
##
2023-02-01 01:05:48 +01:00
## Selection action performed.
2023-01-28 01:13:49 +01:00
##
2023-02-01 01:05:48 +01:00
## [code]PRIMARY[/code] refers to the default selection action, while [code]SECONDARY[/code] refers
## to the secondary selection action.
2023-01-28 01:13:49 +01:00
##
enum SelectAction {
PRIMARY,
SECONDARY,
}
##
## Supported selection input devices.
##
enum SelectMode {
NONE,
MOUSE,
}
##
## The device being used for selection has changed.
##
signal select_mode_changed(mode: SelectMode)
##
2023-02-01 01:05:48 +01:00
## Selection of a point on the screen space has started happening, with [code]select_action[/code]
## as selection action performed.
##
## See [enum SelectAction] for more details.
##
signal selection_started(select_action: SelectAction)
##
## Selection of a point on screenspace has stopped happening.
##
signal selection_stopped()
2023-01-10 02:36:09 +01:00
const _BACKWARD := "player_controller_backward"
const _FORWARD := "player_controller_forward"
const _LEFT := "player_controller_left"
const _RIGHT := "player_controller_right"
const _ROTATE_CCW := "player_controller_rotate_ccw"
const _ROTATE_CW := "player_controller_rotate_cw"
const _DRAG_SPEED_BASE_MODIFIER := 0.15
const _MOVE_SMOOTHING := 0.5
2023-01-10 02:36:09 +01:00
const _MOVE_SPEED_BASE_MODIFIER := 50.0
const _ROTATE_SPEED_BASE := 5.0
const _TRANSFORM_DELTA := 10.0
@export
var _camera: Camera3D = null
var _control_override_count := 0
var _cursor_point := Vector2.ZERO
2023-01-10 02:36:09 +01:00
var _is_drag_panning := false
var _select_mode := SelectMode.NONE
@export
var _selection_area: Control = null
2023-01-10 02:36:09 +01:00
@onready
var _target_position := position
2023-01-10 02:36:09 +01:00
@onready
var _target_orientation := global_rotation.y
2023-01-10 02:36:09 +01:00
func _process(delta: float) -> void:
if not(is_frozen()):
var global_basis := global_transform.basis
var camera_settings := GameSettings.camera_settings
var delta_speed :=\
camera_settings.movement_speed_modifier * _MOVE_SPEED_BASE_MODIFIER * delta
_target_position += delta_speed.y * (-global_basis.z) *\
(Input.get_action_strength(_FORWARD) - Input.get_action_strength(_BACKWARD)) *\
(-1.0 if camera_settings.is_y_inverted else 1.0)
2023-01-10 02:36:09 +01:00
_target_position += delta_speed.x * (-global_basis.x) *\
(Input.get_action_strength(_LEFT) - Input.get_action_strength(_RIGHT)) *\
(-1.0 if camera_settings.is_y_inverted else 1.0)
2023-01-10 02:36:09 +01:00
_target_orientation += (Input.get_action_strength(_ROTATE_CCW) -\
Input.get_action_strength(_ROTATE_CW)) * _ROTATE_SPEED_BASE *\
camera_settings.rotation_speed_modifier * delta
2023-01-10 02:36:09 +01:00
global_transform = global_transform.interpolate_with(
Transform3D(Basis(Vector3.UP, _target_orientation), _target_position),
delta * _TRANSFORM_DELTA * _MOVE_SMOOTHING)
2023-01-10 02:36:09 +01:00
match _select_mode:
SelectMode.NONE:
_cursor_point = get_viewport().size / 2.0
SelectMode.MOUSE:
_cursor_point = get_viewport().get_mouse_position()
func _ready() -> void:
if _selection_area != null:
_selection_area.mouse_entered.connect(func () -> void:
if _select_mode != SelectMode.MOUSE:
_select_mode = SelectMode.MOUSE
select_mode_changed.emit(SelectMode.MOUSE))
_selection_area.mouse_exited.connect(func () -> void:
if _select_mode != SelectMode.NONE:
_select_mode = SelectMode.NONE
select_mode_changed.emit(SelectMode.NONE))
_selection_area.gui_input.connect(func (event: InputEvent) -> void:
if event is InputEventMouseButton:
match event.button_index:
MOUSE_BUTTON_MIDDLE:
_is_drag_panning = event.is_pressed() and not(is_frozen())
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if\
_is_drag_panning else Input.MOUSE_MODE_VISIBLE
MOUSE_BUTTON_LEFT:
if event.is_pressed():
selection_started.emit(SelectAction.PRIMARY)
else:
selection_stopped.emit()
MOUSE_BUTTON_RIGHT:
if event.is_pressed():
selection_started.emit(SelectAction.SECONDARY)
else:
selection_stopped.emit()
return
if (event is InputEventMouseMotion) and _is_drag_panning:
var global_basis := global_transform.basis
var camera_settings := GameSettings.camera_settings
var dampened_speed := camera_settings.movement_speed_modifier * _DRAG_SPEED_BASE_MODIFIER
_target_position += dampened_speed.y * (-global_basis.z) *\
event.relative.y * (-1.0 if camera_settings.is_y_inverted else 1.0)
_target_position += dampened_speed.x * (-global_basis.x) *\
event.relative.x * (-1.0 if camera_settings.is_x_inverted else 1.0)
return
if event is InputEventScreenDrag:
return
if event is InputEventScreenTouch:
return)
##
## Returns the position of the selection cursor with respect to the select current mode being used.
##
## When a mouse input device is being used, this will be its location in screen coordinates. For
## touchscreen interactions, this will be the location of an active gesture. Finally, for all other
## states - including gamepad - this will be the middle of screenspace at all times.
##
func get_plane_cursor() -> Vector2:
if _camera != null:
var plane_cursor = Plane(Vector3.UP, 0.0).intersects_ray(
_camera.global_position, _camera.project_ray_normal(_cursor_point))
if plane_cursor is Vector3:
return Vector2(plane_cursor.x, plane_cursor.z)
return Vector2.ZERO
2023-02-01 01:05:48 +01:00
##
## Returns [code]true[/code] if the player controller is currently frozen, otherwise
## [code]false[/code].
##
func is_frozen() -> bool:
assert(_control_override_count > -1, "control override count cannot be less than 0")
return _control_override_count != 0
2023-01-10 02:36:09 +01:00
2023-01-22 16:41:37 +01:00
##
2023-02-01 01:05:48 +01:00
## Overrides the controls of the player controller. When [code]unlock_signal[/code] is emitted, the
## override is released.
##
func override_controls(unlock_signal: Signal) -> void:
assert(_control_override_count > -1, "control override count cannot be less than 0")
_control_override_count += 1
unlock_signal.connect(func () -> void:
assert(_control_override_count > 0, "control override count cannot be less than 1")
_control_override_count -= 1, Object.CONNECT_ONE_SHOT)