mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 02:59:37 +00:00 
			
		
		
		
	initial voxel system revamp
This commit is contained in:
		@ -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
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user