Skip to content

Instantly share code, notes, and snippets.

@mohiji
Last active September 13, 2016 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohiji/1f4087395c5ab8aa565595d11e63af0b to your computer and use it in GitHub Desktop.
Save mohiji/1f4087395c5ab8aa565595d11e63af0b to your computer and use it in GitHub Desktop.
import Foundation
struct Vector3 : Equatable {
let x: Float
let y: Float
let z: Float
func magnitude() -> Float {
return sqrtf(x * x + y * y + z * z)
}
func normal() -> Vector3 {
let magnitude = self.magnitude()
if (magnitude == 0.0) {
return Vector3(x: 0.0, y: 0.0, z: 0.0)
} else {
return self / magnitude
}
}
}
func ==(left: Vector3, right: Vector3) -> Bool {
return left.x == right.x && left.y == right.y && left.z == right.z
}
prefix func -(v: Vector3) -> Vector3 {
return Vector3(x: -v.x, y: -v.y, z: -v.z)
}
func +(left: Vector3, right: Vector3) -> Vector3 {
return Vector3(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z)
}
func -(left: Vector3, right: Vector3) -> Vector3 {
return Vector3(x: left.x - right.x, y: left.y - right.y, z: left.z - right.z)
}
func *(left: Vector3, right: Float) -> Vector3 {
return Vector3(x: left.x * right, y: left.y * right, z: left.z * right)
}
func *(left: Vector3, right: Vector3) -> Vector3 {
return Vector3(x: left.z * right.z, y: left.y * right.y, z: left.z * right.z)
}
func *(left: Float, right: Vector3) -> Vector3 {
return Vector3(x: left * right.x, y: left * right.y, z: left * right.z)
}
func /(left: Vector3, right: Float) -> Vector3 {
return Vector3(x: left.x / right, y: left.y / right, z: left.z / right)
}
func distance(left: Vector3, _ right: Vector3) -> Float {
return (left - right).magnitude()
}
struct Block {
let location: Vector3
let name: String
let durability: Int
let textureId: Int
let breakable: Bool
let visible: Bool
let type: Int
let id: Int
}
enum EntityType {
case Zombie
case Chicken
case Exploder
case TallCreepyThing
}
class Entity {
let name: String
let type: EntityType
let speed: Vector3
var location: Vector3
var health: Int
init(location: Vector3, type: EntityType) {
self.location = location
self.type = type
switch (type) {
case .Zombie:
self.name = "Zombie"
self.speed = Vector3(x: 0.5, y: 0.0, z: 0.5)
self.health = 50
case .Chicken:
self.name = "Chicken"
self.speed = Vector3(x: 0.75, y: 0.25, z: 0.75)
self.health = 25
case .Exploder:
self.name = "Exploder"
self.speed = Vector3(x: 0.75, y: 0.0, z: 0.75)
self.health = 75
case .TallCreepyThing:
self.name = "Tall Creepy Thing"
self.speed = Vector3(x: 1.0, y: 1.0, z: 1.0)
self.health = 500
}
}
func updatePosition() {
self.location = self.location + self.speed
}
}
class Chunk {
static let numBlocks = 256
static let numEntities = 1000
let blocks: [Int]
let location: Vector3
var entities: [Entity]
init(location: Vector3) {
self.location = location
var mutableBlocks = [Int]()
mutableBlocks.reserveCapacity(Chunk.numBlocks)
for i in 0 ..< Chunk.numBlocks {
mutableBlocks.append(i % 256)
}
blocks = mutableBlocks
entities = []
entities.reserveCapacity(Chunk.numEntities)
for i in 0 ..< (Chunk.numEntities / 4) {
entities.append(Entity(location: Vector3(x: Float(i), y: Float(i), z: Float(i)), type: EntityType.Chicken))
entities.append(Entity(location: Vector3(x: Float(i + 2), y: Float(i), z: Float(i)), type: EntityType.Zombie))
entities.append(Entity(location: Vector3(x: Float(i + 3), y: Float(i), z: Float(i)), type: EntityType.Exploder))
entities.append(Entity(location: Vector3(x: Float(i + 4), y: Float(i), z: Float(i)), type: EntityType.TallCreepyThing))
}
}
func processEntities() {
for entity in entities {
entity.updatePosition()
}
}
}
class Game {
static let chunkCount = 100
let blocks: [Block]
var chunks: [Chunk]
var playerLocation = Vector3(x: 0.0, y: 0.0, z: 0.0)
var chunkCounter: Int
init() {
var mBlocks = [Block]()
mBlocks.reserveCapacity(Chunk.numBlocks)
for i in 0 ..< Chunk.numBlocks {
mBlocks.append(Block(location: Vector3(x: Float(i), y: Float(i), z: Float(i)),
name: "Block:\(i)",
durability: 100,
textureId: 1,
breakable: true,
visible: true,
type: 1,
id: i))
}
self.blocks = mBlocks
chunks = []
chunks.reserveCapacity(Game.chunkCount)
for i in 0 ..< Game.chunkCount {
chunks.append(Chunk(location: Vector3(x: Float(i), y: 0.0, z: 0.0)))
}
chunkCounter = Game.chunkCount
}
func updateWorld() {
for i in 0 ..< chunks.count {
let chunk = chunks[i]
let dist = distance(playerLocation, chunk.location)
if dist > Float(Game.chunkCount) {
// Replace the existing chunk with a new one
chunks[i] = Chunk(location: Vector3(x: Float(chunkCounter), y: 0.0, z: 0.0))
chunkCounter = chunkCounter + 1
} else {
chunk.processEntities()
}
}
}
}
print("Creating game!")
let loadStart = CFAbsoluteTimeGetCurrent()
let game = Game()
let loadElapsed = CFAbsoluteTimeGetCurrent() - loadStart
print("Load game time: \(loadElapsed * 1000.0)ms")
let numFrames = 60 * 60
var minFrameTime = CFAbsoluteTime(1000.0)
var maxFrameTime = CFAbsoluteTime(0.0)
var frameTimeAccum = CFAbsoluteTime(0.0)
for i in 0 ..< numFrames {
let frameStart = CFAbsoluteTimeGetCurrent()
game.playerLocation = game.playerLocation + Vector3(x: 0.1, y: 0.0, z: 0.0)
game.updateWorld()
let frameElapsed = CFAbsoluteTimeGetCurrent() - frameStart
// print("Frame \(i): \(frameElapsed * 1000.0)ms")
if frameElapsed < minFrameTime {
minFrameTime = frameElapsed
}
if frameElapsed > maxFrameTime {
maxFrameTime = frameElapsed
}
frameTimeAccum += frameElapsed
}
let totalElapsed = CFAbsoluteTimeGetCurrent() - loadStart
print("Run finished in \(totalElapsed) seconds")
print("Minimum frame time: \(minFrameTime * 1000.0)ms")
print("Maximum frame time: \(maxFrameTime * 1000.0)ms")
print("Average frame time: \((frameTimeAccum / CFAbsoluteTime(numFrames)) * 1000.0)ms")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment