Package: tcod-ec
AboutEntity/Component containers for implementing composition over inheritance.InstallationUse pip to install this library:pip install tcod-ecIftcodis installed and the version is less than14.0.0thenimport tcod.ecwill fail.
Remove or updatetcodto fix this issue.Examplestcod.ec.ComponentDictis a container for anonymous components all with a unique class.
The key is the class of the component and can only be assigned one instance of that class.>>>importattrs>>>importtcod.ec# Anonymous components don't need special treatment.>>>@attrs.define...classPosition:...x:int=0...y:int=0>>>@attrs.define...classGraphic:...ch:str="@"# ComponentDict stores a single instance for every unique class, in this case: [str, Position, Graphic]>>>entity=tcod.ec.ComponentDict(["Hello world",Position(1,2),Graphic("!")])>>>{Position,Graphic}inentity# Check if an entity has a set of components.True>>>entity[str]# Access components using the class as the key.'Hello world'>>>entity[Position].y=10>>>entity[Position]Position(x=1,y=10)>>>entity[Graphic]=Graphic("?")# Explicit setting of the component.>>>entityComponentDict(['Hello world',Position(x=1,y=10),Graphic(ch='?')])>>>entity.set(Graphic("#"))# Implicit setting.ComponentDict(['Hello world',Position(x=1,y=10),Graphic(ch='#')])>>>delentity[Graphic]# Components can be deleted.>>>entityComponentDict(['Hello world',Position(x=1,y=10)])# Abstract components can be registered with tcod.ec.abstract_component.>>>@tcod.ec.abstract_component...@attrs.define...classBase:...pass>>>@attrs.define...classDerived(Base):...pass>>>entity.set(Derived())# Derived classes may be set implicitly.ComponentDict(['Hello world',Position(x=1,y=10),Derived()])>>>entity[Base]=Derived()# Or explicitly assigned to the abstract key.>>>BaseinentityTrue>>>entity[Base]# Any derived classes use the base class as the key.Derived()>>>entityComponentDict(['Hello world',Position(x=1,y=10),Derived()])tcod.ec.Compositeis a collection of anonymous components.
UnlikeComponentDictthis can store multiple components with the same class.
Components can also be accessed using the parent class.
This works with multiple inheritance.While this class looks like an all around upgrade toComponentDictit's far more complex to work with.
The ways it mixes class inheritance with composition can lead to anti-patterns if used carelessly.
Any class used as a key will return zero, one, or more instances which must be accounted for.
If in doubt then the simplerComponentDictshould be used instead.>>>@attrs.define...classBody:...name:str...hp:int>>>entity=tcod.ec.Composite([Position(1,2),Graphic("!"),Body("torso",10),Body("head",5)])>>>{Position,Graphic,Body}inentityTrue>>>(pos,)=entity[Position]# Use unpacking logic to verify the number of elements.>>>pos.y=10>>>entity[Position][Position(x=1,y=10)]>>>entity[Graphic]=[Graphic("?")]# New sequences can be assigned, this deletes all previous instances of that key.>>>entity[Graphic][Graphic(ch='?')]>>>delentity[Graphic]>>>entity[Graphic]# Missing keys return an empty sequence instead of KeyError.()>>>entity[Body][Body(name='torso',hp=10),Body(name='head',hp=5)]>>>entity.extend([Body("legs",10),Body("arms",10)])# Use append or extend to add new instances.>>>forbodyinlist(entity[Body]):# Make a copy of the sequence if you intend to remove values during iteration....body.hp-=2...ifbody.name=="torso":...entity.remove(body)>>>entity[Body][Body(name='head',hp=3),Body(name='legs',hp=8),Body(name='arms',hp=8)]# All objects can be accessed at once using `object`.>>>entity[object][Position(x=1,y=10),Body(name='head',hp=3),Body(name='legs',hp=8),Body(name='arms',hp=8)]>>>entity[object]=("Hello","world")>>>entityComposite(['Hello','world'])