comparison bGrease/component/general.py @ 65:e856b604b650

Changed "import bGrease" to "import parpg.bGrease".
author KarstenBock@gmx.net
date Wed, 21 Sep 2011 16:10:14 +0200
parents ff3e395abf91
children
comparison
equal deleted inserted replaced
64:b73050f98411 65:e856b604b650
11 # 11 #
12 ############################################################################# 12 #############################################################################
13 13
14 __version__ = '$Id$' 14 __version__ = '$Id$'
15 15
16 from bGrease.component import base 16 from parpg.bGrease.component import base
17 from bGrease.component import field 17 from parpg.bGrease.component import field
18 from bGrease.entity import ComponentEntitySet 18 from parpg.bGrease.entity import ComponentEntitySet
19 19
20 20
21 class Component(dict): 21 class Component(dict):
22 """General component with a configurable schema 22 """General component with a configurable schema
23 23
24 The field schema is defined via keyword args where the 24 The field schema is defined via keyword args where the
25 arg name is the field name and the value is the type object. 25 arg name is the field name and the value is the type object.
26 26
27 The following types are supported for fields: 27 The following types are supported for fields:
28 28
29 - :class:`int` 29 - :class:`int`
30 - :class:`float` 30 - :class:`float`
31 - :class:`bool` 31 - :class:`bool`
32 - :class:`str` 32 - :class:`str`
33 - :class:`object` 33 - :class:`object`
34 - |Vec2d| 34 - |Vec2d|
35 - |Vec2dArray| 35 - |Vec2dArray|
36 - |RGBA| 36 - |RGBA|
37 - |Rect| 37 - |Rect|
38 """ 38 """
39 39
40 deleted_entities = () 40 deleted_entities = ()
41 """List of entities deleted from the component since the last time step""" 41 """List of entities deleted from the component since the last time step"""
42 42
43 new_entities = () 43 new_entities = ()
44 """List of entities added to the component since the last time step""" 44 """List of entities added to the component since the last time step"""
45 45
46 def __init__(self, **fields): 46 def __init__(self, **fields):
47 self.fields = {} 47 self.fields = {}
48 for fname, ftype in fields.items(): 48 for fname, ftype in fields.items():
49 assert ftype in field.types, fname + " has an illegal field type" 49 assert ftype in field.types, fname + " has an illegal field type"
50 self.fields[fname] = field.Field(self, fname, ftype) 50 self.fields[fname] = field.Field(self, fname, ftype)
51 self.entities = ComponentEntitySet(self) 51 self.entities = ComponentEntitySet(self)
52 self._added = [] 52 self._added = []
53 self._deleted = [] 53 self._deleted = []
54
55 def set_world(self, world):
56 self.world = world
57
58 def step(self, dt):
59 """Update the component for the next timestep"""
60 delitem = super(Component, self).__delitem__
61 for entity in self._deleted:
62 delitem(entity)
63 self.new_entities = self._added
64 self.deleted_entities = self._deleted
65 self._added = []
66 self._deleted = []
67
68 def set(self, entity, data=None, **data_kw):
69 """Set the component data for an entity, adding it to the
70 component if it is not already a member.
71 54
72 If data is specified, its data for the new entity's fields are 55 def set_world(self, world):
73 copied from its attributes, making it easy to copy another 56 self.world = world
74 entity's data. Keyword arguments are also matched to fields.
75 If both a data attribute and keyword argument are supplied for
76 a single field, the keyword arg is used.
77 """
78 if data is not None:
79 for fname, field in self.fields.items():
80 if fname not in data_kw and hasattr(data, fname):
81 data_kw[fname] = getattr(data, fname)
82 data = self[entity] = Data(self.fields, entity, **data_kw)
83 return data
84
85 def __setitem__(self, entity, data):
86 assert entity.world is self.world, "Entity not in component's world"
87 if entity not in self.entities:
88 self._added.append(entity)
89 self.entities.add(entity)
90 super(Component, self).__setitem__(entity, data)
91
92 def remove(self, entity):
93 if entity in self.entities:
94 self._deleted.append(entity)
95 self.entities.remove(entity)
96 return True
97 return False
98
99 __delitem__ = remove
100 57
101 def __repr__(self): 58 def step(self, dt):
102 return '<%s %x of %r>' % ( 59 """Update the component for the next timestep"""
103 self.__class__.__name__, id(self), getattr(self, 'world', None)) 60 delitem = super(Component, self).__delitem__
61 for entity in self._deleted:
62 delitem(entity)
63 self.new_entities = self._added
64 self.deleted_entities = self._deleted
65 self._added = []
66 self._deleted = []
67
68 def set(self, entity, data=None, **data_kw):
69 """Set the component data for an entity, adding it to the
70 component if it is not already a member.
71
72 If data is specified, its data for the new entity's fields are
73 copied from its attributes, making it easy to copy another
74 entity's data. Keyword arguments are also matched to fields.
75 If both a data attribute and keyword argument are supplied for
76 a single field, the keyword arg is used.
77 """
78 if data is not None:
79 for fname, field in self.fields.items():
80 if fname not in data_kw and hasattr(data, fname):
81 data_kw[fname] = getattr(data, fname)
82 data = self[entity] = Data(self.fields, entity, **data_kw)
83 return data
84
85 def __setitem__(self, entity, data):
86 assert entity.world is self.world, "Entity not in component's world"
87 if entity not in self.entities:
88 self._added.append(entity)
89 self.entities.add(entity)
90 super(Component, self).__setitem__(entity, data)
91
92 def remove(self, entity):
93 if entity in self.entities:
94 self._deleted.append(entity)
95 self.entities.remove(entity)
96 return True
97 return False
98
99 __delitem__ = remove
100
101 def __repr__(self):
102 return '<%s %x of %r>' % (
103 self.__class__.__name__, id(self), getattr(self, 'world', None))
104 104
105 105
106 class Singleton(Component): 106 class Singleton(Component):
107 """Component that may contain only a single entity""" 107 """Component that may contain only a single entity"""
108 108
109 def add(self, entity_id, data=None, **data_kw): 109 def add(self, entity_id, data=None, **data_kw):
110 if entity_id not in self._data: 110 if entity_id not in self._data:
111 self.entity_id_set.clear() 111 self.entity_id_set.clear()
112 self._data.clear() 112 self._data.clear()
113 Component.add(self, entity_id, data, **data_kw) 113 Component.add(self, entity_id, data, **data_kw)
114 114
115 @property 115 @property
116 def entity(self): 116 def entity(self):
117 """Return the entity in the component, or None if empty""" 117 """Return the entity in the component, or None if empty"""
118 if self._data: 118 if self._data:
119 return self.manager[self._data.keys()[0]] 119 return self.manager[self._data.keys()[0]]
120 120
121 121
122 class Data(object): 122 class Data(object):
123 123
124 def __init__(self, fields, entity, **data): 124 def __init__(self, fields, entity, **data):
125 self.__dict__['_Data__fields'] = fields 125 self.__dict__['_Data__fields'] = fields
126 self.__dict__['entity'] = entity 126 self.__dict__['entity'] = entity
127 for field in fields.values(): 127 for field in fields.values():
128 if field.name in data: 128 if field.name in data:
129 setattr(self, field.name, data[field.name]) 129 setattr(self, field.name, data[field.name])
130 else: 130 else:
131 setattr(self, field.name, field.default()) 131 setattr(self, field.name, field.default())
132
133 def __setattr__(self, name, value):
134 if name in self.__fields:
135 self.__dict__[name] = self.__fields[name].cast(value)
136 else:
137 raise AttributeError("Invalid data field: " + name)
138
139 def __repr__(self):
140 return '<%s(%r)>' % (self.__class__.__name__, self.__dict__)
141 132
142 133 def __setattr__(self, name, value):
134 if name in self.__fields:
135 self.__dict__[name] = self.__fields[name].cast(value)
136 else:
137 raise AttributeError("Invalid data field: " + name)
143 138
139 def __repr__(self):
140 return '<%s(%r)>' % (self.__class__.__name__, self.__dict__)
141
142