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
 | 
					  test.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Chunk.swift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  shadertypes.h
 | 
					  shadertypes.h
 | 
				
			||||||
  shader.metal
 | 
					  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 simd
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Box {
 | 
					struct Box {
 | 
				
			||||||
  var geometry: AABB
 | 
					  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 {
 | 
					class Game: GameDelegate {
 | 
				
			||||||
  private var fpsCalculator = FPSCalculator()
 | 
					  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 player = Player()
 | 
				
			||||||
  var projection: matrix_float4x4 = .identity
 | 
					  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) {
 | 
					  func fixedUpdate(_ time: GameTime) {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -74,7 +103,7 @@ class Game: GameDelegate {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    instances.append(
 | 
					    instances.append(
 | 
				
			||||||
      Instance(
 | 
					      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),
 | 
					        scale:    .init(repeating: 0.5),
 | 
				
			||||||
        rotation: .init(angle: totalTime * 3.0 * cubeSpeedMul, axis: .init(0, 1, 0)),
 | 
					        rotation: .init(angle: totalTime * 3.0 * cubeSpeedMul, axis: .init(0, 1, 0)),
 | 
				
			||||||
        color:    .init(r: 0.5, g: 0.5, b: 1).linear))
 | 
					        color:    .init(r: 0.5, g: 0.5, b: 1).linear))
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,9 @@ struct Player {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private var _onGround: Bool = false
 | 
					  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 }
 | 
					  public var rotation: SIMD2<Float> { self._rotation }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mutating func update(deltaTime: Float, boxes: [Box]) {
 | 
					  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)
 | 
					      self._rotation.y = self._rotation.y.clamp(-.pi * 0.5, .pi * 0.5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if self._onGround {
 | 
					      // Movement (slower in air than on ground)
 | 
				
			||||||
        // Movement on ground
 | 
					      let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
 | 
				
			||||||
        let movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
 | 
					      let rotc = cos(self._rotation.x), rots = sin(self._rotation.x)
 | 
				
			||||||
        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
 | 
					      self._velocity.x = (
 | 
				
			||||||
        self._velocity.z = (movement.y * rotc + movement.x * rots) * Self.accelerationCoeff
 | 
					        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
 | 
					        // Jumping
 | 
				
			||||||
        if pad.pressed(.east) {
 | 
					        if pad.pressed(.east) {
 | 
				
			||||||
          self._velocity.y = Self.jumpVelocity
 | 
					          self._velocity.y = Self.jumpVelocity
 | 
				
			||||||
          self._onGround = false
 | 
					          self._onGround = false
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      // Flying
 | 
					      // Flying and unflying
 | 
				
			||||||
      self._velocity.y += pad.rightTrigger * 36 * deltaTime
 | 
					      self._velocity.y += (pad.rightTrigger - pad.leftTrigger) * 36 * deltaTime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Reset
 | 
					      // Reset
 | 
				
			||||||
      if pad.pressed(.back) {
 | 
					      if pad.pressed(.back) {
 | 
				
			||||||
@ -112,5 +119,17 @@ struct Player {
 | 
				
			|||||||
      self._velocity.x = 0
 | 
					      self._velocity.x = 0
 | 
				
			||||||
      self._velocity.z = 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