277 lines
7.7 KiB
Swift
277 lines
7.7 KiB
Swift
|
import SDL2
|
||
|
import simd
|
||
|
import OpenGL.GL
|
||
|
import JolkEngine
|
||
|
|
||
|
|
||
|
class Colin: Actor
|
||
|
{
|
||
|
var position: Vec3f { _pos }
|
||
|
|
||
|
var transform: Mat4f
|
||
|
{
|
||
|
//.rotate(yaw: angle.x, pitch: angle.y, roll: sin(time)) *
|
||
|
//.scale(Vec3f(1.0 + 0.25 * cos(time), 1.0 + 0.25 * sin(time), 1.0)) *
|
||
|
.rotate(yawPitch: angle) * .translate(-position - Vec3f(0, 1, 0))
|
||
|
}
|
||
|
|
||
|
var angle: Vec2f { return Vec2f(ofsAngle.x + _angle, ofsAngle.y) }
|
||
|
var fov: Float { return _fov }
|
||
|
|
||
|
private var time: Float = 0.0
|
||
|
//private var jumpVel: Float = 0.0
|
||
|
private var velocity: Vec3f = .zero
|
||
|
private var _pos: Vec3f = .zero
|
||
|
private var _pos2D: Vec2f { get { Vec2f(_pos.x, _pos.z) } set(new) { _pos.x = new.x; _pos.z = new.y } }
|
||
|
private var _angle: Float = 0.0
|
||
|
private var ofsAngle: Vec2f = .zero
|
||
|
private var _fov: Float = 60.0
|
||
|
|
||
|
private var nutted = false
|
||
|
private var colinMode = false
|
||
|
private var backPressed = false
|
||
|
|
||
|
private let colinWidth: Float = 0.2
|
||
|
|
||
|
private func move2D(new: Vec2f, edges: [Collision.Edge])
|
||
|
{
|
||
|
let velocity = new - _pos2D
|
||
|
var lastPos = _pos2D
|
||
|
_pos2D = new
|
||
|
|
||
|
var collided = -1
|
||
|
jolk: while (collided != 0)
|
||
|
{
|
||
|
let scabidabadoo = 10
|
||
|
for edge in edges
|
||
|
{
|
||
|
let diff = _pos2D - lastPos
|
||
|
if simd_dot(edge.n, diff) > 0 && simd_dot(edge.n, velocity) > 0 { continue }
|
||
|
|
||
|
let deltaPos = _pos2D - edge.p
|
||
|
let something = deltaPos.cross(edge.n)
|
||
|
if abs(something) * 2.0 < edge.w
|
||
|
{
|
||
|
let dot = simd_dot(edge.n, deltaPos)
|
||
|
if dot > 0 && dot < colinWidth
|
||
|
{
|
||
|
lastPos = _pos2D
|
||
|
_pos2D += edge.n * (colinWidth - dot)
|
||
|
if collided < 0 { collided = scabidabadoo };
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
let vec = (deltaPos - Vec2f(edge.n.y, -edge.n.x) * Float(signOf: something, magnitudeOf: edge.w * 0.5))
|
||
|
let distance2 = vec.len2
|
||
|
let epsilon: Float = 0.001
|
||
|
if distance2 < (colinWidth - epsilon) * (colinWidth - epsilon)
|
||
|
{
|
||
|
let distance = distance2.squareRoot()
|
||
|
lastPos = _pos2D
|
||
|
_pos2D += (vec / distance) * (colinWidth - epsilon - distance)
|
||
|
if collided < 0 { collided = scabidabadoo };
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
collided -= 1;
|
||
|
if collided <= 0 { break jolk }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private func response3D(plainPos o: Vec3f, plainNorm n: Vec3f)
|
||
|
{
|
||
|
let height: Float = 1.12
|
||
|
//let diff = _pos - lastPos
|
||
|
|
||
|
//let p = n.y > 1.0 ? _pos : (_pos + 2.0)
|
||
|
let ofs: Vec3f = n.y.sign == .plus ? .zero : .up * height
|
||
|
//let p = if n.y.sign == .plus { _pos } else { _pos + 1.0 }
|
||
|
let p = _pos + ofs
|
||
|
let a = p.dot(n) - o.dot(n)
|
||
|
|
||
|
if a > height * -0.5 && a < 0.0
|
||
|
{
|
||
|
_pos -= n * a
|
||
|
velocity -= velocity.project(n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private func move3D(_ deltaTime: Float, world: Collision)
|
||
|
{
|
||
|
var lastPos = _pos
|
||
|
_pos += velocity * deltaTime
|
||
|
|
||
|
for edge in world.edge3d
|
||
|
{
|
||
|
switch edge
|
||
|
{
|
||
|
case .aabbFloor(let normal, let origin, let width, let depth):
|
||
|
//let left = min(edge.v0.x, edge.v1.x, edge.v2.x)
|
||
|
//let right = max(edge.v0.x, edge.v1.x, edge.v2.x)
|
||
|
//let back = min(edge.v0.z, edge.v1.z, edge.v2.z)
|
||
|
//let forward = max(edge.v0.z, edge.v1.z, edge.v2.z)
|
||
|
|
||
|
let left = origin.x - width, right = origin.x + width
|
||
|
let back = origin.z - depth, forward = origin.z + depth
|
||
|
|
||
|
if _pos.x < left || _pos.x > right { continue }
|
||
|
if _pos.z < back || _pos.z > forward { continue }
|
||
|
|
||
|
response3D(plainPos: origin, plainNorm: normal)
|
||
|
|
||
|
case .triangle(let normal, let origin, let verts):
|
||
|
let p = (verts.1 - verts.0, verts.2 - verts.0, _pos - verts.0)
|
||
|
let invDenom = 1.0 / (p.0.x * p.1.z - p.1.x * p.0.z);
|
||
|
let v = invDenom * (p.2.x * p.1.z - p.1.x * p.2.z);
|
||
|
let w = invDenom * (p.0.x * p.2.z - p.2.x * p.0.z);
|
||
|
let x = 1.0 - v - w
|
||
|
//guard v >= 0.0 && w >= 0.0 && v + w <= 1.0 else { break }
|
||
|
guard v >= 0.0 && w >= 0.0 && 0 <= x && x <= 1.0 else { break }
|
||
|
response3D(plainPos: origin, plainNorm: normal)
|
||
|
|
||
|
case .quad(let verts, let winding):
|
||
|
let vn = (
|
||
|
(verts.1 - verts.0).cross(verts.3 - verts.0),
|
||
|
(verts.2 - verts.1).cross(verts.0 - verts.1),
|
||
|
(verts.3 - verts.2).cross(verts.1 - verts.2),
|
||
|
(verts.0 - verts.3).cross(verts.2 - verts.3)
|
||
|
)
|
||
|
|
||
|
let uv = Collision.quadSpaceFromCartesian(quad:
|
||
|
winding == .ccw ? (verts.3, verts.2, verts.1, verts.0) : (verts.0, verts.1, verts.2, verts.3)
|
||
|
, position: _pos)
|
||
|
if uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0
|
||
|
{
|
||
|
//var pp = p.0
|
||
|
//pp += (p.1 - p.0) * uv.x
|
||
|
//pp += (p.3 - p.0) * uv.y
|
||
|
//pp += (p.0 - p.1 + p.2 - p.3) * uv.x * uv.y
|
||
|
let p = verts.0.lerp(verts.1, uv.x).lerp(
|
||
|
verts.3.lerp(verts.2, uv.x), winding == .cw ? uv.y : 1.0 - uv.y)
|
||
|
let n = vn.0.lerp(vn.3, uv.x).lerp(
|
||
|
vn.2.lerp(vn.1, uv.x), winding == .cw ? uv.y : 1.0 - uv.y).normalised
|
||
|
|
||
|
response3D(plainPos: Vec3f(_pos.x, p.y, _pos.z), plainNorm: n)
|
||
|
}
|
||
|
/*
|
||
|
let p = (
|
||
|
verts.0 + (verts.1 - verts.0) * _pos.x,
|
||
|
verts.3 + (verts.2 - verts.3) * _pos.x,
|
||
|
verts.0 + (verts.3 - verts.0) * _pos.z,
|
||
|
verts.1 + (verts.2 - verts.1) * _pos.z)
|
||
|
|
||
|
let xdiff = Vec2f(p.0.x - p.1.x, p.2.x - p.3.x)
|
||
|
let ydiff = Vec2f(p.0.z - p.1.z, p.2.z - p.3.z)
|
||
|
let div = xdiff.cross(ydiff)
|
||
|
guard div != 0.0 else { break }
|
||
|
|
||
|
let d = Vec2f(
|
||
|
Vec2f(p.0.x, p.0.z).cross(Vec2f(p.1.x, p.1.z)),
|
||
|
Vec2f(p.2.x, p.2.z).cross(Vec2f(p.3.x, p.3.z)))
|
||
|
let pos = Vec2f(d.cross(xdiff), d.cross(ydiff)) / div
|
||
|
*/
|
||
|
default: break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func update(deltaTime: Float, world: Collision)
|
||
|
{
|
||
|
time += deltaTime
|
||
|
|
||
|
let axisRescale = 1.0 / Float(INT16_MAX)
|
||
|
let getAxis = { (axis: SDL_GameControllerAxis) in
|
||
|
Float(SDL_GameControllerGetAxis(sdlPad, axis)) * axisRescale }
|
||
|
let getButton = { (btn: SDL_GameControllerButton) in
|
||
|
SDL_GameControllerGetButton(sdlPad, btn) == SDL_PRESSED }
|
||
|
|
||
|
let stick = Vec2f(
|
||
|
getAxis(SDL_CONTROLLER_AXIS_LEFTX),
|
||
|
getAxis(SDL_CONTROLLER_AXIS_LEFTY))
|
||
|
.cardinalDeadzone(min: 0.1, max: 1)
|
||
|
|
||
|
let turnSpeed = Float.pi * 2 * 0.1
|
||
|
if Input.instance.keyDown(.left)
|
||
|
{
|
||
|
_angle -= turnSpeed * deltaTime
|
||
|
}
|
||
|
if Input.instance.keyDown(.right)
|
||
|
{
|
||
|
_angle += turnSpeed * deltaTime
|
||
|
}
|
||
|
if stick != .zero
|
||
|
{
|
||
|
_angle += stick.x * 2.0 * turnSpeed * deltaTime
|
||
|
}
|
||
|
|
||
|
var moveVec: Vec2f = .zero
|
||
|
|
||
|
let speed: Float = 2
|
||
|
let forward = Vec2f(sin(self._angle), -cos(self._angle))
|
||
|
if Input.instance.keyDown(.up)
|
||
|
{
|
||
|
moveVec += forward * speed
|
||
|
}
|
||
|
if Input.instance.keyDown(.down)
|
||
|
{
|
||
|
moveVec -= forward * speed
|
||
|
}
|
||
|
if stick != .zero
|
||
|
{
|
||
|
moveVec -= forward * stick.y * speed
|
||
|
}
|
||
|
|
||
|
if Input.instance.keyDown(.c)
|
||
|
{
|
||
|
colinMode = !colinMode
|
||
|
}
|
||
|
|
||
|
let lookCone = Float.pi / 2.0
|
||
|
let dst = Vec2f(
|
||
|
getAxis(SDL_CONTROLLER_AXIS_RIGHTX),
|
||
|
getAxis(SDL_CONTROLLER_AXIS_RIGHTY))
|
||
|
.radialDeadzone(min: 0.1, max: 1) * lookCone
|
||
|
ofsAngle = ofsAngle.lerp(dst, 16 * deltaTime)
|
||
|
|
||
|
let targetFov = Float.lerp(60, 20, getAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT))
|
||
|
_fov = Float.lerp(_fov, targetFov, 20 * deltaTime)
|
||
|
|
||
|
let right = Vec2f(cos(self._angle), sin(self._angle))
|
||
|
if getButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
|
||
|
{
|
||
|
moveVec -= right * speed
|
||
|
}
|
||
|
if getButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
|
||
|
{
|
||
|
moveVec += right * speed
|
||
|
}
|
||
|
|
||
|
let back = getButton(SDL_CONTROLLER_BUTTON_BACK)
|
||
|
if !backPressed && back { colinMode = !colinMode }
|
||
|
backPressed = back
|
||
|
|
||
|
if getButton(SDL_CONTROLLER_BUTTON_A) || Input.instance.keyDown(.n)
|
||
|
{
|
||
|
// play nut.wav
|
||
|
nutted = true
|
||
|
}
|
||
|
else { nutted = false }
|
||
|
|
||
|
//move2D(new: _pos2D + velocity, edges: edges)
|
||
|
|
||
|
if Input.instance.keyDown(.z) || getButton(SDL_CONTROLLER_BUTTON_B) { velocity.y = 2.0 }
|
||
|
//_pos.y += jumpVel * deltaTime
|
||
|
//if _pos.y > 0.0 { jumpVel -= 5.4 * deltaTime }
|
||
|
velocity.y -= 5.4 * deltaTime
|
||
|
velocity.x = moveVec.x
|
||
|
velocity.z = moveVec.y
|
||
|
move3D(deltaTime, world: world)
|
||
|
//else if _pos.y < 0.0
|
||
|
//{
|
||
|
// jumpVel = max(jumpVel, 0.0)
|
||
|
// _pos.y = 0.0
|
||
|
//}
|
||
|
}
|
||
|
}
|