mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 02:59:37 +00:00 
			
		
		
		
	player physics overhaul
This commit is contained in:
		@ -8,3 +8,16 @@ public extension FloatingPoint {
 | 
			
		||||
  @inline(__always) func clamp(_ a: Self, _ b: Self) -> Self { min(max(self, a), b) }
 | 
			
		||||
  @inline(__always) var saturated: Self { self.clamp(0, 1) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension SIMD3 where Scalar: FloatingPoint {
 | 
			
		||||
  @inline(__always) static var X: Self      { Self(1, 0, 0) }
 | 
			
		||||
  @inline(__always) static var Y: Self      { Self(0, 1, 0) }
 | 
			
		||||
  @inline(__always) static var Z: Self      { Self(0, 0, 1) }
 | 
			
		||||
 | 
			
		||||
  @inline(__always) static var up: Self      {  Y }
 | 
			
		||||
  @inline(__always) static var down: Self    { -Y }
 | 
			
		||||
  @inline(__always) static var left: Self    { -X }
 | 
			
		||||
  @inline(__always) static var right: Self   {  X }
 | 
			
		||||
  @inline(__always) static var forward: Self { -Z }
 | 
			
		||||
  @inline(__always) static var back: Self    {  Z }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -70,8 +70,9 @@ class Game: GameDelegate {
 | 
			
		||||
    let deltaTime = min(Float(time.delta.asFloat), 1.0 / 15)
 | 
			
		||||
 | 
			
		||||
    if let pad = GameController.current?.state {
 | 
			
		||||
      // Delete block underneath player
 | 
			
		||||
      if pad.pressed(.south) {
 | 
			
		||||
        chunk.setBlockInternally(at: SIMD3(player.position - SIMD3(0, 2, 0)), type: .air)
 | 
			
		||||
        chunk.setBlockInternally(at: SIMD3(player.position + .down * 0.2), type: .air)
 | 
			
		||||
      }
 | 
			
		||||
      // Player reset
 | 
			
		||||
      if pad.pressed(.back) {
 | 
			
		||||
@ -95,9 +96,7 @@ class Game: GameDelegate {
 | 
			
		||||
 | 
			
		||||
    player.update(deltaTime: deltaTime, boxes: boxes)
 | 
			
		||||
    camera.position = player.eyePosition
 | 
			
		||||
    camera.rotation =
 | 
			
		||||
      simd_quatf(angle: player.rotation.y, axis: .init(1, 0, 0)) *
 | 
			
		||||
      simd_quatf(angle: player.rotation.x, axis: .init(0, 1, 0))
 | 
			
		||||
    camera.rotation = player.eyeRotation
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func draw(_ renderer: Renderer, _ time: GameTime) {
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import simd
 | 
			
		||||
 | 
			
		||||
struct Player {
 | 
			
		||||
  static let height: Float = 1.8
 | 
			
		||||
  static let radius: Float = 0.4
 | 
			
		||||
  static let radius: Float = 0.22
 | 
			
		||||
  static let bounds = AABB(
 | 
			
		||||
    from: .init(-Self.radius, 0, -Self.radius),
 | 
			
		||||
    to: .init(Self.radius, Self.height, Self.radius))
 | 
			
		||||
@ -10,9 +10,12 @@ struct Player {
 | 
			
		||||
  static let eyeLevel: Float = 1.4
 | 
			
		||||
  static let epsilon = Float.ulpOfOne * 10
 | 
			
		||||
 | 
			
		||||
  static let accelerationCoeff: Float = 7.5
 | 
			
		||||
  static let gravityCoeff: Float = 12
 | 
			
		||||
  static let jumpVelocity: Float = 9
 | 
			
		||||
  static let accelerationCoeff: Float = 75
 | 
			
		||||
  static let airAccelCoeff: Float = 3
 | 
			
		||||
  static let gravityCoeff: Float = 20
 | 
			
		||||
  static let frictionCoeff: Float = 22
 | 
			
		||||
  static let jumpVelocity: Float = 7
 | 
			
		||||
  static let maxVelocity: Float = 160
 | 
			
		||||
 | 
			
		||||
  private var _position = SIMD3<Float>.zero
 | 
			
		||||
  private var _velocity = SIMD3<Float>.zero
 | 
			
		||||
@ -24,11 +27,14 @@ struct Player {
 | 
			
		||||
  public var velocity: SIMD3<Float> { get { self._velocity } set { self._velocity = newValue } }
 | 
			
		||||
  public var rotation: SIMD2<Float> { get { self._rotation } set { self._rotation = newValue } }
 | 
			
		||||
 | 
			
		||||
  public var eyePosition: SIMD3<Float> { self._position + .init(0, Self.eyeLevel, 0) }
 | 
			
		||||
  public var eyePosition: SIMD3<Float> { self._position + .up * Self.eyeLevel }
 | 
			
		||||
  public var eyeRotation: simd_quatf {
 | 
			
		||||
    .init(angle: self._rotation.y, axis: .right) *
 | 
			
		||||
    .init(angle: self._rotation.x, axis: .up)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
@ -39,25 +45,21 @@ struct Player {
 | 
			
		||||
      }
 | 
			
		||||
      self._rotation.y = self._rotation.y.clamp(-.pi * 0.5, .pi * 0.5)
 | 
			
		||||
 | 
			
		||||
      // Movement (slower in air than on ground)
 | 
			
		||||
      let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
 | 
			
		||||
      let rotc = cos(self._rotation.x), rots = sin(self._rotation.x)
 | 
			
		||||
      let movementScale: Float = self._onGround ? 1.0 : 0.4
 | 
			
		||||
      self._velocity.x = (
 | 
			
		||||
        movement.x * rotc - movement.y * rots
 | 
			
		||||
      ) * Self.accelerationCoeff * movementScale
 | 
			
		||||
      self._velocity.z = (
 | 
			
		||||
        movement.y * rotc + movement.x * rots
 | 
			
		||||
      ) * Self.accelerationCoeff * movementScale
 | 
			
		||||
 | 
			
		||||
      // Jumping
 | 
			
		||||
      if self._onGround {
 | 
			
		||||
        // Jumping
 | 
			
		||||
        if pad.pressed(.east) {
 | 
			
		||||
          self._velocity.y = Self.jumpVelocity
 | 
			
		||||
          self._onGround = false
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Movement (slower in air than on ground)
 | 
			
		||||
      let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
 | 
			
		||||
      let rotc = cos(self._rotation.x), rots = sin(self._rotation.x)
 | 
			
		||||
      let coeff = self._onGround ? Self.accelerationCoeff : Self.airAccelCoeff
 | 
			
		||||
      self._velocity.x += (movement.x * rotc - movement.y * rots) * coeff * deltaTime
 | 
			
		||||
      self._velocity.z += (movement.y * rotc + movement.x * rots) * coeff * deltaTime
 | 
			
		||||
 | 
			
		||||
      // Flying and unflying
 | 
			
		||||
      self._velocity.y += (pad.rightTrigger - pad.leftTrigger) * 36 * deltaTime
 | 
			
		||||
    }
 | 
			
		||||
@ -75,27 +77,27 @@ struct Player {
 | 
			
		||||
      }
 | 
			
		||||
      return nil
 | 
			
		||||
    }
 | 
			
		||||
    self._position.x += _velocity.x * deltaTime
 | 
			
		||||
    self._position.x += self._velocity.x * deltaTime
 | 
			
		||||
    if let aabb = checkCollision(self._position) {
 | 
			
		||||
      if _velocity.x < 0 {
 | 
			
		||||
      if self._velocity.x < 0 {
 | 
			
		||||
        self._position.x = aabb.right + Self.radius + Self.epsilon
 | 
			
		||||
      } else {
 | 
			
		||||
        self._position.x = aabb.left - Self.radius - Self.epsilon
 | 
			
		||||
      }
 | 
			
		||||
      self._velocity.x = 0
 | 
			
		||||
    }
 | 
			
		||||
    self._position.z += _velocity.z * deltaTime
 | 
			
		||||
    self._position.z += self._velocity.z * deltaTime
 | 
			
		||||
    if let aabb = checkCollision(self._position) {
 | 
			
		||||
      if _velocity.z < 0 {
 | 
			
		||||
      if self._velocity.z < 0 {
 | 
			
		||||
        self._position.z = aabb.near + Self.radius + Self.epsilon
 | 
			
		||||
      } else {
 | 
			
		||||
        self._position.z = aabb.far - Self.radius - Self.epsilon
 | 
			
		||||
      }
 | 
			
		||||
      self._velocity.z = 0
 | 
			
		||||
    }
 | 
			
		||||
    self._position.y += _velocity.y * deltaTime
 | 
			
		||||
    if let aabb = checkCollision(self._position) {
 | 
			
		||||
      if _velocity.y < 0 {
 | 
			
		||||
    self._position.y += self._velocity.y * deltaTime
 | 
			
		||||
    if let aabb = checkCollision(self._velocity.y > 0 ? self._position + .down * Self.epsilon : self.position) {
 | 
			
		||||
      if self._velocity.y < 0 {
 | 
			
		||||
        self._position.y = aabb.top + Self.epsilon
 | 
			
		||||
        self._onGround = true
 | 
			
		||||
      } else {
 | 
			
		||||
@ -109,20 +111,14 @@ struct Player {
 | 
			
		||||
 | 
			
		||||
    // Ground friction
 | 
			
		||||
    if self._onGround {
 | 
			
		||||
      self._velocity.x = 0
 | 
			
		||||
      self._velocity.z = 0
 | 
			
		||||
      self._velocity.x /= 1.0 + Self.frictionCoeff * deltaTime
 | 
			
		||||
      self._velocity.z /= 1.0 + Self.frictionCoeff * deltaTime
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if self._velocity.x > 10 {
 | 
			
		||||
      self._velocity.x = 10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if self._velocity.y > 10 {
 | 
			
		||||
      self._velocity.y = 10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if abs(self._velocity.y) > 40 {
 | 
			
		||||
      self._velocity.y = Float(signOf: self._velocity.y, magnitudeOf: 40.0)
 | 
			
		||||
    // Limit maximum velocity
 | 
			
		||||
    let velocityLen = simd_length(self._velocity)
 | 
			
		||||
    if velocityLen > Self.maxVelocity {
 | 
			
		||||
      self._velocity = self._velocity / velocityLen * Self.maxVelocity
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user