Optimized a lot
This commit is contained in:
parent
a33281b1fa
commit
7c7b38253b
|
|
@ -9,11 +9,15 @@ let package = Package(
|
|||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
.library(
|
||||
name: "FirebladeECS",
|
||||
targets: ["FirebladeECS"])
|
||||
targets: ["FirebladeECS"]),
|
||||
.executable(
|
||||
name: "FirebladeECSDemo",
|
||||
targets: ["FirebladeECSDemo"])
|
||||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
// .package(url: /* package url */, from: "1.0.0"),
|
||||
.package(url: "https://github.com/PureSwift/CSDL2.git", .branch("master"))
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
|
|
@ -21,6 +25,9 @@ let package = Package(
|
|||
.target(
|
||||
name: "FirebladeECS",
|
||||
dependencies: []),
|
||||
.target(
|
||||
name: "FirebladeECSDemo",
|
||||
dependencies: ["FirebladeECS"]),
|
||||
.testTarget(
|
||||
name: "FirebladeECSTests",
|
||||
dependencies: ["FirebladeECS"])
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// ContiguousComponentArray.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 28.10.17.
|
||||
//
|
||||
|
||||
private let pow2: [Int] = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296
|
||||
]
|
||||
|
||||
private func nearestToPow2(_ value: Int) -> Int {
|
||||
let exp = (value.bitWidth-value.leadingZeroBitCount)
|
||||
return pow2[exp]
|
||||
}
|
||||
|
||||
public class ContiguousComponentArray {
|
||||
public typealias Element = Component
|
||||
|
||||
private var _store: ContiguousArray<Element?>
|
||||
|
||||
public init(minEntityCount minCount: Int) {
|
||||
let count = nearestToPow2(minCount)
|
||||
_store = ContiguousArray<Element?>(repeating: nil, count: count)
|
||||
}
|
||||
|
||||
public func insert(_ element: Element, at entityIdx: EntityIndex) {
|
||||
|
||||
if needsToGrow(entityIdx) {
|
||||
grow(to: entityIdx)
|
||||
}
|
||||
_store[entityIdx] = element
|
||||
}
|
||||
|
||||
public func has(_ entityIdx: EntityIndex) -> Bool {
|
||||
if _store.count <= entityIdx { return false }
|
||||
return _store[entityIdx] != nil
|
||||
}
|
||||
|
||||
public func get(at entityIdx: EntityIndex) -> Element? {
|
||||
return _store[entityIdx]
|
||||
}
|
||||
|
||||
public func remove(at entityIdx: EntityIndex) {
|
||||
return _store[entityIdx] = nil
|
||||
}
|
||||
|
||||
fileprivate func needsToGrow(_ entityId: EntityIndex) -> Bool {
|
||||
return entityId > _store.count - 1
|
||||
}
|
||||
|
||||
fileprivate func grow(to minIndex: Int) {
|
||||
if minIndex >= _store.count {
|
||||
let newCapacity: Int = nearestToPow2(minIndex)
|
||||
let count: Int = newCapacity-_store.count
|
||||
let nilElements: ContiguousArray<Element?> = ContiguousArray<Element?>.init(repeating: nil, count: count)
|
||||
|
||||
_store.reserveCapacity(newCapacity)
|
||||
_store.append(contentsOf: nilElements)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ extension Family {
|
|||
/*public var members: LazyMapCollection<LazyFilterCollection<LazyMapCollection<EntityIdSet, Entity?>>, Entity> {
|
||||
return nexus.members(of: self)
|
||||
}*/
|
||||
internal var memberIds: EntityIdSet {
|
||||
internal var memberIds: [EntityIdentifier] {
|
||||
return nexus.members(of: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// ManagedContiguousArray.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 28.10.17.
|
||||
//
|
||||
|
||||
private let pow2: [Int] = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296
|
||||
]
|
||||
|
||||
private func nearestToPow2(_ value: Int) -> Int {
|
||||
let exp = (value.bitWidth-value.leadingZeroBitCount)
|
||||
return pow2[exp]
|
||||
}
|
||||
|
||||
public protocol ManagedContiguousArrayProtocol: class {
|
||||
associatedtype Element
|
||||
static var chunkSize: Int { get }
|
||||
init(minCount: Int)
|
||||
func insert(_ element: Element, at index: Int)
|
||||
func has(_ index: Int) -> Bool
|
||||
func get(at index: Int) -> Element?
|
||||
func remove(at index: Int)
|
||||
}
|
||||
|
||||
public class ManagedContiguousArray: ManagedContiguousArrayProtocol {
|
||||
public static var chunkSize: Int = 4096
|
||||
|
||||
public typealias Element = Any
|
||||
var _store: ContiguousArray<Element?> = []
|
||||
public required init(minCount: Int = chunkSize) {
|
||||
_store = ContiguousArray<Element?>(repeating: nil, count: minCount)
|
||||
}
|
||||
|
||||
public func insert(_ element: Element, at index: Int) {
|
||||
if needsToGrow(index) {
|
||||
grow(including: index)
|
||||
}
|
||||
_store[index] = element
|
||||
}
|
||||
public func has(_ index: Int) -> Bool {
|
||||
if _store.count <= index { return false }
|
||||
return _store[index] != nil
|
||||
}
|
||||
|
||||
public func get(at index: Int) -> Element? {
|
||||
return _store[index]
|
||||
}
|
||||
|
||||
public func remove(at index: Int) {
|
||||
return _store[index] = nil
|
||||
}
|
||||
|
||||
internal func needsToGrow(_ index: Int) -> Bool {
|
||||
return index > _store.count - 1
|
||||
}
|
||||
|
||||
internal func grow(including index: Int) {
|
||||
//var t = Timer()
|
||||
//t.start()
|
||||
let newCapacity: Int = nearest(to: index)
|
||||
let count: Int = newCapacity-_store.count
|
||||
//_store.reserveCapacity(newCapacity)
|
||||
for _ in 0..<count {
|
||||
_store.append(nil)
|
||||
}
|
||||
//t.stop()
|
||||
//print("did grow to \(newCapacity) in \(t.milliSeconds)ms")
|
||||
}
|
||||
|
||||
internal func nearest(to index: Int) -> Int {
|
||||
let delta = Float(index) / Float(ManagedContiguousArray.chunkSize)
|
||||
let multiplier = Int(delta) + 1
|
||||
return multiplier * ManagedContiguousArray.chunkSize
|
||||
}
|
||||
}
|
||||
|
||||
public class ContiguousComponentArray: ManagedContiguousArray {
|
||||
public typealias Element = Component
|
||||
}
|
||||
|
||||
public class ContiguousEntityIdArray: ManagedContiguousArray {
|
||||
public typealias Element = EntityIdentifier
|
||||
}
|
||||
|
||||
/*
|
||||
public func insert(_ element: Element, at entityIdx: EntityIndex) {
|
||||
super.insert(element, at: entityIdx)
|
||||
}
|
||||
|
||||
public func has(_ entityIdx: EntityIndex) -> Bool {
|
||||
if _store.count <= entityIdx { return false }
|
||||
return _store[entityIdx] != nil
|
||||
}
|
||||
|
||||
public func get(at entityIdx: EntityIndex) -> Element? {
|
||||
return _store[entityIdx]
|
||||
}
|
||||
|
||||
public func remove(at entityIdx: EntityIndex) {
|
||||
return _store[entityIdx] = nil
|
||||
}
|
||||
|
||||
fileprivate func needsToGrow(_ entityId: EntityIndex) -> Bool {
|
||||
return entityId > _store.count - 1
|
||||
}
|
||||
|
||||
fileprivate func grow(to minIndex: Int) {
|
||||
|
||||
let newCapacity: Int = nearestToPow2(minIndex)
|
||||
let count: Int = newCapacity-_store.count
|
||||
let nilElements: ContiguousArray<Element?> = ContiguousArray<Element?>.init(repeating: nil, count: count)
|
||||
|
||||
_store.reserveCapacity(newCapacity)
|
||||
_store.append(contentsOf: nilElements)
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
@ -34,7 +34,7 @@ extension Nexus {
|
|||
if componentsByType[componentId] != nil {
|
||||
componentsByType[componentId]!.insert(component, at: entityIdx)
|
||||
} else {
|
||||
componentsByType[componentId] = UniformComponents(minEntityCount: entities.count)
|
||||
componentsByType[componentId] = UniformComponents()
|
||||
componentsByType[componentId]!.insert(component, at: entityIdx)
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ extension Nexus {
|
|||
|
||||
public func get(component componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component? {
|
||||
guard let uniformComponents: UniformComponents = componentsByType[componentId] else { return nil }
|
||||
return uniformComponents.get(at: entityId.index)
|
||||
return uniformComponents.get(at: entityId.index) as? Component
|
||||
}
|
||||
|
||||
public func get<C>(for entityId: EntityIdentifier) -> C? where C: Component {
|
||||
|
|
|
|||
|
|
@ -39,23 +39,24 @@ extension Nexus {
|
|||
return family.traits.isMatch(components: componentSet)
|
||||
}
|
||||
|
||||
public func members(of family: Family) -> EntityIdSet {
|
||||
public func members(of family: Family) -> [EntityIdentifier] {
|
||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||
return familyMembersByTraitHash[traitHash] ?? [] // FIXME: fail?
|
||||
}
|
||||
|
||||
/*public func members(of family: Family) -> LazyMapCollection<LazyFilterCollection<LazyMapCollection<EntityIdSet, Entity?>>, Entity> {
|
||||
return members(of: family).lazy.flatMap { self.get(entity: $0) }
|
||||
}*/
|
||||
|
||||
public func isMember(_ entity: Entity, in family: Family) -> Bool {
|
||||
return isMember(entity.identifier, in: family)
|
||||
}
|
||||
|
||||
public func isMember(byHash traitSetEntityIdHash: TraitEntityIdHash) -> Bool {
|
||||
return familyContainsEntityId[traitSetEntityIdHash] ?? false
|
||||
}
|
||||
|
||||
public func isMember(_ entityId: EntityIdentifier, in family: Family) -> Bool {
|
||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||
// FIXME: this may be costly for many entities in family
|
||||
return familyMembersByTraitHash[traitHash]?.contains(entityId) ?? false
|
||||
// FIXME: this is costly!
|
||||
guard let members: [EntityIdentifier] = familyMembersByTraitHash[traitHash] else { return false }
|
||||
return members.contains(entityId)
|
||||
}
|
||||
|
||||
fileprivate func get(family traits: FamilyTraitSet) -> Family? {
|
||||
|
|
@ -82,44 +83,57 @@ extension Nexus {
|
|||
|
||||
// MARK: - update family membership
|
||||
|
||||
fileprivate func calculateTraitEntityIdHash(traitHash: FamilyTraitSetHash, entityIdx: EntityIndex) -> TraitEntityIdHash {
|
||||
return hash(combine: traitHash, entityIdx)
|
||||
}
|
||||
|
||||
func update(membership family: Family, for entityId: EntityIdentifier) {
|
||||
let entityIdx: EntityIndex = entityId.index
|
||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||
guard let componentIds: ComponentIdentifiers = componentIdsByEntity[entityIdx] else { return }
|
||||
// FIXME: bottle neck
|
||||
|
||||
let trash: TraitEntityIdHash = calculateTraitEntityIdHash(traitHash: traitHash, entityIdx: entityIdx)
|
||||
let is_Member: Bool = isMember(byHash: trash)
|
||||
|
||||
let componentsSet: ComponentSet = ComponentSet.init(componentIds)
|
||||
let isMember: Bool = family.isMember(entityId)
|
||||
let isMatch: Bool = family.traits.isMatch(components: componentsSet)
|
||||
switch (isMatch, isMember) {
|
||||
switch (isMatch, is_Member) {
|
||||
case (true, false):
|
||||
add(to: family, entityId: entityId)
|
||||
add(to: family, entityId: entityId, with: trash)
|
||||
case (false, true):
|
||||
remove(from: family, entityId: entityId)
|
||||
remove(from: family, entityId: entityId, with: trash)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func add(to family: Family, entityId: EntityIdentifier) {
|
||||
fileprivate func add(to family: Family, entityId: EntityIdentifier, with traitEntityIdHash: TraitEntityIdHash) {
|
||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||
|
||||
if familyMembersByTraitHash[traitHash] != nil {
|
||||
familyMembersByTraitHash[traitHash]?.insert(entityId)
|
||||
// here we already checked if entity is a member
|
||||
familyMembersByTraitHash[traitHash]!.append(entityId)
|
||||
} else {
|
||||
familyMembersByTraitHash[traitHash] = EntityIdSet(arrayLiteral: entityId)
|
||||
familyMembersByTraitHash[traitHash] = [EntityIdentifier].init(arrayLiteral: entityId)
|
||||
familyMembersByTraitHash.reserveCapacity(4096)
|
||||
}
|
||||
|
||||
familyContainsEntityId[traitEntityIdHash] = true
|
||||
|
||||
notify(FamilyMemberAdded(member: entityId, to: family.traits))
|
||||
}
|
||||
|
||||
fileprivate func remove(from family: Family, entityId: EntityIdentifier) {
|
||||
fileprivate func remove(from family: Family, entityId: EntityIdentifier, with traitEntityIdHash: TraitEntityIdHash) {
|
||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||
|
||||
guard let removed: EntityIdentifier = familyMembersByTraitHash[traitHash]?.remove(entityId) else {
|
||||
// FIXME: index of is not cheep
|
||||
guard let indexInFamily = familyMembersByTraitHash[traitHash]?.index(of: entityId) else {
|
||||
assert(false, "removing entity id \(entityId) that is not in family \(family)")
|
||||
report("removing entity id \(entityId) that is not in family \(family)")
|
||||
return
|
||||
}
|
||||
|
||||
let removed: EntityIdentifier = familyMembersByTraitHash[traitHash]!.remove(at: indexInFamily)
|
||||
familyContainsEntityId[traitEntityIdHash] = false
|
||||
notify(FamilyMemberRemoved(member: removed, from: family.traits))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ public class Nexus {
|
|||
var freeEntities: ContiguousArray<EntityIdentifier>
|
||||
|
||||
var familiyByTraitHash: [FamilyTraitSetHash: Family]
|
||||
var familyMembersByTraitHash: [FamilyTraitSetHash: EntityIdSet]
|
||||
var familyMembersByTraitHash: [FamilyTraitSetHash: [EntityIdentifier]]
|
||||
var familyContainsEntityId: [TraitEntityIdHash: Bool]
|
||||
|
||||
public init() {
|
||||
entities = Entities()
|
||||
|
|
@ -52,6 +53,7 @@ public class Nexus {
|
|||
freeEntities = ContiguousArray<EntityIdentifier>()
|
||||
familiyByTraitHash = [:]
|
||||
familyMembersByTraitHash = [:]
|
||||
familyContainsEntityId = [:]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// Profiler.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 28.10.17.
|
||||
//
|
||||
|
||||
struct Profiler {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Timer.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 28.10.17.
|
||||
//
|
||||
|
||||
import Darwin.Mach.mach_time
|
||||
|
||||
struct Timer {
|
||||
private let numerator: UInt64
|
||||
private let denominator: UInt64
|
||||
private var startTime: UInt64 = 0
|
||||
private var stopTime: UInt64 = 0
|
||||
|
||||
init() {
|
||||
var timeBaseInfo = mach_timebase_info.init(numer: 0, denom: 0 )
|
||||
let success: kern_return_t = mach_timebase_info(&timeBaseInfo)
|
||||
assert(KERN_SUCCESS == success)
|
||||
numerator = UInt64(timeBaseInfo.numer)
|
||||
denominator = UInt64(timeBaseInfo.denom)
|
||||
}
|
||||
|
||||
mutating func start() {
|
||||
startTime = mach_absolute_time()
|
||||
}
|
||||
mutating func stop() {
|
||||
stopTime = mach_absolute_time()
|
||||
}
|
||||
mutating func reset() {
|
||||
startTime = 0
|
||||
stopTime = 0
|
||||
}
|
||||
|
||||
var nanoSeconds: UInt64 {
|
||||
return ((stopTime - startTime) * numerator) / denominator
|
||||
}
|
||||
|
||||
var microSeconds: Double {
|
||||
return Double(nanoSeconds) / 1.0e3
|
||||
}
|
||||
|
||||
var milliSeconds: Double {
|
||||
return Double(nanoSeconds) / 1.0e6
|
||||
}
|
||||
|
||||
var seconds: Double {
|
||||
return Double(nanoSeconds) / 1.0e9
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
import CSDL2
|
||||
import FirebladeECS
|
||||
|
||||
if SDL_Init(SDL_INIT_VIDEO) != 0 {
|
||||
fatalError("could not init video")
|
||||
}
|
||||
let width: Int32 = 640
|
||||
let height: Int32 = 480
|
||||
let hWin = SDL_CreateWindow("Fireblade ECS demo", 100, 100, width, height, SDL_WINDOW_SHOWN.rawValue)
|
||||
if hWin == nil {
|
||||
SDL_Quit()
|
||||
fatalError("could not crate window")
|
||||
}
|
||||
|
||||
func randNorm() -> Double {
|
||||
return Double(arc4random()) / Double(UInt32.max)
|
||||
}
|
||||
|
||||
// won't produce pure black
|
||||
func randColor() -> UInt8 {
|
||||
return UInt8(randNorm() * 254) + 1
|
||||
}
|
||||
|
||||
let nexus = Nexus()
|
||||
|
||||
class Position: Component {
|
||||
var x: Int32 = width/2
|
||||
var y: Int32 = height/2
|
||||
}
|
||||
class Color: Component {
|
||||
var r: UInt8 = randColor()
|
||||
var g: UInt8 = randColor()
|
||||
var b: UInt8 = randColor()
|
||||
}
|
||||
|
||||
func createScene() {
|
||||
|
||||
let numEntities: Int = 10_000
|
||||
|
||||
for i in 0..<numEntities {
|
||||
let e = nexus.create(entity: "\(i)")
|
||||
e.assign(Position())
|
||||
e.assign(Color())
|
||||
}
|
||||
}
|
||||
|
||||
class PositionSystem {
|
||||
let family = nexus.family(requiresAll: [Position.self], excludesAll: [])
|
||||
var acceleration: Double = 4.0
|
||||
func update() {
|
||||
family.iterate(components: Position.self) { [unowned self](_, pos) in
|
||||
|
||||
let deltaX: Double = self.acceleration*((randNorm() * 2) - 1)
|
||||
let deltaY: Double = self.acceleration*((randNorm() * 2) - 1)
|
||||
var x = pos!.x + Int32(deltaX)
|
||||
var y = pos!.y + Int32(deltaY)
|
||||
|
||||
if x < 0 || x > width {
|
||||
x = -x
|
||||
}
|
||||
if y < 0 || y > height {
|
||||
y = -y
|
||||
}
|
||||
|
||||
pos!.x = x
|
||||
pos!.y = y
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PositionResetSystem {
|
||||
let family = nexus.family(requiresAll: [Position.self], excludesAll: [])
|
||||
|
||||
func update() {
|
||||
family.iterate(components: Position.self) { (_, pos) in
|
||||
pos!.x = width/2
|
||||
pos!.y = height/2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ColorSystem {
|
||||
let family = nexus.family(requiresAll: [Color.self], excludesAll: [])
|
||||
|
||||
func update() {
|
||||
family.iterate(components: Color.self) { (_, color) in
|
||||
|
||||
color!.r = randColor()
|
||||
color!.g = randColor()
|
||||
color!.b = randColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RenderSystem {
|
||||
let hRenderer: OpaquePointer?
|
||||
let family = nexus.family(requiresAll: [Position.self, Color.self], excludesAll: [])
|
||||
|
||||
init(hWin: OpaquePointer?) {
|
||||
hRenderer = SDL_CreateRenderer(hWin, -1, SDL_RENDERER_ACCELERATED.rawValue)
|
||||
if hRenderer == nil {
|
||||
SDL_DestroyWindow(hWin)
|
||||
SDL_Quit()
|
||||
fatalError("could not create renderer")
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
SDL_DestroyRenderer(hRenderer)
|
||||
}
|
||||
|
||||
func render() {
|
||||
|
||||
SDL_SetRenderDrawColor( hRenderer, 0, 0, 0, 255 ) // black
|
||||
SDL_RenderClear(hRenderer) // clear screen
|
||||
|
||||
family.iterate(components: Position.self, Color.self) { [unowned self] (_, pos, color) in
|
||||
var rect = SDL_Rect(x: pos!.x, y: pos!.y, w: 2, h: 2)
|
||||
|
||||
SDL_SetRenderDrawColor(self.hRenderer, color!.r, color!.g, color!.b, 255)
|
||||
SDL_RenderFillRect(self.hRenderer, &rect)
|
||||
}
|
||||
|
||||
SDL_RenderPresent(hRenderer)
|
||||
}
|
||||
}
|
||||
let positionSystem = PositionSystem()
|
||||
let positionResetSystem = PositionResetSystem()
|
||||
let renderSystem = RenderSystem(hWin: hWin)
|
||||
let colorSystem = ColorSystem()
|
||||
|
||||
createScene()
|
||||
|
||||
var event: SDL_Event = SDL_Event()
|
||||
var quit: Bool = false
|
||||
while quit == false {
|
||||
while SDL_PollEvent(&event) == 1 {
|
||||
switch SDL_EventType(rawValue: event.type) {
|
||||
case SDL_QUIT:
|
||||
quit = true
|
||||
break
|
||||
case SDL_KEYDOWN:
|
||||
switch Int(event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
quit = true
|
||||
break
|
||||
case SDLK_c:
|
||||
colorSystem.update()
|
||||
case SDLK_r:
|
||||
positionResetSystem.update()
|
||||
case SDLK_s:
|
||||
positionSystem.acceleration = 0.0
|
||||
case SDLK_PLUS:
|
||||
positionSystem.acceleration += 0.1
|
||||
case SDLK_MINUS:
|
||||
positionSystem.acceleration -= 0.1
|
||||
case SDLK_SPACE:
|
||||
positionSystem.acceleration = 4.0
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
positionSystem.update()
|
||||
|
||||
renderSystem.render()
|
||||
}
|
||||
|
||||
SDL_DestroyWindow(hWin)
|
||||
SDL_Quit()
|
||||
Loading…
Reference in New Issue