refactor: move world concepts into engine
This commit is contained in:
parent
eeedcb8e48
commit
2d15c7ab8d
52 changed files with 3298 additions and 1558 deletions
89
engine/world/CharacterController.ts
Normal file
89
engine/world/CharacterController.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import type { Vec3 } from "../math/Vec3"
|
||||
import { CollisionWorld, type CollisionWorld as World } from "./CollisionWorld"
|
||||
|
||||
export type Character = {
|
||||
position: Vec3
|
||||
yaw: number
|
||||
velocityY: number
|
||||
onGround: boolean
|
||||
}
|
||||
|
||||
export type CharacterInput = {
|
||||
forward: number
|
||||
right: number
|
||||
jump: boolean
|
||||
run: boolean
|
||||
}
|
||||
|
||||
export type CharacterConfig = {
|
||||
radius: number
|
||||
speed: number
|
||||
runMultiplier: number
|
||||
gravity: number
|
||||
jumpSpeed: number
|
||||
eyeHeight: number
|
||||
}
|
||||
|
||||
export namespace CharacterController {
|
||||
export function update(
|
||||
character: Character,
|
||||
input: CharacterInput,
|
||||
dt: number,
|
||||
world: World,
|
||||
config: CharacterConfig,
|
||||
): void {
|
||||
if (input.jump && character.onGround) {
|
||||
character.velocityY = config.jumpSpeed
|
||||
character.onGround = false
|
||||
}
|
||||
const steps = moveSubsteps(input, dt, config)
|
||||
for (let i = 0; i < steps; i++) {
|
||||
moveHorizontal(character, input, dt / steps, config)
|
||||
CollisionWorld.pushOut(world, character.position, config.radius)
|
||||
}
|
||||
character.velocityY -= config.gravity * dt
|
||||
character.position.y += character.velocityY * dt
|
||||
const ground = CollisionWorld.groundHeight(world, character.position)
|
||||
if (character.position.y <= ground) {
|
||||
character.position.y = ground
|
||||
character.velocityY = 0
|
||||
character.onGround = true
|
||||
} else {
|
||||
character.onGround = false
|
||||
}
|
||||
}
|
||||
|
||||
function moveSubsteps(
|
||||
input: CharacterInput,
|
||||
dt: number,
|
||||
config: CharacterConfig,
|
||||
): number {
|
||||
const distance =
|
||||
config.speed *
|
||||
runFactor(input, config) *
|
||||
dt *
|
||||
Math.hypot(input.forward, input.right)
|
||||
return Math.max(1, Math.ceil(distance / config.radius))
|
||||
}
|
||||
|
||||
function moveHorizontal(
|
||||
character: Character,
|
||||
input: CharacterInput,
|
||||
dt: number,
|
||||
config: CharacterConfig,
|
||||
): void {
|
||||
const speed = config.speed * runFactor(input, config) * dt
|
||||
const forwardX = Math.sin(character.yaw)
|
||||
const forwardZ = -Math.cos(character.yaw)
|
||||
const rightX = Math.cos(character.yaw)
|
||||
const rightZ = Math.sin(character.yaw)
|
||||
character.position.x +=
|
||||
(forwardX * input.forward + rightX * input.right) * speed
|
||||
character.position.z +=
|
||||
(forwardZ * input.forward + rightZ * input.right) * speed
|
||||
}
|
||||
|
||||
function runFactor(input: CharacterInput, config: CharacterConfig): number {
|
||||
return input.run ? config.runMultiplier : 1
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue