Mercurial > parpg-core
comparison src/parpg/bGrease/component/general.py @ 66:96af64cf3b81
Renamed grease to bGrease (Basic Grease) to get rid of conflicts with an already installed grease.
author | KarstenBock@gmx.net |
---|---|
date | Mon, 05 Sep 2011 15:00:34 +0200 |
parents | src/parpg/grease/component/general.py@09b581087d68 |
children | 0f659c7675f6 |
comparison
equal
deleted
inserted
replaced
65:765cb0c16f20 | 66:96af64cf3b81 |
---|---|
1 ############################################################################# | |
2 # | |
3 # Copyright (c) 2010 by Casey Duncan and contributors | |
4 # All Rights Reserved. | |
5 # | |
6 # This software is subject to the provisions of the MIT License | |
7 # A copy of the license should accompany this distribution. | |
8 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
9 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
10 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
11 # | |
12 ############################################################################# | |
13 | |
14 __version__ = '$Id$' | |
15 | |
16 from bGrease.component import base | |
17 from bGrease.component import field | |
18 from bGrease.entity import ComponentEntitySet | |
19 | |
20 | |
21 class Component(dict): | |
22 """General component with a configurable schema | |
23 | |
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. | |
26 | |
27 The following types are supported for fields: | |
28 | |
29 - :class:`int` | |
30 - :class:`float` | |
31 - :class:`bool` | |
32 - :class:`str` | |
33 - :class:`object` | |
34 - |Vec2d| | |
35 - |Vec2dArray| | |
36 - |RGBA| | |
37 - |Rect| | |
38 """ | |
39 | |
40 deleted_entities = () | |
41 """List of entities deleted from the component since the last time step""" | |
42 | |
43 new_entities = () | |
44 """List of entities added to the component since the last time step""" | |
45 | |
46 def __init__(self, **fields): | |
47 self.fields = {} | |
48 for fname, ftype in fields.items(): | |
49 assert ftype in field.types, fname + " has an illegal field type" | |
50 self.fields[fname] = field.Field(self, fname, ftype) | |
51 self.entities = ComponentEntitySet(self) | |
52 self._added = [] | |
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 | |
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 | |
105 | |
106 class Singleton(Component): | |
107 """Component that may contain only a single entity""" | |
108 | |
109 def add(self, entity_id, data=None, **data_kw): | |
110 if entity_id not in self._data: | |
111 self.entity_id_set.clear() | |
112 self._data.clear() | |
113 Component.add(self, entity_id, data, **data_kw) | |
114 | |
115 @property | |
116 def entity(self): | |
117 """Return the entity in the component, or None if empty""" | |
118 if self._data: | |
119 return self.manager[self._data.keys()[0]] | |
120 | |
121 | |
122 class Data(object): | |
123 | |
124 def __init__(self, fields, entity, **data): | |
125 self.__dict__['_Data__fields'] = fields | |
126 self.__dict__['entity'] = entity | |
127 for field in fields.values(): | |
128 if field.name in data: | |
129 setattr(self, field.name, data[field.name]) | |
130 else: | |
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 | |
142 | |
143 |