Thank you very much, dawkot. So I've ended up with something like this
    
    
    import macros
    import strutils
    import strformat
    export actors
    
    
    ############################
    ### Entities
    ############################
    
    type
      ent* = object
        id*: int
        age*: uint8
    
    var
      entStash = newSeqOfCap[ent](256)
    
    proc newEntity*(): ent =
      var id_last {.global.} = 1
      if entStash.len > 0:
        result.id = entStash[0].id
        result.age = entStash[0].age+1
        entStash.del(0)
      else:
        let id = id_last
        id_last += 1
        result.id = id
        result.age = 0
    
    proc release*(entity: ent) =
      add(entStash, entity)
    
    
    ##############################
    ### Components
    ##############################
    
    type Storage[T] = seq[T]
    
    
    proc newStorage[T](size: int): seq[T] = newSeq[T](size)
    proc components[T](x: var seq[T]): var seq[T] = x
    
    macro getComponentPretty(t: untyped): untyped =
      let tName = $NimNode(t) # name of the component
      let pragma = "{.inline.}"
      let source = fmt("""
      proc {toLowerAscii(tName[..0]) & tName[1..tName.high]}(self: ent): ptr 
{tName} {pragma} =
         self.getComponent {tName} """)
      result = parseStmt(source)
    
    
    template reg(t: typedesc, size = 256) =
      
      var storage {.used.} = newStorage[t]size
      
      proc getStorage(_: typedesc[t]): var Storage[t] {.inline.} =
        storage
      
      proc getComponent(self: ent, _: typedesc[t]): ptr t {.inline.} =
        addr storage.components[self.id]
      
      getComponentPretty(t)
    
    
    type
      ComponentMotion = object
        x, y: float
      ComponentObject = object
        name: string
    
    
    reg ComponentMotion
    reg ComponentObject
    
    
    var entity = newEntity()
    
    var cMotion = entity.componentMotion
    var cObject = entity.componentObject
    
    cMotion.x = 20
    cObject.name = "Pixeye"
    
    echo getStorage(ComponentMotion)[1].x
    
    
    Run

It wasn't easy to understand all that template/macros magic... if there is any 
more elegant way of doing the code below?
    
    
    macro getComponentPretty(t: untyped): untyped =
      let tName = $NimNode(t) # name of the component
      let pragma = "{.inline.}"
      let source = fmt("""
      proc {toLowerAscii(tName[..0]) & tName[1..tName.high]}(self: ent): ptr 
{tName} {pragma} =
         self.getComponent {tName} """)
      result = parseStmt(source)
    
    
    template reg(t: typedesc, size = 256) =
      
      var storage {.used.} = newStorage[t]size
      
      proc getStorage(_: typedesc[t]): var Storage[t] {.inline.} =
        storage
      
      proc getComponent(self: ent, _: typedesc[t]): ptr t {.inline.} =
        addr storage.components[self.id]
      
      getComponentPretty(t)
    
    
    Run

The reason why I need getComponentPretty() is to take components from storage 
in a pretty way like this:
    
    
    var cMotion = entity.componentMotion
    var cObject = entity.componentObject
    
    
    Run

instead of this 
    
    
    var cMotion = en.getComponent(ComponentMotion).x = 10
    var cObject = en.getComponent(componentObject).x = 10
    
    
    Run

Please excuse if my code is naive, I'm learning : )

Reply via email to