mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-02 13:00:53 +00:00
initial voxel system revamp
This commit is contained in:
parent
2e8f1de0a7
commit
9dd56faa4e
@ -1,10 +1,15 @@
|
||||
public struct Chunk {
|
||||
public static let chunkSize: Int = 16
|
||||
public static let blockCount = chunkSize * chunkSize * chunkSize
|
||||
|
||||
private static let yStride = chunkSize
|
||||
private static let zStride = chunkSize * chunkSize
|
||||
|
||||
public let position: SIMD3<Int>
|
||||
private var blocks: [Block]
|
||||
|
||||
init(position: SIMD3<Int>, blocks: [Block]) {
|
||||
assert(blocks.count == Self.blockCount)
|
||||
self.position = position
|
||||
self.blocks = blocks
|
||||
}
|
||||
@ -13,24 +18,29 @@ public struct Chunk {
|
||||
self.position = position
|
||||
self.blocks = Array(
|
||||
repeating: BlockType.air,
|
||||
count: Chunk.chunkSize * Chunk.chunkSize * Chunk.chunkSize
|
||||
count: Self.blockCount
|
||||
).map { type in Block(type) }
|
||||
}
|
||||
|
||||
func getBlockInternally(at position: SIMD3<Int>) -> Block {
|
||||
blocks[position.x + position.y * Chunk.chunkSize + position.z * Chunk.chunkSize * Chunk.chunkSize]
|
||||
func getBlock(at position: SIMD3<Int>) -> Block {
|
||||
if position.x < 0 || position.y < 0 || position.z < 0 {
|
||||
Block(.air)
|
||||
} else if position.x >= Self.chunkSize || position.y >= Self.chunkSize || position.z >= Self.chunkSize {
|
||||
Block(.air)
|
||||
} else {
|
||||
blocks[position.x + position.y * Self.yStride + position.z * Self.zStride]
|
||||
}
|
||||
}
|
||||
|
||||
mutating func setBlockInternally(at position: SIMD3<Int>, type: BlockType) {
|
||||
if position.x >= Chunk.chunkSize || position.y >= Chunk.chunkSize || position.z >= Chunk.chunkSize {
|
||||
return
|
||||
}
|
||||
|
||||
mutating func setBlock(at position: SIMD3<Int>, type: BlockType) {
|
||||
if position.x < 0 || position.y < 0 || position.z < 0 {
|
||||
return
|
||||
}
|
||||
if position.x >= Self.chunkSize || position.y >= Self.chunkSize || position.z >= Self.chunkSize {
|
||||
return
|
||||
}
|
||||
|
||||
blocks[position.x + position.y * Chunk.chunkSize + position.z * Chunk.chunkSize * Chunk.chunkSize].type = type
|
||||
blocks[position.x + position.y * Self.yStride + position.z * Self.zStride].type = type
|
||||
}
|
||||
|
||||
mutating func fill(allBy calculation: () -> BlockType) {
|
||||
@ -39,26 +49,75 @@ public struct Chunk {
|
||||
}
|
||||
}
|
||||
|
||||
func forEach(block perform: (SIMD3<Int>, Block) -> Void) {
|
||||
for x in 0..<Chunk.chunkSize {
|
||||
for y in 0..<Chunk.chunkSize {
|
||||
for z in 0..<Chunk.chunkSize {
|
||||
perform(SIMD3(x, y, z), blocks[x + y * Chunk.chunkSize + z * Chunk.chunkSize * Chunk.chunkSize])
|
||||
func forEach(block perform: (Block, SIMD3<Int>) -> Void) {
|
||||
for x in 0..<Self.chunkSize {
|
||||
for y in 0..<Self.chunkSize {
|
||||
for z in 0..<Self.chunkSize {
|
||||
let idx = x + y * Self.yStride + z * Self.zStride
|
||||
let position = SIMD3(x, y, z)
|
||||
perform(blocks[idx], position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func map<T>(block transform: (Block, SIMD3<Int>) throws -> T) rethrows -> [T] {
|
||||
assert(self.blocks.count == Self.blockCount)
|
||||
|
||||
var out = [T]()
|
||||
out.reserveCapacity(Self.blockCount)
|
||||
|
||||
var position = SIMD3<Int>()
|
||||
for i in self.blocks.indices {
|
||||
out.append(try transform(blocks[i], position))
|
||||
position.x += 1
|
||||
if position.x == Self.chunkSize {
|
||||
position.x = 0
|
||||
position.y += 1
|
||||
if position.y == Self.chunkSize {
|
||||
position.y = 0
|
||||
position.z += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
public func compactMap<T>(block transform: (Block, SIMD3<Int>) throws -> T?) rethrows -> [T] {
|
||||
assert(self.blocks.count == Self.blockCount)
|
||||
|
||||
var out = [T]()
|
||||
out.reserveCapacity(Self.blockCount >> 1)
|
||||
|
||||
var position = SIMD3<Int>()
|
||||
for i in self.blocks.indices {
|
||||
if let element = try transform(blocks[i], position) {
|
||||
out.append(element)
|
||||
}
|
||||
position.x += 1
|
||||
if position.x == Self.chunkSize {
|
||||
position.x = 0
|
||||
position.y += 1
|
||||
if position.y == Self.chunkSize {
|
||||
position.y = 0
|
||||
position.z += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
public enum BlockType: Equatable {
|
||||
case air
|
||||
case solid(Color<Float16>)
|
||||
case solid(_ color: Color<UInt8>)
|
||||
}
|
||||
|
||||
public struct Block {
|
||||
public var type: BlockType
|
||||
|
||||
|
||||
|
||||
public init(_ type: BlockType) {
|
||||
self.type = type
|
||||
}
|
||||
|
@ -1,11 +1,6 @@
|
||||
import simd
|
||||
import Foundation
|
||||
|
||||
struct Box {
|
||||
var geometry: AABB
|
||||
var color: Color<Float16> = .white
|
||||
}
|
||||
|
||||
struct Instance {
|
||||
let position: SIMD3<Float>
|
||||
let scale: SIMD3<Float>
|
||||
@ -30,32 +25,24 @@ class Game: GameDelegate {
|
||||
var camera = Camera(fov: 60, size: .one, range: 0.06...900)
|
||||
var player = Player()
|
||||
var projection: matrix_float4x4 = .identity
|
||||
|
||||
var boxes: [Box] = []
|
||||
var chunk = Chunk(position: .zero)
|
||||
|
||||
init() {
|
||||
player.position = SIMD3(0.5, Float(Chunk.chunkSize) + 0.5, 0.5)
|
||||
player.rotation = .init(.pi, 0)
|
||||
|
||||
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,
|
||||
let colors: [Color<UInt8>] = [
|
||||
.white,
|
||||
.red, .blue, .green,
|
||||
.magenta, .yellow, .cyan
|
||||
]
|
||||
chunk.fill(allBy: { options[Int(arc4random_uniform(UInt32(options.count)))] })
|
||||
chunk.fill(allBy: {
|
||||
if (arc4random() & 0x1) == 0x1 {
|
||||
.solid(colors[Int(arc4random_uniform(UInt32(colors.count)))])
|
||||
} else {
|
||||
.air
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func fixedUpdate(_ time: GameTime) {
|
||||
@ -72,29 +59,17 @@ class Game: GameDelegate {
|
||||
if let pad = GameController.current?.state {
|
||||
// Delete block underneath player
|
||||
if pad.pressed(.south) {
|
||||
chunk.setBlockInternally(at: SIMD3(player.position + .down * 0.2), type: .air)
|
||||
chunk.setBlock(at: SIMD3(player.position + .down * 0.2), type: .air)
|
||||
}
|
||||
// Player reset
|
||||
if pad.pressed(.back) {
|
||||
player.position = SIMD3(0.5, Float(Chunk.chunkSize) + 0.5, 0.5)
|
||||
player.position = .init(repeating: 0.5) + .init(0, Float(Chunk.chunkSize), 0)
|
||||
player.velocity = .zero
|
||||
player.rotation = .init(.pi, 0)
|
||||
}
|
||||
}
|
||||
boxes = []
|
||||
chunk.forEach { position, block in
|
||||
if block.type == .air {
|
||||
return
|
||||
}
|
||||
|
||||
if case let .solid(color) = block.type {
|
||||
boxes.append(Box(
|
||||
geometry: .fromUnitCube(position: SIMD3<Float>(position) + 0.5, scale: .init(repeating: 0.5)),
|
||||
color: color))
|
||||
}
|
||||
}
|
||||
|
||||
player.update(deltaTime: deltaTime, boxes: boxes)
|
||||
player.update(deltaTime: deltaTime, chunk: chunk)
|
||||
camera.position = player.eyePosition
|
||||
camera.rotation = player.eyeRotation
|
||||
}
|
||||
@ -103,18 +78,14 @@ class Game: GameDelegate {
|
||||
let totalTime = Float(time.total.asFloat)
|
||||
let cubeSpeedMul: Float = 0.1
|
||||
|
||||
var instances: [Instance] = boxes.map {
|
||||
Instance(
|
||||
position: $0.geometry.center,
|
||||
scale: $0.geometry.size * 0.5,
|
||||
color: $0.color)
|
||||
let instances = chunk.compactMap { block, position in
|
||||
if case let .solid(color) = block.type {
|
||||
Instance(
|
||||
position: SIMD3<Float>(position) + 0.5,
|
||||
scale: .init(repeating: 0.5),
|
||||
color: Color<Float16>(color).linear)
|
||||
} else { nil }
|
||||
}
|
||||
instances.append(
|
||||
Instance(
|
||||
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))
|
||||
renderer.batch(instances: instances, camera: self.camera)
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct Player {
|
||||
.init(angle: self._rotation.x, axis: .up)
|
||||
}
|
||||
|
||||
mutating func update(deltaTime: Float, boxes: [Box]) {
|
||||
mutating func update(deltaTime: Float, chunk: Chunk) {
|
||||
if let pad = GameController.current?.state {
|
||||
// Turning input
|
||||
let turning = pad.rightStick.radialDeadzone(min: 0.1, max: 1)
|
||||
@ -69,12 +69,10 @@ struct Player {
|
||||
|
||||
// Move & handle collision
|
||||
let checkCollision = { (position: SIMD3<Float>) -> Optional<AABB> in
|
||||
for box in boxes {
|
||||
let bounds = Self.bounds + position
|
||||
if bounds.touching(box.geometry) {
|
||||
return box.geometry
|
||||
}
|
||||
}
|
||||
let bounds = Self.bounds + position
|
||||
//if bounds.touching(blockGeometry) {
|
||||
// return box.geometry
|
||||
//}
|
||||
return nil
|
||||
}
|
||||
self._position.x += self._velocity.x * deltaTime
|
||||
|
Loading…
Reference in New Issue
Block a user