diff --git a/Sources/Voxelotl/CMakeLists.txt b/Sources/Voxelotl/CMakeLists.txt index 5e2bfcc..4a99689 100644 --- a/Sources/Voxelotl/CMakeLists.txt +++ b/Sources/Voxelotl/CMakeLists.txt @@ -3,6 +3,8 @@ add_executable(Voxelotl MACOSX_BUNDLE test.png + Chunk.swift + shadertypes.h shader.metal diff --git a/Sources/Voxelotl/Chunk.swift b/Sources/Voxelotl/Chunk.swift new file mode 100644 index 0000000..a551b39 --- /dev/null +++ b/Sources/Voxelotl/Chunk.swift @@ -0,0 +1,57 @@ +public struct Chunk { + public static let chunkSize: Int = 16 + + public let position: SIMD3 + private var blocks: [Block] + + init(position: SIMD3, blocks: [Block]) { + self.position = position + self.blocks = blocks + } + + init(position: SIMD3) { + self.position = position + self.blocks = Array( + repeating: BlockType.air, + count: Chunk.chunkSize * Chunk.chunkSize * Chunk.chunkSize + ).map { type in Block(type) } + } + + func getBlockInternally(at position: SIMD3) -> Block { + blocks[position.x + position.y * Chunk.chunkSize + position.z * Chunk.chunkSize * Chunk.chunkSize] + } + + mutating func setBlockInternally(at position: SIMD3, type: BlockType) { + blocks[position.x + position.y * Chunk.chunkSize + position.z * Chunk.chunkSize * Chunk.chunkSize].type = type + } + + mutating func fill(allBy calculation: () -> BlockType) { + blocks.indices.forEach { i in + blocks[i].type = calculation() + } + } + + func forEach(block perform: (SIMD3, Block) -> Void) { + for x in 0..) +} + +public struct Block { + public var type: BlockType + + + public init(_ type: BlockType) { + self.type = type + } +} diff --git a/Sources/Voxelotl/Game.swift b/Sources/Voxelotl/Game.swift index 4d39b07..f04bb98 100644 --- a/Sources/Voxelotl/Game.swift +++ b/Sources/Voxelotl/Game.swift @@ -1,4 +1,5 @@ import simd +import Foundation struct Box { var geometry: AABB @@ -24,26 +25,54 @@ struct Instance { } } -let boxes: [Box] = [ - Box(geometry: .fromUnitCube( - position: .init( 0, -1, 0) * 2, - scale: .init(10, 0.1, 10) * 2)), - Box(geometry: .fromUnitCube( - position: .init(-2.5, 0, -3) * 2, - scale: .init(repeating: 2)), - color: .init(rgb888: 0xFF80BF).linear), - Box(geometry: .fromUnitCube( - position: .init(-2.5, -0.5, -5) * 2, - scale: .init(repeating: 2)), - color: .init(rgb888: 0xBFFFFF).linear) -] - class Game: GameDelegate { private var fpsCalculator = FPSCalculator() - var camera = Camera(fov: 60, size: .one, range: 0.06...50) + var camera = Camera(fov: 60, size: .one, range: 0.06...900) var player = Player() var projection: matrix_float4x4 = .identity + var boxes: [Box] = [] + + init() { + var chunk = Chunk(position: .zero) + let options: [BlockType] = [ + .air, + .solid(.blue), + .air, + .solid(.red), + .air, + .solid(.green), + .air, + .solid(.white), + .air, + .solid(.cyan), + .air, + .solid(.yellow), + .air, + .solid(.magenta), + .air, + ] + chunk + .fill(allBy: { options[Int(arc4random_uniform(UInt32(options.count)))] }) + chunk.forEach { position, block in + if block.type == .air { + return + } + + if case let .solid(color) = block.type { + boxes + .append( + Box( + geometry: + .fromUnitCube(position: SIMD3(position) + 0.5, scale: .init(repeating: 0.5)), + color: color + ) + ) + } + } + player.position = SIMD3(0.5, Float(Chunk.chunkSize) + 0.5, 0.5) + } + func fixedUpdate(_ time: GameTime) { } @@ -74,7 +103,7 @@ class Game: GameDelegate { } instances.append( Instance( - position: .init(0, sin(totalTime * 1.5 * cubeSpeedMul) * 0.5, -2) * 2, + position: .init(0, sin(totalTime * 1.5 * cubeSpeedMul) * 0.5, 0) * 2, scale: .init(repeating: 0.5), rotation: .init(angle: totalTime * 3.0 * cubeSpeedMul, axis: .init(0, 1, 0)), color: .init(r: 0.5, g: 0.5, b: 1).linear)) diff --git a/Sources/Voxelotl/Player.swift b/Sources/Voxelotl/Player.swift index 145cf3f..ef1360b 100644 --- a/Sources/Voxelotl/Player.swift +++ b/Sources/Voxelotl/Player.swift @@ -20,7 +20,9 @@ struct Player { private var _onGround: Bool = false - public var position: SIMD3 { self._position + .init(0, Self.eyeLevel, 0) } + public var position: SIMD3 { + get { self._position + .init(0, Self.eyeLevel, 0) } set { self._position = newValue } + } public var rotation: SIMD2 { self._rotation } mutating func update(deltaTime: Float, boxes: [Box]) { @@ -36,22 +38,27 @@ struct Player { } self._rotation.y = self._rotation.y.clamp(-.pi * 0.5, .pi * 0.5) - 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.accelerationCoeff - self._velocity.z = (movement.y * rotc + movement.x * rots) * Self.accelerationCoeff + // 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 + if self._onGround { // Jumping if pad.pressed(.east) { self._velocity.y = Self.jumpVelocity self._onGround = false } } - - // Flying - self._velocity.y += pad.rightTrigger * 36 * deltaTime + + // Flying and unflying + self._velocity.y += (pad.rightTrigger - pad.leftTrigger) * 36 * deltaTime // Reset if pad.pressed(.back) { @@ -112,5 +119,17 @@ struct Player { self._velocity.x = 0 self._velocity.z = 0 } + + 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) + } } }