Coverage for src/gncpy/game_engine/entities.py: 0%

63 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-19 05:48 +0000

1"""Defines game entities and a manager class.""" 

2 

3 

4class Entity: 

5 """Elements in a game. 

6 

7 These should not be created or deleted directly, the manager class should 

8 be used instead. 

9 """ 

10 

11 __slots__ = ("_active", "_id", "_tag", "_components") 

12 

13 def __init__(self, e_id, tag): 

14 """Initialize an object. 

15 

16 This should not be called outside of the :class:`.EntityManager` class. 

17 

18 Parameters 

19 ---------- 

20 e_id : int 

21 Unique ID number for the entity. 

22 tag : string 

23 Type of entity. 

24 """ 

25 self._active = True 

26 self._id = e_id 

27 self._tag = tag 

28 

29 self._components = {} 

30 

31 @property 

32 def active(self): 

33 """Flag indicating if the entity is alive.""" 

34 return self._active 

35 

36 @property 

37 def tag(self): 

38 """Read only tag of for the entity.""" 

39 return self._tag 

40 

41 @property 

42 def id(self): 

43 """Read only unique id of the entity.""" 

44 return self._id 

45 

46 def destroy(self): 

47 """Handles destruction of the entity.""" 

48 self._active = False 

49 

50 def has_component(self, comp): 

51 """Returns true if the entity has the given component. 

52 

53 Parameters 

54 ---------- 

55 comp : object 

56 Component class from :mod:`gncpy.game_engine.components`. 

57 

58 Returns 

59 ------- 

60 bool 

61 Flag indicating if the entity has the component. 

62 """ 

63 return comp.__name__ in self._components 

64 

65 def get_component(self, comp): 

66 """Returns a reference to the given component. 

67 

68 This assumes the component exists. 

69 

70 Parameters 

71 ---------- 

72 comp : object 

73 Component class from :mod:`gncpy.game_engine.components`. 

74 

75 Returns 

76 ------- 

77 object 

78 reference to a class instance from :mod:`gncpy.game_engine.components`. 

79 """ 

80 return self._components[comp.__name__] 

81 

82 def add_component(self, comp, **kwargs): 

83 """Adds a component to the entity. 

84 

85 Parameters 

86 ---------- 

87 comp : class constructor 

88 Component class constructor from :mod:`gncpy.game_engine.components`. 

89 **kwargs : dict, optional 

90 Additional arguments to pass to the constructor. 

91 

92 Returns 

93 ------- 

94 component : object 

95 Reference to the new component class. 

96 """ 

97 component = comp(**kwargs) 

98 self._components[comp.__name__] = component 

99 return component 

100 

101 

102class EntityManager: 

103 """Handles creation and deletion of entities.""" 

104 

105 __slots__ = ("_entities", "_entities_to_add", "_entity_map", "_total_entities") 

106 

107 def __init__(self): 

108 self._entities = [] 

109 self._entities_to_add = [] 

110 self._entity_map = {} 

111 self._total_entities = 0 

112 

113 def _remove_dead_entities(self, vec): 

114 e_to_rm = [] 

115 for ii, e in enumerate(vec): 

116 if not e.active: 

117 e_to_rm.append(ii) 

118 

119 for ii in e_to_rm[::-1]: 

120 del vec[ii] 

121 

122 def update(self): 

123 """Updates the list of entities. 

124 

125 Should be called once per timestep. Adds new entities to the list and 

126 and removes dead ones. 

127 """ 

128 for e in self._entities_to_add: 

129 self._entities.append(e) 

130 if e.tag not in self._entity_map: 

131 self._entity_map[e.tag] = [] 

132 self._entity_map[e.tag].append(e) 

133 self._entities_to_add = [] 

134 

135 self._remove_dead_entities(self._entities) 

136 

137 for tag, ev in self._entity_map.items(): 

138 self._remove_dead_entities(ev) 

139 

140 def add_entity(self, tag): 

141 """Creates a new entity. 

142 

143 The entity is queued to be added. It is not part of the entity list 

144 until after the update function has been called. 

145 

146 Parameters 

147 ---------- 

148 tag : string 

149 Tag to identify the type of entity. 

150 

151 Returns 

152 ------- 

153 e : :class:`.Entity` 

154 Reference to the created entity. 

155 """ 

156 self._total_entities += 1 

157 e = Entity(self._total_entities, tag) 

158 self._entities_to_add.append(e) 

159 

160 return e 

161 

162 def get_entities(self, tag=None): 

163 """Return a list of references to entities. 

164 

165 Can also get all entities with a given tag. Note that changing entities 

166 returned by this function modifies the entities managed by this class. 

167 

168 Parameters 

169 ---------- 

170 tag : string, optional 

171 If provided only return entities with this tag. The default is None. 

172 

173 Returns 

174 ------- 

175 list 

176 Each element is an :class:`.Entity`. 

177 """ 

178 if tag is None: 

179 return self._entities 

180 else: 

181 if tag in self._entity_map: 

182 return self._entity_map[tag] 

183 else: 

184 return [] 

185 

186 def get_entity_ids(self, tag=None): 

187 """Return a list of the entity ids. 

188 

189 Parameters 

190 ---------- 

191 tag : string, optional 

192 If provided only return ids for entities with this tag. The default 

193 is None. 

194 

195 Returns 

196 ------- 

197 list 

198 Each element is an entity id. 

199 """ 

200 return [e.id for e in self.get_entities(tag=tag)]