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