mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-03 13:11:33 +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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.player.rotate += Float(time.delta)
|
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