def __init__(self, resource, position, progress, completed, parent_node): """Constructor. :param resource: The building resource :type resource: :class:`loaders.Resource` :param position: The position of the building :type position: :class:`tuple` :param progress: The current amount of hp and the total one :type progress: :class:`tuple` :param completed: Whether the building is completed or not :type completed: :class:`bool` :param parent_node: The parent node in the scene graph :type parent_node: :class:`renderer.scene.SceneNode` """ self._position = position # Progress is going to be a property used to update only when necessary # the health bar. self._progress = progress self.completed = completed shader = resource['shader'] texture = Texture.from_image(resource['texture']) self.mesh_project = resource['model_project'] self.mesh_complete = resource['model_complete'] # Setup the group node and add the health bar group_node = SceneNode() g_transform = group_node.transform g_transform.translate(to_scene(*position)) parent_node.add_child(group_node) self.health_bar = HealthBar( resource['health_bar'], progress[0] / progress[1], group_node) params = { 'tex': texture, } # create components renderable = Renderable( group_node, self.mesh, shader, params, textures=[texture], enable_light=True) # initialize entity super().__init__(renderable) # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5)
def __init__(self, resource, actor_type, health, parent_node): """Constructor. :param resource: The character resource :type resource: :class:`loaders.Resource` :param health: The current amount of hp and the total one :type health: :class:`tuple` :param parent_node: The parent node in the scene graph :type parent_node: :class:`renderer.scene.SceneNode` """ self.actor_type = actor_type # Health is going to be a property used to update only when necessary # the health bar. self._health = health shader = resource['shader'] mesh = resource['model']['mesh'] md = resource['model']['mesh_data'] # root transformation to apply to the mesh self.transform = md.transform # instantiate animations self.init_animations(md) self.current_anim = self.animations[action_anim_index(ActionType.idle)] texture = Texture.from_image(resource['texture']) # shader params params = { 'tex': texture, 'opacity': 1.0, 'color_ambient': Vec(0, 0, 0, 1), 'color_diffuse': Vec(0, 0, 0, 1), 'color_specular': Vec(0.1, 0.1, 0.1, 1), } # Initialize movable component movable = Movable((0.0, 0.0)) # Setup the group node and add the health bar # FIXME: I don't like the idea of saving the group node here. We need # something better here. self.group_node = SceneNode() g_transform = self.group_node.transform g_transform.translate(to_scene(*movable.position)) parent_node.add_child(self.group_node) self.health_bar = HealthBar( resource['health_bar'], health[0] / health[1], self.group_node, resource.data.get('hb_y_offset')) # create components renderable = Renderable( self.group_node, mesh, shader, params, textures=[texture], enable_light=True, animation=self.current_anim) # by default, start with playing animation renderable.animate = True # initialize actor super().__init__(renderable, movable) # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5) self.heading = 0.0
class Building(Entity): """Game entity which represents a building.""" def __init__(self, resource, position, progress, completed, parent_node): """Constructor. :param resource: The building resource :type resource: :class:`loaders.Resource` :param position: The position of the building :type position: :class:`tuple` :param progress: The current amount of hp and the total one :type progress: :class:`tuple` :param completed: Whether the building is completed or not :type completed: :class:`bool` :param parent_node: The parent node in the scene graph :type parent_node: :class:`renderer.scene.SceneNode` """ self._position = position # Progress is going to be a property used to update only when necessary # the health bar. self._progress = progress self.completed = completed shader = resource['shader'] texture = Texture.from_image(resource['texture']) self.mesh_project = resource['model_project'] self.mesh_complete = resource['model_complete'] # Setup the group node and add the health bar group_node = SceneNode() g_transform = group_node.transform g_transform.translate(to_scene(*position)) parent_node.add_child(group_node) self.health_bar = HealthBar( resource['health_bar'], progress[0] / progress[1], group_node) params = { 'tex': texture, } # create components renderable = Renderable( group_node, self.mesh, shader, params, textures=[texture], enable_light=True) # initialize entity super().__init__(renderable) # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5) @property def mesh(self): """Returns the appropriate mesh based on the building status. :returns: The appropriate mesh :rtype: :class:`renderer.Mesh` """ if not self.completed: return self.mesh_project else: return self.mesh_complete @property def progress(self): """Returns the progress of the building as a tuple current/total. :returns: The progress of the building :rtype: :class:`tuple` """ return self._progress @progress.setter def progress(self, value): """Sets the progress of the building. Propagate the modification to the buliding health bar. :param value: The new progress :type value: :class:`tuple` """ self._progress = value self.health_bar.value = value[0] / value[1] @property def position(self): """The position of the entity in world coordinates. :returns: The position :rtype: :class:`tuple` """ return self._position @property def bounding_box(self): """The bounding box of the entity. The bounding box is represented by the smaller and bigger edge of the box itself. :returns: The bounding box of the actor :rtype: :class:`tuple` """ l, m = self._bounding_box pos = self.position return l + Vec(pos[0], 0, pos[1]), m + Vec(pos[0], 0, pos[1]) def destroy(self): """Removes itself from the scene. """ LOG.debug('Destroying building {}'.format(self.e_id)) # Destroys the health bar first. self.health_bar.destroy() node = self[Renderable].node node.parent.remove_child(node) def update(self, dt): """Updates the building. Applies the status of the building in terms of shader params and meshes. :param dt: Time delta from last update. :type dt: float """ node = self[Renderable].node node.mesh = self.mesh # Update the health bar self.health_bar.update(dt)
class Actor(Entity): """Game entity which represents an actor.""" # *FIXME* *FIXME* *FIXME* # REFACTOR THIS!!! TRANSFORMS = { ActorType.grunt: (pi, 0.12), ActorType.programmer: (pi, 0.022), ActorType.engineer: (pi, 5.5), ActorType.zombie: (pi, 0.05), } def init_animations(self, mesh_data): self.animations = {} for i in range(3): try: self.animations[i] = AnimationInstance(mesh_data.animations[i]) except IndexError: self.animations[i] = None def __init__(self, resource, actor_type, health, parent_node): """Constructor. :param resource: The character resource :type resource: :class:`loaders.Resource` :param health: The current amount of hp and the total one :type health: :class:`tuple` :param parent_node: The parent node in the scene graph :type parent_node: :class:`renderer.scene.SceneNode` """ self.actor_type = actor_type # Health is going to be a property used to update only when necessary # the health bar. self._health = health shader = resource['shader'] mesh = resource['model']['mesh'] md = resource['model']['mesh_data'] # root transformation to apply to the mesh self.transform = md.transform # instantiate animations self.init_animations(md) self.current_anim = self.animations[action_anim_index(ActionType.idle)] texture = Texture.from_image(resource['texture']) # shader params params = { 'tex': texture, 'opacity': 1.0, 'color_ambient': Vec(0, 0, 0, 1), 'color_diffuse': Vec(0, 0, 0, 1), 'color_specular': Vec(0.1, 0.1, 0.1, 1), } # Initialize movable component movable = Movable((0.0, 0.0)) # Setup the group node and add the health bar # FIXME: I don't like the idea of saving the group node here. We need # something better here. self.group_node = SceneNode() g_transform = self.group_node.transform g_transform.translate(to_scene(*movable.position)) parent_node.add_child(self.group_node) self.health_bar = HealthBar( resource['health_bar'], health[0] / health[1], self.group_node, resource.data.get('hb_y_offset')) # create components renderable = Renderable( self.group_node, mesh, shader, params, textures=[texture], enable_light=True, animation=self.current_anim) # by default, start with playing animation renderable.animate = True # initialize actor super().__init__(renderable, movable) # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5) self.heading = 0.0 @property def health(self): """Returns the health of the character as a tuple current/total. :returns: The health of the character :rtype: :class:`tuple` """ return self._health @health.setter def health(self, value): """Sets the health of the character. Propagate the modification to the buliding health bar. :param value: The new health :type value: :class:`tuple` """ self._health = value self.health_bar.value = value[0] / value[1] @property def position(self): """The position of the actor in world coordinates. :returns: The position :rtype: :class:`tuple` """ return self[Movable].position @property def bounding_box(self): """The bounding box of the entity. The bounding box is represented by the smaller and bigger edge of the box itself. :returns: The bounding box of the actor :rtype: :class:`tuple` """ l, m = self._bounding_box pos = self.position return l + Vec(pos[0], 0, pos[1]), m + Vec(pos[0], 0, pos[1]) def orientate(self): """Orientate the character towards the current destination. """ direction = self[Movable].direction if direction: dx = direction.x dy = direction.y if dx: target_heading = atan(dy / dx) + (pi / 2) * copysign(1, dx) else: target_heading = pi if dy > 0 else 0 # Compute remaining rotation delta = target_heading - self.heading abs_delta = abs(delta) if abs_delta > WHOLE_ANGLE / 2: abs_delta = WHOLE_ANGLE - abs(delta) delta = -delta # tweak speed (XXX: make it more rational) rot_speed = abs_delta * 2 * pi / 40 if abs_delta < rot_speed * 2: # Rotation is complete within a small error. # Force it to the exact value: self.heading = target_heading return self.heading += copysign(1, delta) * rot_speed # normalize angle to be in (-pi, pi) if self.heading >= WHOLE_ANGLE / 2: self.heading = -WHOLE_ANGLE + self.heading if self.heading < -WHOLE_ANGLE / 2: self.heading = WHOLE_ANGLE + self.heading def destroy(self): """Removes itself from the scene. """ LOG.debug('Destroying character {}'.format(self.e_id)) node = self.group_node node.parent.remove_child(node) def set_action(self, action_type): """Sets current player action. :param action_type: Action to set. :type action_type: :class:`game.entities.actor.ActionType` """ anim = self.animations[action_anim_index(action_type)] self[Renderable].animation = self.current_anim = anim def update(self, dt): """Update the character. This method computes character's game logic as a function of time. :param dt: Time delta from last update. :type dt: float """ self[Movable].update(dt) x, y = self[Movable].position # FIXME: I don't like the idea of saving the group node here. We need # something better here. g_t = self.group_node.transform g_t.identity() g_t.translate(to_scene(x, y)) rot, scale = self.TRANSFORMS[self.actor_type] t = self[Renderable].transform t.identity() t *= self.transform t.rotate(Vec(0, 1, 0), rot) # FIXME t.rotate(Vec(0, 1, 0), -self.heading) t.scale(Vec(scale, scale, scale)) self.orientate() # Update the health bar self.health_bar.update(dt) # play animation if self.current_anim: self.current_anim.play(dt)