Last active
August 29, 2015 14:21
-
-
Save PhilipWitte/2d167c888f95e67f0292 to your computer and use it in GitHub Desktop.
GameObject Container Concept
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 macros | |
# --- | |
type | |
GameObj[T] = ref object | |
props: T | |
alive: bool | |
macro new(T:typeDesc, args:varArgs[expr]): expr = | |
## allocates a GameObj[T] and setup it properties | |
# compose constructor AST | |
let item = genSym(nskLet, "item") | |
let ctor = newCall("setup", newDotExpr(item, ident"props")) | |
for arg in args.children: | |
ctor.add arg | |
# compose final expression AST | |
let info = result.lineInfo | |
result = quote do: | |
# allocate item & properties | |
let `item` = GameObj[`T`]( | |
alive: true, | |
props: `T`() | |
) | |
# setup item properties | |
when compiles(`ctor`): | |
`ctor` | |
else: | |
quit `info` & ": Error: Invalid Params" | |
# return item | |
`item` | |
# for debugging | |
echo result.repr | |
# access through `.` and `.=` operators | |
macro `.`(me:GameObj, propName:string): untyped = | |
newDotExpr( | |
newDotExpr(me, ident"props"), | |
newIdentNode(propName.strVal)) | |
macro `.=`(me:GameObj, propName:string, assignment:typed): untyped = | |
newNimNode(nnkAsgn).add( | |
newDotExpr( | |
newDotExpr(me, ident"props"), | |
newIdentNode(propName.strVal)), | |
assignment) | |
# or backward access via pointer arithmetic | |
proc kill[T](item:var T) = | |
static: | |
# example validation code... | |
const registeredGameObjs = ["Ship", "Enemy", "Etc.."] # gathered from code | |
assert registeredGameObjs.contains repr T | |
# if valid GameObj type, we can safely step-forward to get alive | |
cast[ptr bool](cast[int](addr item) + sizeof T)[] = false | |
# --- ---- --- # | |
# --- test --- # | |
# --- ---- --- # | |
type | |
Ship = object | |
name: string | |
x, y: int | |
var | |
command = "" | |
proc setup(me:var Ship, name:string, x, y:int) = | |
me.name = name | |
me.x = x | |
me.y = y | |
proc update(me:var Ship) = | |
if command == me.name: | |
kill me # set GameObj's `alive` from Ship var | |
proc render(me:Ship) = | |
echo me.name, ": ", me.x, ", ", me.y | |
# --- | |
var gameObjs = @[ | |
Ship.new("luke", 1, 2), | |
Ship.new("leia", 3, 4), | |
Ship.new("solo", 5, 6), | |
Ship.new("yoda", 9, 0), | |
Ship.new("vader", 7, 8)] | |
proc update = | |
## updates all GameObjs and removes any dead ones | |
var i = 0 | |
while i < gameObjs.len: | |
let obj = gameObjs[i] | |
# update user scrips | |
obj.props.update() | |
# inteligently continue | |
if not obj.alive: | |
gameObjs.del(i) | |
else: | |
inc i | |
proc render = | |
## renders all GameObjs | |
if gameObjs.len > 0: | |
echo "--- Objects:\n " | |
for obj in gameObjs: | |
stdout.write(" - ") | |
obj.props.render() | |
echo "" | |
proc run = | |
# start game | |
echo "--- Game Start ---" | |
render() | |
# game loop | |
while gameObjs.len > 0: | |
# query user | |
echo "Who should I kill?" | |
# buffer input | |
command = readLine(stdin) | |
if command == "": | |
break | |
# progress game | |
update() | |
render() | |
echo "--- Game Done ---" | |
# --- | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment