Add support for multi-context control overrides to player controller

This commit is contained in:
kayomn 2023-01-25 23:36:53 +00:00
parent 7526e60037
commit 0d11abfe23
1 changed files with 72 additions and 63 deletions

View File

@ -37,6 +37,8 @@ const _ROTATE_CW := "player_controller_rotate_cw"
const _DRAG_SPEED_BASE_MODIFIER := 0.15 const _DRAG_SPEED_BASE_MODIFIER := 0.15
const _MOVE_SMOOTHING := 0.5
const _MOVE_SPEED_BASE_MODIFIER := 50.0 const _MOVE_SPEED_BASE_MODIFIER := 50.0
const _ROTATE_SPEED_BASE := 5.0 const _ROTATE_SPEED_BASE := 5.0
@ -46,6 +48,8 @@ const _TRANSFORM_DELTA := 10.0
@export @export
var _camera: Camera3D = null var _camera: Camera3D = null
var _control_override_count := 0
var _cursor_point := Vector2.ZERO var _cursor_point := Vector2.ZERO
var _is_drag_panning := false var _is_drag_panning := false
@ -58,52 +62,40 @@ var _select_mode := SelectMode.NONE
var _selection_area: Control = null var _selection_area: Control = null
@onready @onready
var _target_position := self.position var _target_position := position
@onready @onready
var _target_orientation := self.global_rotation.y var _target_orientation := global_rotation.y
##
## Smoothness applies to the interpolation toward rotation and movement target values.
##
@export
var movement_smoothing := 0.5
##
## Whether or not player movement input processed by the controller should be ignored.
##
@export
var frozen := false
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if event is InputEventMouseButton: if event is InputEventMouseButton:
match event.button_index: match event.button_index:
MOUSE_BUTTON_MIDDLE: MOUSE_BUTTON_MIDDLE:
self._is_drag_panning = event.is_pressed() and not(self.frozen) _is_drag_panning = event.is_pressed() and not(is_frozen())
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if\ Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if\
self._is_drag_panning else Input.MOUSE_MODE_VISIBLE _is_drag_panning else Input.MOUSE_MODE_VISIBLE
MOUSE_BUTTON_LEFT: MOUSE_BUTTON_LEFT:
self._is_selecting = event.is_pressed() _is_selecting = event.is_pressed()
if self._is_selecting: if _is_selecting:
self.selection_started.emit() selection_started.emit()
else: else:
self.selection_stopped.emit() selection_stopped.emit()
return return
if (event is InputEventMouseMotion) and self._is_drag_panning: if (event is InputEventMouseMotion) and _is_drag_panning:
var global_basis := self.global_transform.basis var global_basis := global_transform.basis
var camera_settings := GameSettings.camera_settings var camera_settings := GameSettings.camera_settings
var dampened_speed := camera_settings.movement_speed_modifier * _DRAG_SPEED_BASE_MODIFIER var dampened_speed := camera_settings.movement_speed_modifier * _DRAG_SPEED_BASE_MODIFIER
self._target_position += dampened_speed.y * (-global_basis.z) *\ _target_position += dampened_speed.y * (-global_basis.z) *\
event.relative.y * (-1.0 if camera_settings.is_y_inverted else 1.0) event.relative.y * (-1.0 if camera_settings.is_y_inverted else 1.0)
self._target_position += dampened_speed.x * (-global_basis.x) *\ _target_position += dampened_speed.x * (-global_basis.x) *\
event.relative.x * (-1.0 if camera_settings.is_x_inverted else 1.0) event.relative.x * (-1.0 if camera_settings.is_x_inverted else 1.0)
return return
@ -115,65 +107,49 @@ func _input(event: InputEvent) -> void:
return return
func _process(delta: float) -> void: func _process(delta: float) -> void:
if not(self.frozen): if not(is_frozen()):
var global_basis := self.global_transform.basis var global_basis := global_transform.basis
var camera_settings := GameSettings.camera_settings var camera_settings := GameSettings.camera_settings
var delta_speed :=\ var delta_speed :=\
camera_settings.movement_speed_modifier * _MOVE_SPEED_BASE_MODIFIER * delta camera_settings.movement_speed_modifier * _MOVE_SPEED_BASE_MODIFIER * delta
self._target_position += delta_speed.y * (-global_basis.z) *\ _target_position += delta_speed.y * (-global_basis.z) *\
(Input.get_action_strength(_FORWARD) - Input.get_action_strength(_BACKWARD)) *\ (Input.get_action_strength(_FORWARD) - Input.get_action_strength(_BACKWARD)) *\
(-1.0 if camera_settings.is_y_inverted else 1.0) (-1.0 if camera_settings.is_y_inverted else 1.0)
self._target_position += delta_speed.x * (-global_basis.x) *\ _target_position += delta_speed.x * (-global_basis.x) *\
(Input.get_action_strength(_LEFT) - Input.get_action_strength(_RIGHT)) *\ (Input.get_action_strength(_LEFT) - Input.get_action_strength(_RIGHT)) *\
(-1.0 if camera_settings.is_y_inverted else 1.0) (-1.0 if camera_settings.is_y_inverted else 1.0)
self._target_orientation += (Input.get_action_strength(_ROTATE_CCW) -\ _target_orientation += (Input.get_action_strength(_ROTATE_CCW) -\
Input.get_action_strength(_ROTATE_CW)) * _ROTATE_SPEED_BASE *\ Input.get_action_strength(_ROTATE_CW)) * _ROTATE_SPEED_BASE *\
camera_settings.rotation_speed_modifier * delta camera_settings.rotation_speed_modifier * delta
self.global_transform = self.global_transform.interpolate_with( global_transform = global_transform.interpolate_with(
Transform3D(Basis(Vector3.UP, self._target_orientation), self._target_position), Transform3D(Basis(Vector3.UP, _target_orientation), _target_position),
delta * _TRANSFORM_DELTA * self.movement_smoothing) delta * _TRANSFORM_DELTA * _MOVE_SMOOTHING)
match self._select_mode: match _select_mode:
SelectMode.NONE: SelectMode.NONE:
self._cursor_point = self.get_viewport().size / 2.0 _cursor_point = get_viewport().size / 2.0
SelectMode.MOUSE: SelectMode.MOUSE:
self._cursor_point = self.get_viewport().get_mouse_position() _cursor_point = get_viewport().get_mouse_position()
func _ready() -> void: func _ready() -> void:
if self._selection_area != null: if _selection_area != null:
self._selection_area.mouse_entered.connect(func () -> void: _selection_area.mouse_entered.connect(func () -> void:
if self._select_mode != SelectMode.MOUSE: if _select_mode != SelectMode.MOUSE:
self._select_mode = SelectMode.MOUSE _select_mode = SelectMode.MOUSE
self.select_mode_changed.emit(SelectMode.MOUSE)) select_mode_changed.emit(SelectMode.MOUSE))
self._selection_area.mouse_exited.connect(func () -> void: _selection_area.mouse_exited.connect(func () -> void:
if self._select_mode != SelectMode.NONE: if _select_mode != SelectMode.NONE:
self._select_mode = SelectMode.NONE _select_mode = SelectMode.NONE
self.select_mode_changed.emit(SelectMode.NONE)) select_mode_changed.emit(SelectMode.NONE))
##
##
##
func in_select_area() -> bool:
return self._select_mode != SelectMode.NONE
##
## Returns [code]true[/code] if the player controller is currently selecting a location on the
## screen, otherwise [code]false[/code].
##
## *Note* that it is discouraged that this be continuously polled for single-fire events. Instead,
## see [signal selection_started] and [signal selection_stopped].
##
func is_selecting() -> bool:
return self._is_selecting
## ##
## Returns the position of the selection cursor with respect to the select current mode being used. ## Returns the position of the selection cursor with respect to the select current mode being used.
@ -183,7 +159,40 @@ func is_selecting() -> bool:
## states - including gamepad - this will be the middle of screenspace at all times. ## states - including gamepad - this will be the middle of screenspace at all times.
## ##
func get_cursor_point() -> Vector2: func get_cursor_point() -> Vector2:
return self._cursor_point return _cursor_point
func is_frozen() -> bool:
assert(_control_override_count > -1, "control override count cannot be less than 0")
return _control_override_count != 0
##
##
##
func in_select_area() -> bool:
return _select_mode != SelectMode.NONE
##
## Returns [code]true[/code] if the player controller is currently selecting a location on the
## screen, otherwise [code]false[/code].
##
## *Note* that it is discouraged that this be continuously polled for single-fire events. Instead,
## see [signal selection_started] and [signal selection_stopped].
##
func is_selecting() -> bool:
return _is_selecting
##
##
##
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)
## ##
## Attempts to convert the screen coordinates in [code]screen_point[/code] into 2D worldspace ## Attempts to convert the screen coordinates in [code]screen_point[/code] into 2D worldspace
@ -193,9 +202,9 @@ func get_cursor_point() -> Vector2:
## [code]null[/code] is returned. ## [code]null[/code] is returned.
## ##
func screen_to_plane(screen_point: Vector2) -> Variant: func screen_to_plane(screen_point: Vector2) -> Variant:
if self._camera != null: if _camera != null:
var plane_target = Plane(Vector3.UP, 0.0).intersects_ray( var plane_target = Plane(Vector3.UP, 0.0).intersects_ray(
self._camera.global_position, self._camera.project_ray_normal(screen_point)) _camera.global_position, _camera.project_ray_normal(screen_point))
if plane_target is Vector3: if plane_target is Vector3:
return Vector2(plane_target.x, plane_target.z) return Vector2(plane_target.x, plane_target.z)