rotate toward cursor working (controller untested)
This commit is contained in:
parent
c9cc6173f0
commit
90dc606009
6 changed files with 95 additions and 89 deletions
|
@ -1,39 +0,0 @@
|
|||
import { Camera3D, float64, Vector3 } from 'godot'
|
||||
|
||||
export class CameraCache extends Object {
|
||||
private _camera: Camera3D
|
||||
get camera() { return this._camera }
|
||||
|
||||
private _angle: float64
|
||||
|
||||
get angle() {
|
||||
return this._camera.rotation.y
|
||||
}
|
||||
|
||||
private _dirty: boolean = true
|
||||
|
||||
constructor(initial_camera: Camera3D) {
|
||||
super()
|
||||
this._camera = initial_camera
|
||||
this._angle = this._camera.rotation.y
|
||||
}
|
||||
|
||||
update_camera(camera: Camera3D) {
|
||||
this._camera = camera
|
||||
this._dirty = true
|
||||
}
|
||||
|
||||
recalculate() {
|
||||
if (this._dirty) {
|
||||
this._angle = this._camera.rotation.y
|
||||
this._dirty = false
|
||||
}
|
||||
}
|
||||
|
||||
transform_vec(vec: Vector3): Vector3 {
|
||||
return vec.rotated(Vector3.UP, this._angle)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { Area3D, Camera3D, NodePath, PhysicsBody3D, Variant } from 'godot'
|
||||
import { export_ } from 'godot.annotations'
|
||||
import Player from './player'
|
||||
import MessageBus from './message_bus'
|
||||
|
||||
export default class CameraTrigger extends Area3D {
|
||||
@export_(Variant.Type.TYPE_NODE_PATH)
|
||||
camera!: NodePath
|
||||
_camera!: Camera3D
|
||||
|
||||
_ready(): void {
|
||||
this._camera = this.get_node(this.camera) as Camera3D
|
||||
}
|
||||
|
||||
_on_body_entered(body: PhysicsBody3D) {
|
||||
if (body instanceof Player) {
|
||||
this._camera?.make_current()
|
||||
console.log(MessageBus.instance.active_camera_changed)
|
||||
MessageBus.instance.active_camera_changed.emit(this._camera)
|
||||
}
|
||||
}
|
||||
}
|
15
src/main_camera.ts
Normal file
15
src/main_camera.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Camera3D } from 'godot'
|
||||
import MessageBus from './message_bus'
|
||||
|
||||
export default class MainCamera extends Camera3D {
|
||||
private static _instance: MainCamera
|
||||
|
||||
static get instance() {
|
||||
return MainCamera._instance
|
||||
}
|
||||
|
||||
_ready(): void {
|
||||
MainCamera._instance = this
|
||||
MessageBus.instance.active_camera_changed.emit(this)
|
||||
}
|
||||
}
|
|
@ -2,16 +2,16 @@ import { Camera3D, Node, Signal1 } from 'godot'
|
|||
import { signal } from 'godot.annotations'
|
||||
|
||||
export default class MessageBus extends Node {
|
||||
private static _inst: MessageBus
|
||||
private static _instance: MessageBus
|
||||
|
||||
static get instance() {
|
||||
return MessageBus._inst
|
||||
return MessageBus._instance
|
||||
}
|
||||
|
||||
@signal()
|
||||
active_camera_changed!: Signal1<Camera3D>
|
||||
|
||||
_ready(): void {
|
||||
MessageBus._inst = this
|
||||
MessageBus._instance = this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Callable, Callable0, Callable1, Camera3D, CharacterBody3D, Color, float64, NodePath, ProjectSettings, Variant, Vector2, Vector3 } from 'godot'
|
||||
import { AnyCallable, AnySignal, Callable, Callable0, Callable1, Camera3D, CharacterBody3D, Color, float64, NodePath, ProjectSettings, Signal, Signal0, Signal1, Variant, Vector2, Vector3 } from 'godot'
|
||||
import { export_, help, onready } from 'godot.annotations'
|
||||
import PlayerInput from './player_input'
|
||||
import DebugDraw from './debug_draw'
|
||||
|
@ -6,33 +6,34 @@ import Interactor from './interactor'
|
|||
import PlayerAnimation, { PlayerAnimationName } from './player_animation'
|
||||
|
||||
export default class Player extends CharacterBody3D {
|
||||
gravity = ProjectSettings.get_setting('physics/3d/default_gravity')
|
||||
|
||||
@export_(Variant.Type.TYPE_NODE_PATH)
|
||||
camera!: NodePath
|
||||
private _camera!: Camera3D
|
||||
readonly gravity = ProjectSettings.get_setting('physics/3d/default_gravity')
|
||||
|
||||
@onready("Input")
|
||||
player_input!: PlayerInput
|
||||
readonly player_input!: PlayerInput
|
||||
|
||||
@onready("AnimationTree")
|
||||
player_animation!: PlayerAnimation
|
||||
readonly player_animation!: PlayerAnimation
|
||||
|
||||
@onready("Interactor")
|
||||
interactor!: Interactor
|
||||
readonly interactor!: Interactor
|
||||
|
||||
@help('Forward walk speed in units per second')
|
||||
@export_(Variant.Type.TYPE_FLOAT)
|
||||
walk_speed = 3
|
||||
readonly walk_speed = 3
|
||||
|
||||
@help('Run speed in units per second')
|
||||
@export_(Variant.Type.TYPE_FLOAT)
|
||||
run_speed = 6
|
||||
readonly run_speed = 6
|
||||
|
||||
@help('Turn speed in rotations per second')
|
||||
@export_(Variant.Type.TYPE_FLOAT)
|
||||
turn_speed = 1
|
||||
_rotation_speed = 2 * Math.PI
|
||||
readonly turn_speed = 1
|
||||
private _rotation_speed = 2 * Math.PI
|
||||
|
||||
@help('Aim turn speed in rotations per second')
|
||||
@export_(Variant.Type.TYPE_FLOAT)
|
||||
readonly aim_turn_speed = 2
|
||||
private _aim_rotation_speed = 2 * Math.PI * 2
|
||||
|
||||
is_moving() {
|
||||
return !this.velocity.is_zero_approx()
|
||||
|
@ -53,15 +54,15 @@ export default class Player extends CharacterBody3D {
|
|||
private _can_act: boolean = true
|
||||
private _wants_to_fire: boolean = false
|
||||
|
||||
// TODO: abstract this horrible shit away
|
||||
private _try_interact_callable!: Callable0
|
||||
private _queue_fire_callable!: Callable0
|
||||
private _disable_action_callable!: Callable1<string>
|
||||
private _enable_action_callable!: Callable1<string>
|
||||
|
||||
_ready(): void {
|
||||
this._camera = this.get_node(this.camera) as Camera3D
|
||||
|
||||
this._rotation_speed = this.turn_speed * 2 * Math.PI
|
||||
this._aim_rotation_speed = this.aim_turn_speed * 2 * Math.PI
|
||||
|
||||
this._try_interact_callable = Callable.create(
|
||||
this,
|
||||
|
@ -167,8 +168,14 @@ export default class Player extends CharacterBody3D {
|
|||
this.move_and_slide()
|
||||
}
|
||||
|
||||
private _aim_at_direction() {
|
||||
this._rotate_toward
|
||||
// TODO: combine this with _rotate_toward as a general
|
||||
// rotate_over_time_toward method
|
||||
// right now, both rotate instantly
|
||||
private _aim_toward(delta: float64) {
|
||||
// TODO: this performs a costly sqrt operation. necessary?
|
||||
const look = this.player_input.look_direction.project(this.global_position)
|
||||
look.y = this.global_position.y
|
||||
this.look_at(look, Vector3.UP, true)
|
||||
}
|
||||
|
||||
_physics_process(delta: float64): void {
|
||||
|
@ -180,7 +187,7 @@ export default class Player extends CharacterBody3D {
|
|||
|
||||
if (this.player_input.is_aiming) {
|
||||
this.velocity = Vector3.ZERO
|
||||
this._aim_at_direction()
|
||||
this._aim_toward(delta)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { float64, Input, InputEvent, InputEventJoypadButton, InputEventJoypadMotion, InputEventKey, InputEventMouse, InputEventMouseMotion, int32, Node3D, Signal0, Signal1, Variant, Vector2 } from 'godot'
|
||||
import { Callable, Callable1, Camera3D, float64, Input, InputEvent, InputEventJoypadButton, InputEventJoypadMotion, InputEventKey, InputEventMouse, InputEventMouseMotion, int32, Node3D, Signal0, Signal1, Variant, Vector2, Vector3 } from 'godot'
|
||||
import { export_, signal } from 'godot.annotations'
|
||||
import InputBuffer from './input_buffer'
|
||||
import MainCamera from './main_camera'
|
||||
import MessageBus from './message_bus'
|
||||
|
||||
export const PlayerMovement = Object.freeze({
|
||||
MoveLeft: 'move_left',
|
||||
|
@ -19,13 +21,37 @@ export const PlayerLook = Object.freeze({
|
|||
class LookDirection {
|
||||
static Empty = new LookDirection(Vector2.ZERO, false)
|
||||
|
||||
readonly value: Vector2
|
||||
readonly needs_projection: boolean
|
||||
_value: Vector2
|
||||
needs_projection: boolean
|
||||
camera?: Camera3D
|
||||
|
||||
get value() {
|
||||
return this._value
|
||||
}
|
||||
|
||||
set value(val: Vector2) {
|
||||
this._value = val
|
||||
}
|
||||
|
||||
constructor(value: Vector2, needs_projection: boolean) {
|
||||
this.value = value
|
||||
this._value = value
|
||||
this.needs_projection = needs_projection
|
||||
}
|
||||
|
||||
accumulate(delta: Vector2) {
|
||||
this.value = Vector2.ADD(this._value, delta)
|
||||
}
|
||||
|
||||
project(to_position: Vector3): Vector3 {
|
||||
if (this.camera) {
|
||||
// TODO: this performance a sqrt operation,
|
||||
// check if this is necessary
|
||||
const distance = this.camera.global_position.distance_to(to_position)
|
||||
return this.camera?.project_position(this._value, distance) ?? Vector3.ZERO
|
||||
} else {
|
||||
return Vector3.ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PlayerAction = Object.freeze({
|
||||
|
@ -112,6 +138,8 @@ export default class PlayerInput extends Node3D {
|
|||
return this._changed_since_last_frame
|
||||
}
|
||||
|
||||
private _camera!: Camera3D
|
||||
|
||||
private _running: boolean = false
|
||||
private _interacting: boolean = false
|
||||
private _aiming: boolean = false
|
||||
|
@ -181,7 +209,16 @@ export default class PlayerInput extends Node3D {
|
|||
return n * n
|
||||
}
|
||||
|
||||
private _await_camera_callable!: Callable1<Camera3D>
|
||||
|
||||
_ready(): void {
|
||||
this._camera = MainCamera.instance
|
||||
|
||||
this._await_camera_callable = Callable.create(this, this._await_camera)
|
||||
MessageBus.instance.active_camera_changed.connect(this._await_camera_callable)
|
||||
|
||||
this._look_direction.camera = this._camera
|
||||
|
||||
this._min_range_sqr = this._sqr(this.min_range)
|
||||
this._max_range_sqr = this._sqr(this.max_range)
|
||||
|
||||
|
@ -189,6 +226,12 @@ export default class PlayerInput extends Node3D {
|
|||
this._input_buffer = new InputBuffer(this.input_buffer_size)
|
||||
}
|
||||
|
||||
private _await_camera(camera: Camera3D) {
|
||||
console.log('got camera', camera)
|
||||
this._camera = camera
|
||||
this._look_direction.camera = camera
|
||||
}
|
||||
|
||||
_process(_delta: float64): void {
|
||||
const next_movement = Input.get_vector(
|
||||
PlayerMovement.MoveLeft,
|
||||
|
@ -207,11 +250,13 @@ export default class PlayerInput extends Node3D {
|
|||
PlayerLook.LookUp,
|
||||
PlayerLook.LookDown
|
||||
)
|
||||
this._look_direction = new LookDirection(dir, false)
|
||||
break
|
||||
|
||||
this._look_direction.value = dir
|
||||
this._look_direction.needs_projection = false
|
||||
case Device.KeyboardMouse:
|
||||
dir = this.get_viewport().get_mouse_position()
|
||||
this._look_direction = new LookDirection(dir, true)
|
||||
this._look_direction.value = dir
|
||||
this._look_direction.needs_projection = true
|
||||
break
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue