Skip to content

Instantly share code, notes, and snippets.

@PhilipWitte
Last active August 29, 2015 14:21
Show Gist options
  • Save PhilipWitte/2d167c888f95e67f0292 to your computer and use it in GitHub Desktop.
Save PhilipWitte/2d167c888f95e67f0292 to your computer and use it in GitHub Desktop.
GameObject Container Concept
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