mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 10:59:39 +00:00 
			
		
		
		
	initial voxel implementation
This commit is contained in:
		@ -3,6 +3,8 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
			
		||||
 | 
			
		||||
  test.png
 | 
			
		||||
 | 
			
		||||
  Chunk.swift
 | 
			
		||||
 | 
			
		||||
  shadertypes.h
 | 
			
		||||
  shader.metal
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								Sources/Voxelotl/Chunk.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Sources/Voxelotl/Chunk.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
public struct Chunk {
 | 
			
		||||
  public static let chunkSize: Int = 16
 | 
			
		||||
  
 | 
			
		||||
  public let position: SIMD3<Int>
 | 
			
		||||
  private var blocks: [Block]
 | 
			
		||||
  
 | 
			
		||||
  init(position: SIMD3<Int>, blocks: [Block]) {
 | 
			
		||||
    self.position = position
 | 
			
		||||
    self.blocks = blocks
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  init(position: SIMD3<Int>) {
 | 
			
		||||
    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<Int>) -> Block {
 | 
			
		||||
    blocks[position.x + position.y * Chunk.chunkSize + position.z * Chunk.chunkSize * Chunk.chunkSize]
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  mutating func setBlockInternally(at position: SIMD3<Int>, 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<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])
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public enum BlockType: Equatable {
 | 
			
		||||
  case air
 | 
			
		||||
  case solid(Color<Float16>)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public struct Block {
 | 
			
		||||
  public var type: BlockType
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  public init(_ type: BlockType) {
 | 
			
		||||
    self.type = type
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -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<Float>(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))
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,9 @@ struct Player {
 | 
			
		||||
 | 
			
		||||
  private var _onGround: Bool = false
 | 
			
		||||
 | 
			
		||||
  public var position: SIMD3<Float> { self._position + .init(0, Self.eyeLevel, 0) }
 | 
			
		||||
  public var position: SIMD3<Float> {
 | 
			
		||||
    get { self._position + .init(0, Self.eyeLevel, 0) } set { self._position = newValue }
 | 
			
		||||
  }
 | 
			
		||||
  public var rotation: SIMD2<Float> { self._rotation }
 | 
			
		||||
 | 
			
		||||
  mutating func update(deltaTime: Float, boxes: [Box]) {
 | 
			
		||||
@ -36,13 +38,18 @@ struct Player {
 | 
			
		||||
      }
 | 
			
		||||
      self._rotation.y = self._rotation.y.clamp(-.pi * 0.5, .pi * 0.5)
 | 
			
		||||
 | 
			
		||||
      if self._onGround {
 | 
			
		||||
        // Movement on ground
 | 
			
		||||
      // 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)
 | 
			
		||||
        self._velocity.x = (movement.x * rotc - movement.y * rots) * Self.accelerationCoeff
 | 
			
		||||
        self._velocity.z = (movement.y * rotc + movement.x * rots) * Self.accelerationCoeff
 | 
			
		||||
      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
 | 
			
		||||
@ -50,8 +57,8 @@ struct Player {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // 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)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user