mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 10:59:39 +00:00 
			
		
		
		
	rotating flip flags
This commit is contained in:
		@ -1,6 +1,15 @@
 | 
				
			|||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public struct Extent<T: AdditiveArithmetic & Hashable>: Hashable {
 | 
					public struct Extent<T: AdditiveArithmetic & Hashable>: Hashable {
 | 
				
			||||||
  public var left: T, top: T, right: T, bottom: T
 | 
					  public var left: T, top: T, right: T, bottom: T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(left: T, top: T, right: T, bottom: T) {
 | 
				
			||||||
 | 
					    self.left   = left
 | 
				
			||||||
 | 
					    self.top    = top
 | 
				
			||||||
 | 
					    self.right  = right
 | 
				
			||||||
 | 
					    self.bottom = bottom
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @inline(__always) public var topLeft: Point<T> { .init(left, top) }
 | 
					  @inline(__always) public var topLeft: Point<T> { .init(left, top) }
 | 
				
			||||||
  @inline(__always) public var topRight: Point<T> { .init(right, top) }
 | 
					  @inline(__always) public var topRight: Point<T> { .init(right, top) }
 | 
				
			||||||
  @inline(__always) public var bottomLeft: Point<T> { .init(left, bottom) }
 | 
					  @inline(__always) public var bottomLeft: Point<T> { .init(left, bottom) }
 | 
				
			||||||
@ -24,6 +33,14 @@ public extension Extent where T: SIMDScalar {
 | 
				
			|||||||
    self.right  = to.x
 | 
					    self.right  = to.x
 | 
				
			||||||
    self.bottom = to.y
 | 
					    self.bottom = to.y
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @inline(__always) static func + (lhs: Self, rhs: SIMD2<T>) -> Self {
 | 
				
			||||||
 | 
					    .init(
 | 
				
			||||||
 | 
					      left:   lhs.left + rhs.x,
 | 
				
			||||||
 | 
					      top:    lhs.top + rhs.y,
 | 
				
			||||||
 | 
					      right:  lhs.right + rhs.x,
 | 
				
			||||||
 | 
					      bottom: lhs.bottom + rhs.y)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public extension Extent where T: AdditiveArithmetic {
 | 
					public extension Extent where T: AdditiveArithmetic {
 | 
				
			||||||
@ -44,3 +61,52 @@ public extension Extent where T: Numeric {
 | 
				
			|||||||
      bottom: lhs.bottom * rhs.h)
 | 
					      bottom: lhs.bottom * rhs.h)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public extension Extent where T: BinaryInteger {
 | 
				
			||||||
 | 
					  init<O: BinaryInteger>(_ other: Extent<O>) {
 | 
				
			||||||
 | 
					    self.left   = T(other.left)
 | 
				
			||||||
 | 
					    self.top    = T(other.top)
 | 
				
			||||||
 | 
					    self.right  = T(other.right)
 | 
				
			||||||
 | 
					    self.bottom = T(other.bottom)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  init<O: BinaryFloatingPoint>(_ other: Extent<O>) {
 | 
				
			||||||
 | 
					    self.left   = T(other.left)
 | 
				
			||||||
 | 
					    self.top    = T(other.top)
 | 
				
			||||||
 | 
					    self.right  = T(other.right)
 | 
				
			||||||
 | 
					    self.bottom = T(other.bottom)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public extension Extent where T: FloatingPoint {
 | 
				
			||||||
 | 
					  init<O: BinaryInteger>(_ other: Extent<O>) {
 | 
				
			||||||
 | 
					    self.left   = T(other.left)
 | 
				
			||||||
 | 
					    self.top    = T(other.top)
 | 
				
			||||||
 | 
					    self.right  = T(other.right)
 | 
				
			||||||
 | 
					    self.bottom = T(other.bottom)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @inline(__always) static func / (lhs: Self, rhs: T) -> Self {
 | 
				
			||||||
 | 
					    .init(
 | 
				
			||||||
 | 
					      left:   lhs.left / rhs,
 | 
				
			||||||
 | 
					      top:    lhs.top / rhs,
 | 
				
			||||||
 | 
					      right:  lhs.right / rhs,
 | 
				
			||||||
 | 
					      bottom: lhs.bottom / rhs)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public extension Extent where T: BinaryFloatingPoint {
 | 
				
			||||||
 | 
					  init<O: BinaryFloatingPoint>(_ other: Extent<O>) {
 | 
				
			||||||
 | 
					    self.left   = T(other.left)
 | 
				
			||||||
 | 
					    self.top    = T(other.top)
 | 
				
			||||||
 | 
					    self.right  = T(other.right)
 | 
				
			||||||
 | 
					    self.bottom = T(other.bottom)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inlinable public func floor<T: FloatingPoint>(_ extent: Extent<T>) -> Extent<T> {
 | 
				
			||||||
 | 
					  .init(
 | 
				
			||||||
 | 
					    left:   floor(extent.left),
 | 
				
			||||||
 | 
					    top:    floor(extent.top),
 | 
				
			||||||
 | 
					    right:  floor(extent.right),
 | 
				
			||||||
 | 
					    bottom: floor(extent.bottom))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,8 @@ public struct Sprite {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static let none: Self = Self(rawValue: 0)
 | 
					    public static let none: Self = Self(rawValue: 0)
 | 
				
			||||||
    public static let x: Self    = Self(rawValue: 1 << 0)
 | 
					    public static let horz: Self = Self(rawValue: 1 << 0)
 | 
				
			||||||
    public static let y: Self    = Self(rawValue: 1 << 1)
 | 
					    public static let vert: Self = Self(rawValue: 1 << 1)
 | 
				
			||||||
    public static let diag: Self = Self(rawValue: 1 << 2)
 | 
					    public static let diag: Self = Self(rawValue: 1 << 2)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,3 +21,15 @@ public struct Sprite {
 | 
				
			|||||||
  var flip: Flip
 | 
					  var flip: Flip
 | 
				
			||||||
  var color: Color<Float>
 | 
					  var color: Color<Float>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public extension Sprite.Flip {
 | 
				
			||||||
 | 
					  var clockwise: Self {
 | 
				
			||||||
 | 
					    [Self](arrayLiteral: [ .vert, .diag ], [ .horz, .vert, .diag ], .diag,
 | 
				
			||||||
 | 
					      [ .horz, .diag ], .horz, .none, [ .horz, .vert ], .vert)[Int(self.rawValue)]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var counterClockwise: Self {
 | 
				
			||||||
 | 
					    [Self](arrayLiteral: [ .horz, .diag ], .diag, [ .horz, .vert, .diag ],
 | 
				
			||||||
 | 
					      [ .vert, .diag ], .vert, [ .horz, .vert ], .none, .horz)[Int(self.rawValue)]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -64,7 +64,7 @@ public struct SpriteBatch {
 | 
				
			|||||||
      let bias = origin / SIMD2(size)
 | 
					      let bias = origin / SIMD2(size)
 | 
				
			||||||
      self.drawQuad(texture, .positions(position, size * scale, angle, bias), texCoord, color: color)
 | 
					      self.drawQuad(texture, .positions(position, size * scale, angle, bias), texCoord, color: color)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      self.drawQuad(texture, .positions(position - origin, size * scale), texCoord, color: color)
 | 
					      self.drawQuad(texture, .positions(position - origin * scale, size * scale), texCoord, color: color)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,7 +83,7 @@ public struct SpriteBatch {
 | 
				
			|||||||
      let bias = SIMD2(origin) / SIMD2(size)
 | 
					      let bias = SIMD2(origin) / SIMD2(size)
 | 
				
			||||||
      self.drawQuad(texture, .positions(position, size * scale, angle, bias), texCoord, color: color)
 | 
					      self.drawQuad(texture, .positions(position, size * scale, angle, bias), texCoord, color: color)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      self.drawQuad(texture, .positions(position, size * scale), texCoord, color: color)
 | 
					      self.drawQuad(texture, .positions(position - origin * scale, size * scale), texCoord, color: color)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -345,12 +345,11 @@ fileprivate extension SpriteBatch.Quad {
 | 
				
			|||||||
    v10: SIMD2<Float>(0, 0), v11: SIMD2<Float>(1, 0))
 | 
					    v10: SIMD2<Float>(0, 0), v11: SIMD2<Float>(1, 0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static func texcoords(_ flip: Sprite.Flip) -> Self {
 | 
					  static func texcoords(_ flip: Sprite.Flip) -> Self {
 | 
				
			||||||
    let flipX = flip.contains(.x), flipY = flip.contains(.y)
 | 
					    let flipX = flip.contains(.horz), flipY = flip.contains(.vert), flipD = flip.contains(.diag)
 | 
				
			||||||
    //TODO: diag
 | 
					 | 
				
			||||||
    return .init(
 | 
					    return .init(
 | 
				
			||||||
      v00: .init(flipX ? 1 : 0, flipY ? 0 : 1),
 | 
					      v00: .init(flipX ? 1 : 0, flipY ? 0 : 1),
 | 
				
			||||||
      v01: .init(flipX ? 0 : 1, flipY ? 0 : 1),
 | 
					      v01: flipD ? .init(flipX ? 1 : 0, flipY ? 1 : 0) : .init(flipX ? 0 : 1, flipY ? 0 : 1),
 | 
				
			||||||
      v10: .init(flipX ? 1 : 0, flipY ? 1 : 0),
 | 
					      v10: flipD ? .init(flipX ? 0 : 1, flipY ? 0 : 1) : .init(flipX ? 1 : 0, flipY ? 1 : 0),
 | 
				
			||||||
      v11: .init(flipX ? 0 : 1, flipY ? 1 : 0))
 | 
					      v11: .init(flipX ? 0 : 1, flipY ? 1 : 0))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -363,14 +362,17 @@ fileprivate extension SpriteBatch.Quad {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static func texcoords(_ texSize: Size<Int>, _ source: Rect<Float>, _ flip: Sprite.Flip) -> Self {
 | 
					  static func texcoords(_ texSize: Size<Int>, _ source: Rect<Float>, _ flip: Sprite.Flip) -> Self {
 | 
				
			||||||
    let flipX = flip.contains(.x), flipY = flip.contains(.y)
 | 
					    let flipX = flip.contains(.horz), flipY = flip.contains(.vert), flipD = flip.contains(.diag)
 | 
				
			||||||
    let invSize = 1 / Size<Float>(texSize)
 | 
					    let invSize = 1 / Size<Float>(texSize)
 | 
				
			||||||
    let st = Extent(source) * invSize
 | 
					    let st = Extent(source) * invSize
 | 
				
			||||||
    //TODO: diag
 | 
					 | 
				
			||||||
    return .init(
 | 
					    return .init(
 | 
				
			||||||
      v00: .init(flipX ? st.right : st.left, flipY ? st.bottom : st.top),
 | 
					      v00: .init(flipX ? st.right : st.left, flipY ? st.bottom : st.top),
 | 
				
			||||||
      v01: .init(flipX ? st.left : st.right, flipY ? st.bottom : st.top),
 | 
					      v01: flipD
 | 
				
			||||||
      v10: .init(flipX ? st.right : st.left, flipY ? st.top : st.bottom),
 | 
					        ?  .init(flipX ? st.right : st.left, flipY ? st.top : st.bottom)
 | 
				
			||||||
 | 
					        :  .init(flipX ? st.left : st.right, flipY ? st.bottom : st.top),
 | 
				
			||||||
 | 
					      v10: flipD
 | 
				
			||||||
 | 
					        ?  .init(flipX ? st.left : st.right, flipY ? st.bottom : st.top)
 | 
				
			||||||
 | 
					        :  .init(flipX ? st.right : st.left, flipY ? st.top : st.bottom),
 | 
				
			||||||
      v11: .init(flipX ? st.left : st.right, flipY ? st.top : st.bottom))
 | 
					      v11: .init(flipX ? st.left : st.right, flipY ? st.top : st.bottom))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,18 +6,7 @@ internal class SpriteTestGame: GameDelegate {
 | 
				
			|||||||
  private var player = TestPlayer(position: .one * 10)
 | 
					  private var player = TestPlayer(position: .one * 10)
 | 
				
			||||||
  private var texture: RendererTexture2D!
 | 
					  private var texture: RendererTexture2D!
 | 
				
			||||||
  private var wireShark: RendererTexture2D!
 | 
					  private var wireShark: RendererTexture2D!
 | 
				
			||||||
 | 
					  private var level = TestLevel()
 | 
				
			||||||
  private static let levelWidth = 40, levelHeight = 23
 | 
					 | 
				
			||||||
  private var level: [UInt8]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  init() {
 | 
					 | 
				
			||||||
    self.level = .init(repeating: 0, count: Self.levelWidth * Self.levelHeight)
 | 
					 | 
				
			||||||
    for i in 0..<Self.levelWidth { self.level[i + (Self.levelHeight - 1) * Self.levelWidth] = 1 }
 | 
					 | 
				
			||||||
    for i in 0..<Self.levelWidth { self.level[i + (Self.levelHeight - 2) * Self.levelWidth] = 1 }
 | 
					 | 
				
			||||||
    for i in 17...20 { self.level[10 + (i) * Self.levelWidth] = 1 }
 | 
					 | 
				
			||||||
    for i in 17...20 { self.level[14 + (i) * Self.levelWidth] = 1 }
 | 
					 | 
				
			||||||
    for i in 11...13 { self.level[i + (17) * Self.levelWidth] = 1 }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func create(_ renderer: Renderer) {
 | 
					  func create(_ renderer: Renderer) {
 | 
				
			||||||
    self.spriteBatch = renderer.createSpriteBatch()
 | 
					    self.spriteBatch = renderer.createSpriteBatch()
 | 
				
			||||||
@ -29,10 +18,38 @@ internal class SpriteTestGame: GameDelegate {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func update(_ time: GameTime) {
 | 
					  func update(_ time: GameTime) {
 | 
				
			||||||
 | 
					    let dt = Float(time.delta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.player.velocity.x = 0
 | 
				
			||||||
    if let pad = GameController.current?.state {
 | 
					    if let pad = GameController.current?.state {
 | 
				
			||||||
      self.player.position += pad.leftStick.radialDeadzone(min: 0.1, max: 1) * 1000 * Float(time.delta)
 | 
					      self.player.velocity.x = pad.leftStick.x.axisDeadzone(0.1, 0.8) * 660
 | 
				
			||||||
 | 
					      if pad.pressed(.start) {
 | 
				
			||||||
 | 
					        self.player.position = .one * 10
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    self.player.rotate += Float(time.delta)
 | 
					      if pad.pressed(.east) && player.onGround {
 | 
				
			||||||
 | 
					        self.player.velocity.y = -1000
 | 
				
			||||||
 | 
					      } else if pad.released(.east) && self.player.velocity.y < -550 {
 | 
				
			||||||
 | 
					        self.player.velocity.y = -550
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if Keyboard.down(.left) {
 | 
				
			||||||
 | 
					      self.player.velocity.x = -660
 | 
				
			||||||
 | 
					    } else if Keyboard.down(.right) {
 | 
				
			||||||
 | 
					      self.player.velocity.x = 660
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if Keyboard.pressed(.up) && player.onGround {
 | 
				
			||||||
 | 
					      self.player.velocity.y = -1000
 | 
				
			||||||
 | 
					    } else if Keyboard.released(.up) && self.player.velocity.y < -550 {
 | 
				
			||||||
 | 
					      self.player.velocity.y = -550
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if Mouse.down(.left) {
 | 
				
			||||||
 | 
					      self.level.set(SIMD2(Mouse.position / TestLevel.cellScale, rounding: .down), true)
 | 
				
			||||||
 | 
					    } else if Mouse.down(.right) {
 | 
				
			||||||
 | 
					      self.level.set(SIMD2(Mouse.position / TestLevel.cellScale, rounding: .down), false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.player.update(deltaTime: dt, level: self.level)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func draw(_ renderer: Renderer, _ time: GameTime) {
 | 
					  func draw(_ renderer: Renderer, _ time: GameTime) {
 | 
				
			||||||
@ -41,27 +58,28 @@ internal class SpriteTestGame: GameDelegate {
 | 
				
			|||||||
    // Draw background
 | 
					    // Draw background
 | 
				
			||||||
    self.spriteBatch.draw(self.texture,
 | 
					    self.spriteBatch.draw(self.texture,
 | 
				
			||||||
      source: .init(
 | 
					      source: .init(
 | 
				
			||||||
        origin: .init(scalar: fmod(player.rotate, 32)),
 | 
					        origin: .init(scalar: fmod(Float(time.total), 32)),
 | 
				
			||||||
        size:   (spriteBatch.viewport?.size ?? Size<Float>(renderer.frame.size)) * 0.01),
 | 
					        size:   (spriteBatch.viewport?.size ?? Size<Float>(renderer.frame.size)) * 0.01),
 | 
				
			||||||
      destination: nil,
 | 
					      destination: nil,
 | 
				
			||||||
      angle: sin(player.rotate) * .pi * 0.1, center: nil,
 | 
					 | 
				
			||||||
      color: .init(renderer.clearColor).setAlpha(0.7))
 | 
					      color: .init(renderer.clearColor).setAlpha(0.7))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Draw level
 | 
					    // Draw level
 | 
				
			||||||
    let scale: Float = 64
 | 
					    let scale: Float = 64
 | 
				
			||||||
    for y in 0..<Self.levelHeight {
 | 
					    for y in 0..<TestLevel.levelHeight {
 | 
				
			||||||
      for x in 0..<Self.levelWidth {
 | 
					      for x in 0..<TestLevel.levelWidth {
 | 
				
			||||||
        if level[x + Self.levelWidth * y] == 1 {
 | 
					        if self.level.get(.init(x, y)) {
 | 
				
			||||||
          self.spriteBatch.draw(self.texture, destination: .init(origin: Point(Point(x, y)) * scale, size: .init(scalar: scale)))
 | 
					          self.spriteBatch.draw(self.texture, destination: .init(origin: Point(Point(x, y)) * scale, size: .init(scalar: scale)))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Draw wireshark (controllable)
 | 
					    // Draw wireshark
 | 
				
			||||||
 | 
					    var shorkFlip: Sprite.Flip = fmod(self.player.rotate, 0.25) < 0.125 ? .none : .horz
 | 
				
			||||||
 | 
					    if self.player.velocity.y > 0 {
 | 
				
			||||||
 | 
					      shorkFlip = self.player.velocity.x < 0 ? shorkFlip.counterClockwise : shorkFlip.clockwise
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    self.spriteBatch.draw(self.wireShark,
 | 
					    self.spriteBatch.draw(self.wireShark,
 | 
				
			||||||
      position: player.position,
 | 
					      position: self.player.position, scale: 0.2, origin: .init(250, 275 * 2), flip: shorkFlip)
 | 
				
			||||||
      scale: .init(sin(player.rotate * 5), cos(player.rotate * 3)),
 | 
					 | 
				
			||||||
      angle: player.rotate, origin: .init(250, 275))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Sliding door test
 | 
					    // Sliding door test
 | 
				
			||||||
    let doorAngle = max(sin(player.rotate * 2.6) - 0.75, 0) * .pi
 | 
					    let doorAngle = max(sin(player.rotate * 2.6) - 0.75, 0) * .pi
 | 
				
			||||||
@ -78,7 +96,7 @@ internal class SpriteTestGame: GameDelegate {
 | 
				
			|||||||
      mpos /= SIMD2(Size<Float>(renderer.frame.size))
 | 
					      mpos /= SIMD2(Size<Float>(renderer.frame.size))
 | 
				
			||||||
      mpos *= SIMD2(self.spriteBatch.viewport!.size)
 | 
					      mpos *= SIMD2(self.spriteBatch.viewport!.size)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let inter = 0.5 + sin(player.rotate * 10) * 0.5
 | 
					    let inter = 0.5 + sin(Float(time.total) * 10) * 0.5
 | 
				
			||||||
    let color = Color<Float>.green.mix(.white, 0.3)
 | 
					    let color = Color<Float>.green.mix(.white, 0.3)
 | 
				
			||||||
    let mesh = Mesh<VertexPosition2DTexcoordColor, UInt16>.init(vertices: [
 | 
					    let mesh = Mesh<VertexPosition2DTexcoordColor, UInt16>.init(vertices: [
 | 
				
			||||||
      .init(position: mpos, texCoord: .zero, color: .one),
 | 
					      .init(position: mpos, texCoord: .zero, color: .one),
 | 
				
			||||||
@ -91,13 +109,95 @@ internal class SpriteTestGame: GameDelegate {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      self.spriteBatch.draw(self.texture, vertices: mesh.vertices[..<3])
 | 
					      self.spriteBatch.draw(self.texture, vertices: mesh.vertices[..<3])
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self.spriteBatch.end()
 | 
					    self.spriteBatch.end()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fileprivate struct TestLevel {
 | 
				
			||||||
 | 
					  public static let levelWidth = 40, levelHeight = 23
 | 
				
			||||||
 | 
					  public static let cellScale: Float = 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var data: [UInt8]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init() {
 | 
				
			||||||
 | 
					    self.data = .init(repeating: 0, count: Self.levelWidth * Self.levelHeight)
 | 
				
			||||||
 | 
					    for i in 0..<Self.levelWidth { self.data[i + (Self.levelHeight - 1) * Self.levelWidth] = 1 }
 | 
				
			||||||
 | 
					    for i in 0..<Self.levelWidth { self.data[i + (Self.levelHeight - 2) * Self.levelWidth] = 1 }
 | 
				
			||||||
 | 
					    for i in 17...20 { self.data[10 + i * Self.levelWidth] = 1 }
 | 
				
			||||||
 | 
					    for i in 17...20 { self.data[14 + i * Self.levelWidth] = 1 }
 | 
				
			||||||
 | 
					    for i in 11...13 { self.data[i + 17 * Self.levelWidth] = 1 }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mutating func set(_ p: SIMD2<Int>, _ to: Bool) {
 | 
				
			||||||
 | 
					    if p.x >= 0 && p.y >= 0 && p.x < Self.levelWidth && p.y < Self.levelHeight {
 | 
				
			||||||
 | 
					      self.data[p.x + Self.levelWidth * p.y] = to ? 1 : 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func get(_ p: Point<Int>) -> Bool {
 | 
				
			||||||
 | 
					    if p.x < 0 || p.y < 0 || p.x >= Self.levelWidth || p.y >= Self.levelHeight {
 | 
				
			||||||
 | 
					      return false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return self.data[p.x + Self.levelWidth * p.y] == 1
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func check(_ p: SIMD2<Float>) -> Bool {
 | 
				
			||||||
 | 
					    let p = SIMD2<Int>(p / TestLevel.cellScale, rounding: .down)
 | 
				
			||||||
 | 
					    return self.get(Point<Int>(p.x, p.y))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func check(_ rect: Extent<Float>) -> Bool {
 | 
				
			||||||
 | 
					    let p = Extent<Int>(floor(rect / Self.cellScale))
 | 
				
			||||||
 | 
					    return self.get(p.topLeft) || self.get(p.topRight) || self.get(p.bottomLeft) || self.get(p.bottomRight)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fileprivate struct TestPlayer {
 | 
					fileprivate struct TestPlayer {
 | 
				
			||||||
 | 
					  static private let rect = Extent<Float>(left: -30, top: -63, right: 30, bottom: 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var position: SIMD2<Float>
 | 
					  var position: SIMD2<Float>
 | 
				
			||||||
 | 
					  var velocity: SIMD2<Float> = .zero
 | 
				
			||||||
  var rotate: Float = 0
 | 
					  var rotate: Float = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var _onGround = false
 | 
				
			||||||
 | 
					  var onGround: Bool { self._onGround }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init(position: SIMD2<Float>) {
 | 
				
			||||||
 | 
					    self.position = position
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mutating func update(deltaTime dt: Float, level: TestLevel) {
 | 
				
			||||||
 | 
					    self.velocity.y += 1500 * dt
 | 
				
			||||||
 | 
					    if abs(self.velocity.y) > 3000 {
 | 
				
			||||||
 | 
					      self.velocity.y = .init(signOf: self.velocity.y, magnitudeOf: 3000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if self.velocity.x != 0 {
 | 
				
			||||||
 | 
					      self.position.x += self.velocity.x * dt
 | 
				
			||||||
 | 
					      if level.check(Self.rect + self.position) {
 | 
				
			||||||
 | 
					        let offset = self.velocity.x < 0 ? Self.rect.left : Self.rect.right
 | 
				
			||||||
 | 
					        self.position.x = round((self.position.x + offset) / TestLevel.cellScale) * TestLevel.cellScale - offset
 | 
				
			||||||
 | 
					        self.position.x -= .init(signOf: self.velocity.x, magnitudeOf: .ulpOfOne * 12000);
 | 
				
			||||||
 | 
					        self.velocity.x = 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if self.velocity.y != 0 {
 | 
				
			||||||
 | 
					      self.position.y += self.velocity.y * dt
 | 
				
			||||||
 | 
					      if level.check(Self.rect + (self.position)) {
 | 
				
			||||||
 | 
					        let offset = self.velocity.y < 0 ? Self.rect.top : Self.rect.bottom
 | 
				
			||||||
 | 
					        self.position.y = round((self.position.y + offset) / TestLevel.cellScale) * TestLevel.cellScale - offset
 | 
				
			||||||
 | 
					        self.position.y -= .init(signOf: self.velocity.y, magnitudeOf: .ulpOfOne * 12000);
 | 
				
			||||||
 | 
					        self.velocity.y = 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if self.velocity.x != 0 {
 | 
				
			||||||
 | 
					      self.rotate += abs(self.velocity.x) / 1000 * dt
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self._onGround = level.check(Self.rect + self.position + .init(0, .ulpOfOne * 24000))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fileprivate extension Color {
 | 
					fileprivate extension Color {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user