Fix player controller incompatibility with editor menus

This commit is contained in:
kayomn 2023-01-12 00:43:23 +00:00
parent 58d9a0b8c5
commit 0dc5288e45
2 changed files with 139 additions and 25 deletions

BIN
editor.scn (Stored with Git LFS)

Binary file not shown.

View File

@ -1,5 +1,28 @@
class_name PlayerController extends Node3D class_name PlayerController extends Node3D
##
## Supported selection input devices.
##
enum SelectMode {
NONE,
MOUSE,
}
##
## The device being used for selection has changed.
##
signal select_mode_changed(mode: SelectMode)
##
## Selection of a point on screenspace has started happening.
##
signal selection_started()
##
## Selection of a point on screenspace has stopped happening.
##
signal selection_stopped()
const _BACKWARD := "player_controller_backward" const _BACKWARD := "player_controller_backward"
const _FORWARD := "player_controller_forward" const _FORWARD := "player_controller_forward"
@ -20,29 +43,54 @@ const _ROTATE_SPEED_BASE := 5.0
const _TRANSFORM_DELTA := 10.0 const _TRANSFORM_DELTA := 10.0
@export
var _camera: Camera3D = null
var _cursor_point := Vector2.ZERO
var _is_drag_panning := false var _is_drag_panning := false
var _is_selecting := false
var _select_mode := SelectMode.NONE
@export
var _selection_area: Control = null
@onready @onready
var _target_position := self.position var _target_position := self.position
@onready @onready
var _target_orientation := self.global_rotation.y var _target_orientation := self.global_rotation.y
##
## Smoothness applies to the interpolation toward rotation and movement target values.
##
@export @export
var movement_smoothing := 0.5 var movement_smoothing := 0.5
##
## Whether or not player movement input processed by the controller should be ignored.
##
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() self._is_drag_panning = event.is_pressed() and not(self.frozen)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if self._is_drag_panning else Input.MOUSE_MODE_VISIBLE
MOUSE_BUTTON_WHEEL_DOWN: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if\
pass self._is_drag_panning else Input.MOUSE_MODE_VISIBLE
MOUSE_BUTTON_WHEEL_UP: MOUSE_BUTTON_LEFT:
pass self._is_selecting = event.is_pressed()
if self._is_selecting:
self.selection_started.emit()
else:
self.selection_stopped.emit()
return return
@ -64,10 +112,16 @@ func _input(event: InputEvent) -> void:
if event is InputEventScreenDrag: if event is InputEventScreenDrag:
return return
if event is InputEventScreenTouch:
return
func _process(delta: float) -> void: func _process(delta: float) -> void:
if not(self.frozen):
var global_basis := self.global_transform.basis var global_basis := self.global_transform.basis
var camera_settings := GameSettings.camera_settings var camera_settings := GameSettings.camera_settings
var delta_speed := camera_settings.movement_speed_modifier * _MOVE_SPEED_BASE_MODIFIER * delta
var delta_speed :=\
camera_settings.movement_speed_modifier * _MOVE_SPEED_BASE_MODIFIER * delta
self._target_position += delta_speed.y * (-global_basis.z) *\ self._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)) *\
@ -85,8 +139,68 @@ func _process(delta: float) -> void:
Transform3D(Basis(Vector3.UP, self._target_orientation), self._target_position), Transform3D(Basis(Vector3.UP, self._target_orientation), self._target_position),
delta * _TRANSFORM_DELTA * self.movement_smoothing) delta * _TRANSFORM_DELTA * self.movement_smoothing)
match self._select_mode:
SelectMode.NONE:
self._cursor_point = self.get_viewport().size / 2.0
SelectMode.MOUSE:
self._cursor_point = self.get_viewport().get_mouse_position()
func _ready() -> void:
if self._selection_area != null:
self._selection_area.mouse_entered.connect(func () -> void:
if self._select_mode != SelectMode.MOUSE:
self._select_mode = SelectMode.MOUSE
self.select_mode_changed.emit(SelectMode.MOUSE))
self._selection_area.mouse_exited.connect(func () -> void:
if self._select_mode != SelectMode.NONE:
self._select_mode = SelectMode.NONE
self.select_mode_changed.emit(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_drag_panning() -> bool: func is_selecting() -> bool:
return self._is_drag_panning return self._is_selecting
##
## 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_cursor_point() -> Vector2:
return self._cursor_point
##
## Returns the current [enum SelectMode] being used for selections.
##
## The general use-case for this function is to peek through the player controller abstraction and
## see what supported hardware interface is currently being used to select in the world. This is
## useful for handling input-specific behaviors, such as showing a mouse cursor when a mouse input
## device is being used.
##
func get_select_mode() -> int:
return self._select_mode
##
## Converts and returns the screen coordinates in [code]screen_point[/code] into 2D worldspace
## coordinates relative to an infinite ground plane at a y offset of [code]0.0[/code].
##
func screen_to_plane(screen_point: Vector2):
if self._camera != null:
var plane_target = Plane(Vector3.UP, 0.0).intersects_ray(
self._camera.global_position, self._camera.project_ray_normal(screen_point))
if plane_target is Vector3:
return Vector2(plane_target.x, plane_target.z)
return null