Mercurial > parpg-source
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 |