diff --git a/player_controller.gd b/player_controller.gd index 968840a..e9acec7 100644 --- a/player_controller.gd +++ b/player_controller.gd @@ -37,6 +37,8 @@ const _ROTATE_CW := "player_controller_rotate_cw" const _DRAG_SPEED_BASE_MODIFIER := 0.15 +const _MOVE_SMOOTHING := 0.5 + const _MOVE_SPEED_BASE_MODIFIER := 50.0 const _ROTATE_SPEED_BASE := 5.0 @@ -46,6 +48,8 @@ const _TRANSFORM_DELTA := 10.0 @export var _camera: Camera3D = null +var _control_override_count := 0 + var _cursor_point := Vector2.ZERO var _is_drag_panning := false @@ -58,52 +62,40 @@ var _select_mode := SelectMode.NONE var _selection_area: Control = null @onready -var _target_position := self.position +var _target_position := position @onready -var _target_orientation := self.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 +var _target_orientation := global_rotation.y func _input(event: InputEvent) -> void: if event is InputEventMouseButton: match event.button_index: 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\ - self._is_drag_panning else Input.MOUSE_MODE_VISIBLE + _is_drag_panning else Input.MOUSE_MODE_VISIBLE MOUSE_BUTTON_LEFT: - self._is_selecting = event.is_pressed() + _is_selecting = event.is_pressed() - if self._is_selecting: - self.selection_started.emit() + if _is_selecting: + selection_started.emit() else: - self.selection_stopped.emit() + selection_stopped.emit() return - if (event is InputEventMouseMotion) and self._is_drag_panning: - var global_basis := self.global_transform.basis + 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 - 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) - 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) return @@ -115,65 +107,49 @@ func _input(event: InputEvent) -> void: return func _process(delta: float) -> void: - if not(self.frozen): - var global_basis := self.global_transform.basis + 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 - 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)) *\ (-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)) *\ (-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 *\ camera_settings.rotation_speed_modifier * delta - self.global_transform = self.global_transform.interpolate_with( - Transform3D(Basis(Vector3.UP, self._target_orientation), self._target_position), - delta * _TRANSFORM_DELTA * self.movement_smoothing) + global_transform = global_transform.interpolate_with( + Transform3D(Basis(Vector3.UP, _target_orientation), _target_position), + delta * _TRANSFORM_DELTA * _MOVE_SMOOTHING) - match self._select_mode: + match _select_mode: SelectMode.NONE: - self._cursor_point = self.get_viewport().size / 2.0 + _cursor_point = get_viewport().size / 2.0 SelectMode.MOUSE: - self._cursor_point = self.get_viewport().get_mouse_position() + _cursor_point = 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 + if _selection_area != null: + _selection_area.mouse_entered.connect(func () -> void: + if _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: - if self._select_mode != SelectMode.NONE: - self._select_mode = SelectMode.NONE + _selection_area.mouse_exited.connect(func () -> void: + if _select_mode != SelectMode.NONE: + _select_mode = SelectMode.NONE - self.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 + select_mode_changed.emit(SelectMode.NONE)) ## ## 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. ## 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 @@ -193,9 +202,9 @@ func get_cursor_point() -> Vector2: ## [code]null[/code] is returned. ## 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( - 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: return Vector2(plane_target.x, plane_target.z)