crude player physics & collision response

This commit is contained in:
2024-08-16 00:27:35 +10:00
parent 60ced3691d
commit 6b92b538a5
6 changed files with 206 additions and 34 deletions

View File

@ -1,36 +1,122 @@
import simd
struct Player {
static let height: Float = 1.8
static let radius: Float = 0.4
static let bounds = AABB(
from: .init(-Self.radius, 0, -Self.radius),
to: .init(Self.radius, Self.height, Self.radius))
static let eyeLevel: Float = 1.4
static let epsilon = Float.ulpOfOne * 10
static let speedCoeff: Float = 720
static let gravityCoeff: Float = 12
static let jumpVelocity: Float = 9
private var _position = SIMD3<Float>.zero
private var _velocity = SIMD3<Float>.zero
private var _rotation = SIMD2<Float>.zero
public var position: SIMD3<Float> { self._position }
private var _onGround: Bool = false
public var position: SIMD3<Float> { self._position + .init(0, Self.eyeLevel, 0) }
public var rotation: SIMD2<Float> { self._rotation }
mutating func update(deltaTime: Float) {
mutating func update(deltaTime: Float, boxes: [Box]) {
if let pad = GameController.current?.state {
// Turning input
let turning = pad.rightStick.radialDeadzone(min: 0.1, max: 1)
_rotation += turning * deltaTime * 3.0
if _rotation.x < 0.0 {
_rotation.x += .pi * 2
if self._rotation.x < 0.0 {
self._rotation.x += .pi * 2
} else if _rotation.x > .pi * 2 {
_rotation.x -= .pi * 2
self._rotation.x -= .pi * 2
}
_rotation.y = _rotation.y.clamp(-.pi * 0.5, .pi * 0.5)
self._rotation.y = self._rotation.y.clamp(-.pi * 0.5, .pi * 0.5)
let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
if self._onGround {
// Movement on ground
let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
let rotc = cos(self._rotation.x), rots = sin(self._rotation.x)
self._velocity.x += (movement.x * rotc - movement.y * rots) * Self.speedCoeff * deltaTime
self._velocity.z += (movement.y * rotc + movement.x * rots) * Self.speedCoeff * deltaTime
let rotc = cos(_rotation.x), rots = sin(_rotation.x)
_position += .init(
movement.x * rotc - movement.y * rots,
0,
movement.y * rotc + movement.x * rots
) * deltaTime * 3.0
// Jumping
if pad.pressed(.east) {
self._velocity.y = Self.jumpVelocity
self._onGround = false
}
}
// Flying
self._velocity.y += pad.rightTrigger * 36 * deltaTime
// Reset
if pad.pressed(.back) {
_position = .zero
_rotation = .zero
self._position = .zero
self._velocity = .zero
self._rotation = .zero
self._onGround = false
}
}
// Apply gravity
self._velocity.y -= Self.gravityCoeff * deltaTime
// Move & handle collision
let checkCollision = { (position: SIMD3<Float>) -> Optional<AABB> in
for box in boxes {
let bounds = Self.bounds + position
if bounds.touching(box.geometry) {
return box.geometry
}
}
return nil
}
self._position.x += _velocity.x * deltaTime
if let aabb = checkCollision(self._position) {
if _velocity.x < 0 {
self._position.x = aabb.right + Self.radius + Self.epsilon
printErr("-x")
} else {
self._position.x = aabb.left - Self.radius - Self.epsilon
printErr("+x")
}
self._velocity.x = 0
}
self._position.z += _velocity.z * deltaTime
if let aabb = checkCollision(self._position) {
if _velocity.z < 0 {
self._position.z = aabb.near + Self.radius + Self.epsilon
printErr("-x")
} else {
self._position.z = aabb.far - Self.radius - Self.epsilon
printErr("+x")
}
self._velocity.z = 0
}
self._position.y += _velocity.y * deltaTime
if let aabb = checkCollision(self._position) {
if _velocity.y < 0 {
self._position.y = aabb.top + Self.epsilon
if !self._onGround { printErr("-y") }
self._onGround = true
} else {
self._position.y = aabb.bottom - Self.height - Self.epsilon
self._onGround = false
printErr("+y")
}
self._velocity.y = 0
} else {
self._onGround = false
}
// Ground friction
if self._onGround {
self._velocity.x *= 25 * deltaTime
self._velocity.z *= 25 * deltaTime
}
}
}