Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ###############################################
- # An example of using Python decorators to
- # build an Entity-Component system.
- # Here be dragons.
- # @eigenbom 10/2016
- ###############################################
- import copy
- from enum import Enum
- from functools import wraps
- ###########################
- # Base entity
- ###########################
- class Entity(object):
- """Generic entity class"""
- def __init__(self, name=None, *args, **kwargs):
- self.components = list()
- self.lazy_init = dict()
- # Common
- self.name = name
- # Passed args override defaults
- self.__dict__.update(*args)
- self.__dict__.update(**kwargs)
- def __str__(self):
- components = [c.__name__ for c in self.components]
- res = '"%s"'%self.name
- res += " ["
- for i, c in enumerate(self.components):
- res += c.__name__ + (" " if i != len(self.components)-1 else "")
- res += "]\n"
- for k, v in sorted(self.__dict__.items()):
- if k in ["name", "components", "lazy_init"]: continue
- res += " %s: %s\n"%(k,v)
- return res
- def merge_entities(one, other):
- """Merge two entities"""
- e = copy.deepcopy(one)
- e.components.extend(other.components)
- for k,v in other.__dict__.items():
- if k in ["components"]: continue
- if k not in e.__dict__:
- e.__dict__[k] = v
- elif isinstance(e.__dict__[k], list):
- e.__dict__[k].extend(v)
- elif isinstance(e.__dict__[k], dict):
- e.__dict__[k].update(v)
- else:
- # TODO: intelligently merge conflicting vars? (give vars a priority?)
- pass
- return e
- ###########################
- # Decorators
- ###########################
- def entity(func):
- """(Decorator) Creates an entity from a factory function"""
- @wraps(func)
- def func_wrapper(*args, **kwargs):
- e = Entity(*args, **kwargs)
- if e.name is None:
- # Name defaults to factory function name
- e.name = func.__name__
- e.lazy_init.update(func(**kwargs))
- return e
- return func_wrapper
- def inherits(factory, **kwargsfactory):
- """(Decorator) Uses an existing factory function to create an entity."""
- def wrapper(func):
- @wraps(func)
- def func_wrapper(*args, **kwargs):
- e = factory(*args, **kwargs, **kwargsfactory)
- res = func(**kwargs, **kwargsfactory)
- if isinstance(res, Entity):
- e = merge_entities(e, res)
- e.__dict__.update(e.lazy_init)
- else:
- e.lazy_init.update(res)
- e.__dict__.update(e.lazy_init)
- return e
- return func_wrapper
- return wrapper
- def component(f, **kwargs):
- """(Decorator) Adds a component (function) to an entity"""
- def decorator(func):
- @wraps(func)
- def func_wrapper(*args, **kwargs2):
- e = func(*args, **kwargs2)
- e.components.append(f)
- e = f(e, **kwargs)
- e.__dict__.update(e.lazy_init)
- return e
- return func_wrapper
- return decorator
- ###########################
- # Components
- ###########################
- def info(e, tooltip=None, description=None):
- """(Component) Holds basic information about an entity."""
- # Merge multiple tooltips
- e.tooltip = e.__dict__.get("tooltip", "") + " " + tooltip
- e.description = description
- return e
- def decay(e, rate=1):
- """(Component) Decays an object over time."""
- e.health = 1
- e.decaying = True
- e.decay_rate = rate
- # (Then we'd add a function that actually does the decay)
- # e.g., e.add_handler(...)
- return e
- Mob = Enum('Mob', 'humanoid flying')
- def mob(e, type=None, types=None):
- """(Component) Is a Mob."""
- e.mob = True
- mob_types = e.__dict__.get("mob_types", [])
- if types:
- mob_types.extend(types)
- if type:
- mob_types.append(types)
- e.mob_types = mob_types
- return e
- ###########################
- # Factories / Prefabs
- ###########################
- Material = Enum('Material', 'uranium silver jelly etc')
- @component(info, tooltip="It glows.")
- @component(decay, rate=2)
- @entity
- def uranium(**kwargs):
- return dict(
- material=Material.uranium,
- health=10
- )
- @component(mob, type=Mob.humanoid)
- @entity
- def human(**kwargs):
- return dict (
- health = 10
- )
- @component(info, tooltip="Up and Atom!")
- @inherits(uranium)
- @inherits(human, mob_types=[Mob.humanoid, Mob.flying])
- def radioactive_man(**kwargs):
- return dict (
- health = 50
- )
- def example():
- world = [
- uranium(name="Nuclear Pile"),
- human(name="Ben"),
- radioactive_man(name="Captain Atom")
- ]
- for e in world:
- print(e)
- if __name__ == "__main__":
- example()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement