Last active
December 17, 2015 11:39
-
-
Save fowlmouth/5603457 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fowltek/entitty, fowltek/sdl2/engine | |
entitty_imports | |
import_all_sdl2_modules | |
import fowltek/vector_math | |
type TVector2f* = TVector2[float] | |
proc getPos* : TVector2f {.unicast.} | |
proc update* (dt: float) {.multicast.} | |
proc draw* (R: PRenderer) {.unicast.} | |
proc debugDraw* (R: PRenderer) {.multicast.} | |
proc handleEvent* (X: var TEvent): bool {.unicast.} | |
proc accelerate* {.unicast.} | |
proc rev_accel* {.unicast.} | |
proc debugStrCollect* (result: var seq[string]) {.multicast.} | |
template debugStrImpl*(ty; body: stmt): stmt {.immediate.} = | |
msg_impl(ty, "debugStrCollect") do (result: var seq[string]): | |
body | |
proc debugStr*(E: PEntity): seq[string] = | |
result = @[] | |
E.debugStrCollect result | |
type Pos* = TVector2f | |
msg_impl(Pos, getPos) do -> TVector2f: entity[Pos] | |
type Velocity* = object | |
vec: TVector2f | |
Velocity.requiresComponent Pos | |
msg_impl(Velocity, update) do (dt: float): | |
entity[Pos] += entity[Velocity].vec * dt | |
entity[Velocity].vec *= 0.99 | |
msg_impl(Velocity, debugDraw) do(R: PRenderer): | |
let p = entity[Pos].addr | |
let v = entity[Velocity].vec.addr | |
R.lineRGBA p.x.int16, p.y.int16, | |
(p.x + v.x).int16, (p.y + v.y).int16, | |
0,255,0,255 | |
type Circle* = object | |
radius: float | |
Circle.requiresComponent Pos | |
Circle.setInitializer proc(x: PEntity) = x[Circle].radius = 10.0 | |
proc debugDraw_circ (some: PEntity; R: PRenderer) = | |
let pos = some[Pos].addr | |
R.circleRGBA pos.x.int16, pos.y.int16, some[Circle].radius.int16, 255,0,0,255 | |
Circle.addMulticastMsg "debugDraw", debugDraw_circ | |
msg_impl(Circle, draw) do (R: PRenderer): | |
let pos = entity[Pos].addr | |
R.circleRGBA pos.x.int16, pos.y.int16, entity[Circle].radius.int16, 255,0,0,255 | |
type Orientation* = object | |
angle_radians: float | |
proc turnRight* {.unicast.} | |
proc turnLeft* {.unicast.} | |
msg_impl(Orientation, "turnRight") do : | |
entity[Orientation].angle_radians -= 0.1 | |
msg_impl(Orientation, "turnLeft") do : | |
entity[Orientation].angle_radians += 0.1 | |
msg_impl(Orientation, debugDraw) do (R: PRenderer) : | |
if entity.hasComponent(Pos): | |
var offs = vectorForAngle(entity[Orientation].angle_radians) | |
if entity.hasComponent(Circle): | |
offs *= entity[Circle].radius | |
let p = entity[Pos].addr | |
R.lineRGBA p.x.int16, p.y.int16, | |
(p.x + offs.x).int16, (p.y + offs.y).int16, | |
255,0,0,255 | |
type Acceleration* = object | |
vec: TVector2f | |
Acceleration.requiresComponent Velocity, Orientation | |
msg_impl(Acceleration, update) do (dt: float): | |
entity[Velocity].vec += entity[Acceleration].vec | |
entity[Acceleration].reset | |
msg_impl(Acceleration, accelerate) do : | |
entity[Acceleration].vec += entity[Orientation].angle_radians.vectorForAngle * 10.0 | |
msg_impl(Acceleration, rev_accel) do : | |
entity[Acceleration].vec += entity[Orientation].angle_radians.vectorForAngle * -10.0 | |
type | |
InputState* = object | |
accel: TAccel | |
turning: TTurn | |
TInputKind* = enum Pressed, Released | |
TAccel* = enum AccelIdle, AccelForward, AccelReverse | |
TTurn* = enum NoTurn, RightTurn, LeftTurn | |
proc setTurning*(dir: TTurn; pressed: TInputKind) {.unicast.} | |
proc setAccel*(acc: TAccel; pressed: TInputKind){.unicast.} | |
debugStrImpl(InputState): | |
result.add ($entity[InputState]) | |
msg_impl(InputState, setAccel) do (acc: TAccel; kind: TInputKind): | |
case kind | |
of Pressed: | |
entity[InputState].accel = acc | |
else: | |
if acc == entity[InputState].accel: | |
entity[InputState].accel = AccelIdle | |
msg_impl(InputState, setTurning) do(dir: TTurn; kind: TInputKind): | |
case Kind | |
of Pressed: | |
entity[InputState].turning = dir | |
else: | |
if dir == entity[InputState].turning: | |
entity[InputState].turning = NoTurn | |
msg_impl(InputState, update) do (dt: float): | |
case entity[InputState].accel | |
of AccelForward: entity.accelerate() | |
of AccelReverse: entity.rev_accel() | |
else: nil | |
case entity[InputState].turning | |
of RightTurn: entity.turnRight | |
of LeftTurn: entity.turnLeft | |
else: nil | |
type | |
THIDCallback = proc(E: PEntity; X: var sdl2.TEvent): bool | |
HID_Controller* = object | |
cb: THIDCallback | |
connected: bool | |
HID_Controller.requiresComponent InputState | |
proc hid_nop(E: PEntity; X: var sdl2.TEvent): bool = false | |
HID_Controller.setInitializer proc(x: PEntity) = | |
x[HID_Controller].cb = hid_nop | |
x[HID_Controller].connected = false | |
msg_impl(HID_Controller, handleEvent) do (event: var sdl2.TEvent) -> bool: | |
if entity[HID_Controller].connected: return entity[HID_Controller].cb(entity, event) | |
import unsigned | |
proc hid_keyboard_handler (entity: PEntity; evt: var sdl2.TEvent): bool = | |
case evt.kind | |
of keyDown, keyUP: | |
let k = evKeyboard(evt) | |
if k.repeat != 0'u8: return | |
var p = (if k.kind == keyUp: Released else: Pressed) | |
result = true | |
case k.keysym.sym | |
of K_UP: | |
entity.setAccel AccelForward, p | |
of K_DOWN: | |
entity.setAccel AccelReverse, p | |
of K_LEFT: | |
entity.setTurning LeftTurn, p | |
of K_RIGHT: | |
entity.setTurning RightTurn, p | |
else: result = false | |
else:nil | |
proc setupKeyboard*(x: var HID_Controller) = | |
x.cb = hid_keyboard_handler | |
x.connected = true | |
type # Keeps an entity within a boundary | |
Bounded = object | |
rect: sdl2.TRect | |
checkEnt: proc(entity: PEntity; bounds: var Bounded) | |
#defcomponent Bounded | |
Bounded.requiresComponent Pos, Velocity | |
proc right*(some: ptr TRect): cint {.inline.} = some.x + some.w | |
proc bottom*(some: ptr TRect): cint {.inline.} = some.y + some.h | |
proc newBounded(x, y, w, h: int): Bounded = | |
result.rect = rect(x.cint, y.cint, w.cint, h.cint) | |
proc setToroidal(bounds: var Bounded) = | |
bounds.checkEnt = proc(entity: PEntity; bounds: var Bounded) = | |
let pos = entity[Pos].addr | |
let bounds = bounds.rect.addr | |
if pos.x.cint < bounds.x: | |
pos.x = bounds.right.float | |
elif pos.x.cint > bounds.right: | |
pos.x = bounds.x.float | |
if pos.y.cint < bounds.y: | |
pos.y = bounds.bottom.float | |
elif pos.y.cint > bounds.bottom: | |
pos.y = bounds.y.float | |
proc toroidalBounds(x, y, w, h: int): Bounded = | |
result = newBounded(x,y,w,h) | |
result.setToroidal | |
proc setBouncy(bounds: var Bounded) = | |
bounds.checkEnt = proc(entity: PEntity; bounds: var Bounded) = | |
let pos = entity[Pos].addr | |
let vel = entity[Velocity].vec.addr | |
let bounds = bounds.rect.addr | |
template flipReset(field, toVal): stmt = | |
pos.field = toVal | |
vel.field = - vel.field | |
if pos.x.cint < bounds.x: | |
flipReset(x, bounds.x.float) | |
elif pos.x.cint > bounds.right: | |
flipReset(x, bounds.right.float) | |
if pos.y.cint < bounds.y: | |
flipReset(y, bounds.y.float) | |
elif pos.y.cint > bounds.bottom: | |
flipReset(y, bounds.bottom.float) # """ | |
proc bouncyBounds(x, y, w, h: int): Bounded = | |
result = newBounded(x, y, w, h) | |
result.setBouncy | |
Bounded.setInitializer proc(x: PEntity) = x[Bounded].setToroidal() | |
msg_impl(Bounded, update) do(dt: float): | |
entity[Bounded].checkEnt entity, entity[Bounded] | |
import fowltek/idgen | |
var idg = newIDGen[int]() | |
assert idg.get == 0 #waste the first id, yes on purpose | |
var engy = newSdlEngine() | |
var em = newEntityManager() | |
var ents = newSeq[TEntity](0) | |
var connected_HIDs = newSeq[int]() | |
proc add_entity* (e: TEntity): int = | |
let id = idg.get | |
ents.ensureLen id+1 | |
ents[id] = e | |
ents[id].userdata = cast[pointer](id) #teehee | |
return id | |
proc del_entity* (e_id: int): int = | |
destroy ents[e_id] | |
ents[e_id].userdata = nil | |
idg.release e_id | |
proc connectKeyboard(e: PEntity) = | |
assert e.hasComponent(HID_Controller) | |
e[HID_Controller].setupKeyboard | |
connected_HIDs.add cast[int](e.userData) | |
echo repr(connected_HIDS) | |
proc id* (E: PEntity): int{.inline.} = cast[int](E.userdata) | |
template eachEntity(body: stmt): stmt {.immediate,dirty.}= | |
for e_id{.inject.} in 1.. <ents.len: | |
template entity: expr = ents[e_id] | |
if ents[e_id].id != -1: body | |
block: | |
var e1 = em.newEntity(Pos, Acceleration, Velocity, Circle, Orientation, | |
InputState, HID_Controller, Bounded) | |
e1[Pos].x = 100 | |
e1[Pos].y = 100 | |
e1[Circle].radius = 6.0 | |
var e1_id = add_entity(e1) | |
ents[e1_id].connectKeyboard | |
var running = true | |
var dt: float | |
while running: | |
while engy.pollHandle: | |
case engy.evt.kind | |
of QuitEvent: running = false | |
of MouseMotion: | |
let m = evMouseMOtion(engy.evt) | |
of KeyDown, KeyUP: | |
block key_handled: | |
for ID in 0 .. < connectedHIDs.len: | |
if ents[connectedHIDS[ID]].handleEvent(engy.evt): | |
#echo "event handled. breaking." | |
break key_handled | |
if evKeyboard(engy.evt).keysym.sym == K_Escape: | |
running = false | |
else: nil | |
dt = engy.frameDeltaFlt | |
eachEntity: | |
entity.update dt | |
engy.setDrawColor 0,0,0,255 | |
engy.clear | |
#for e_id in 0 .. < ents.len: ents[e_id].draw engy | |
eachEntity: | |
entity.debugdraw engy | |
engy.MLstringRGBA 10, 10, ents[1].debugStr, 0,255,0,255 | |
engy.present | |
engy.destroy | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment