def getitem(M, k): """ Returns the value of entry k in M, if k is a 2-tuple. Returns the vector M[k], if k is a number (column-vector, if k label is present both for rows and columns). >>> M = Mat(({1,3,5}, {'a'}), {(1,'a'):4, (5,'a'): 2}) >>> M[1,'a'] 4 >>> M[3,'a'] 0 >>> M['a'] == Vec({1, 3, 5}, {1:4, 5:2}) True >>> M = Mat(({'a','b'}, {'a','b'}), {('a','a'):1, ('b','b'):1, ('b','a'):1}) >>> M['a'] == Vec({'a','b'}, {'a':1, 'b':1}) True >>> M['b'] == Vec({'a','b'}, {'a':0, 'b':1}) True """ if tuple == type(k): # getting number by pair of indices assert k[0] in M.D[0] and k[1] in M.D[1] return M.f.get((k[0], k[1]), 0) else: # getting vector by one index, preference given to column-vectors assert k in M.D[0] or k in M.D[1] if k in M.D[1]: return Vec(M.D[0], {i: M.f.get((i, k), 0) for i in M.D[0]}) # return column labeled with k else: # in M.D[0] return Vec(M.D[1], {i: M.f.get((k, i), 0) for i in M.D[1]}) # return row labeled with k
def setup_light(self): light = Light() light.direction = Vec(-5, -5, -5) light.direction.norm() light.color = Vec(1, 1, 1) light.ambient_intensity = 0.3 light.diffuse_intensity = 1.0 return light
def __init__(self, resource, scene, actor_type): """Constructor. :param resource: The character resource :type resource: :class:`loaders.Resource` :param scene: Scene to add the actor to. :type scene: :class:`renderlib.scene.Scene` :param actor_type: Type of actor entity. :type actor_type: :enum:`game.entities.actor.ActorType` """ self.resource = resource self.actor_type = actor_type mesh = resource['model'] # root transformation to apply to the mesh self.transform = mesh.transform # instantiate animations self.init_animations(mesh) self.current_anim = self.animations[action_anim_index(ActionType.idle)] # create a 2D texture from texture image texture = Texture.from_image(resource['texture'], Texture.TextureType.texture_2d) # create a material material = Material() material.texture = texture material.receive_light = True # rendering props self.props = MeshProps() self.props.material = material self.props.animation = self.current_anim self.props.receive_shadows = True self.props.cast_shadows = True # add the mesh to the scene self.obj = scene.add_mesh(mesh, self.props) # Initialize movable component movable = Movable((0.0, 0.0)) # initialize actor super().__init__(movable) # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5) self.heading = 0.0
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 matrix_vector_mul(M, v): """ Returns the product of matrix M and vector v. Consider using brackets notation v[...] in your procedure to access entries of the input vector. This avoids some sparsity bugs. >>> N1 = Mat(({1, 3, 5, 7}, {'a', 'b'}), {(1, 'a'): -1, (1, 'b'): 2, (3, 'a'): 1, (3, 'b'):4, (7, 'a'): 3, (5, 'b'):-1}) >>> u1 = Vec({'a', 'b'}, {'a': 1, 'b': 2}) >>> N1*u1 == Vec({1, 3, 5, 7},{1: 3, 3: 9, 5: -2, 7: 3}) True >>> N1 == Mat(({1, 3, 5, 7}, {'a', 'b'}), {(1, 'a'): -1, (1, 'b'): 2, (3, 'a'): 1, (3, 'b'):4, (7, 'a'): 3, (5, 'b'):-1}) True >>> u1 == Vec({'a', 'b'}, {'a': 1, 'b': 2}) True >>> N2 = Mat(({('a', 'b'), ('c', 'd')}, {1, 2, 3, 5, 8}), {}) >>> u2 = Vec({1, 2, 3, 5, 8}, {}) >>> N2*u2 == Vec({('a', 'b'), ('c', 'd')},{}) True >>> M3 = Mat(({0,1},{'a','b'}),{(0,'a'):1, (0,'b'):1, (1,'a'):1, (1,'b'):1}) >>> v3 = Vec({'a','b'},{'a':1,'b':1}) >>> M3*v3 == Vec({0, 1},{0: 2, 1: 2}) True """ assert M.D[1] == v.D # A(m*n), x(n*1) => A*x = [ dot(a1*,v), ..., dot(an*v) ] => column-vector (m*1) # return Vec(M.D[0], {i:sum(M[i,j]*v[j] for j in M.D[1]) for i in M.D[0]}) # not using sparsity => need to rewrite # Sparse matrix optimization # b = Vec(M.D[0], {i:0 for i in M.D[0]}) b = Vec(M.D[0], {}) for i, j in M.f: b[i] = b[i] + v[j] * M[i, j] return b
def vector_matrix_mul(v, M): """ returns the product of vector v and matrix M Consider using brackets notation v[...] in your procedure to access entries of the input vector. This avoids some sparsity bugs. >>> v1 = Vec({1, 2, 3}, {1: 1, 2: 8}) >>> M1 = Mat(({1, 2, 3}, {'a', 'b', 'c'}), {(1, 'b'): 2, (2, 'a'):-1, (3, 'a'): 1, (3, 'c'): 7}) >>> v1*M1 == Vec({'a', 'b', 'c'},{'a': -8, 'b': 2, 'c': 0}) True >>> v1 == Vec({1, 2, 3}, {1: 1, 2: 8}) True >>> M1 == Mat(({1, 2, 3}, {'a', 'b', 'c'}), {(1, 'b'): 2, (2, 'a'):-1, (3, 'a'): 1, (3, 'c'): 7}) True >>> v2 = Vec({'a','b'}, {}) >>> M2 = Mat(({'a','b'}, {0, 2, 4, 6, 7}), {}) >>> v2*M2 == Vec({0, 2, 4, 6, 7},{}) True >>> v3 = Vec({'a','b'},{'a':1,'b':1}) >>> M3 = Mat(({'a', 'b'}, {0, 1}), {('a', 1): 1, ('b', 1): 1, ('a', 0): 1, ('b', 0): 1}) >>> v3*M3 == Vec({0, 1},{0: 2, 1: 2}) True """ assert M.D[0] == v.D # v*(1*m), A(m*n) => v*A = [ dot(v*,a1), ..., dot(v*,an) ]* => row-vector (1*n) # return Vec(M.D[1], {j:sum(v[i]*M[i,j] for i in M.D[0]) for j in M.D[1]}) # not using sparsity => need to rewrite # Sparse matrix optimization # b = Vec(M.D[1], {i:0 for i in M.D[1]}) b = Vec(M.D[1], {}) for i, j in M.f: b[j] = b[j] + v[i] * M[i, j] return b
def __init__(self, resource, scene): """Constructor. :param resource: Resource containing map data. :type resource: :class:`resource_manager.Resource` :param scene: Scene to add the health bar to. :type scene: :class:`renderlib.scene.Scene` """ super().__init__() mesh = resource['walls_mesh'] texture = Texture.from_image(resource['walls_texture'], Texture.TextureType.texture_2d) material = Material() material.texture = texture material.receive_light = True props = MeshProps() props.material = material props.receive_shadows = False props.cast_shadows = False self.obj = scene.add_mesh(mesh, props) # FIXME: this offset here is due to the calculation of the walkable # matrix that adds one more walkable line on top of the scenario. self.obj.position = Vec(0.0, 0.0, 1.0) self.objects = [] # Initialize static objects for obj in resource.data['objects']: self.add_object(MapObject(resource[obj['ref']], scene, obj))
def ray_cast(x, y, w, h, camera): """Returns the world coordinates related to the given x,y coordinates. :param x: The x coordinate relative to screen :type x: int :param y: The y coordinate relative to screen :type y: int :param w: The width of the screen :type w: int :param h: The height of the screen :type h: int :param camera: The camera we are using to trace the ray. :type camera: :class:`renderer.Camera` :returns: The point in world coordinates. :type: :class:`mat.Vec` """ # Find the direction applying the modelview matrix to the facing direction # of the camera pos, ray = camera.trace_ray(x, y, w, h) # The normal vector for the y=0 plane norm = Vec(0, 1, 0) # And here finally we have the target of the click in world coordinates More # reference about the used math here: # * http://antongerdelan.net/opengl/raycasting.html t = -(pos.dot(norm)) / ray.dot(norm) return pos + (ray * t)
def partial_movement(self, distance, position, next_position, path): """Recursive function to calculate parial movements (to consider cases in which during the given dt we are actually going over a the destination point. :param distance: The magnitude of the movement vector. :type distance: float :param position: The current position of the movable. :type position: tuple :param next_position: The next position in the path. :type next_position: tuple :param path: The other points of the path. :type path: list """ # Actual distance from destination np = Vec(next_position[0], next_position[1], 0.0) p = Vec(position[0], position[1], 0.0) dst = (np - p).mag() # We did not reach the next_position yet. if distance < dst: self._direction = np - p self._direction.norm() cur = p + self._direction * distance self._position = cur.x, cur.y # We arrived in next_position, continue toward the next waypoint of the # path recursively calling partial_movement. elif path: position, next_position, path = next_position, path[0], path[1:] LOG.debug('Switched destination to {}'.format(next_position)) self.partial_movement(distance - dst, position, next_position, path) # We reached or surpassed next_position and there are no more path # steps: we arrived! else: LOG.debug('Movable arrived at destination {}'.format( self._position)) self.next_position = None self._direction = None self.path = [] self.speed = 0 self._position = next_position
def __init__(self, resource, scene, position, progress, completed): """Constructor. :param resource: The building resource :type resource: :class:`loaders.Resource` :param scene: Scene to add the building bar to. :type scene: :class:`renderlib.scene.Scene` :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` """ super().__init__() self.scene = scene self.obj = None self._position = to_scene(*position) self._completed = None # create texture texture = Texture.from_image(resource['texture'], Texture.TextureType.texture_2d) self.mesh_project = resource['model_project'] self.mesh_complete = resource['model_complete'] # create material material = Material() material.texture = texture # create render props self.props = MeshProps() self.props.material = material # set initial building status self.completed = completed # FIXME: hardcoded bounding box self._bounding_box = Vec(-0.5, 0, -0.5), Vec(0.5, 2, 0.5)
def update(self, dt): """Update the local player. This method computes player's game logic as a function of time and sends the appropriate event. :param dt: Time delta from last update. :type dt: float """ super(Player, self).update(dt) # map player game position to world (x,y -> x,z) x, z = self.position # update camera position and orientation context = Context.get_instance() camera = context.camera camera.position = Vec(x, 20, z + 5) camera.look_at(camera.position, Vec(x, 0, z))
def __init__(self, resource, width, height, player_data): """Constructor. :param resource: The UI resource. :type resource: :class:`loaders.Resource` :param width: UI width in pixels. :type width: int :param height: UI height in pixels. :type height: int :param player_data: Player resource. :type player_ddata: :class:`loaders.Resource` """ self.w = width self.h = height self.scene = Scene() self.camera = OrthographicCamera( -self.w / 2, # left +self.w / 2, # right +self.h / 2, # top -self.h / 2, # bottom 0, # near 1) # far font = resource['font'].get_size(16) props = TextProps() props.color = Vec(1, 1, 1, 1) # Mode node self.game_mode_text = Text(font, Context.GameMode.default.value) self.game_mode = self.scene.add_text(self.game_mode_text, props) self.transform(self.game_mode, self.w * 0.85, 20) # FPS counter self.fps_counter_text = Text(font, 'FPS') self.fps_counter = self.scene.add_text(self.fps_counter_text, props) self.transform(self.fps_counter, self.w * 0.85, 0) # clock self.clock_text = Text(font, '--:--') self.clock = self.scene.add_text(self.clock_text, props) self.transform(self.clock, self.w * 0.5, 0) # avatar avatar_res, avatar = player_data['avatar_res'], player_data['avatar'] self.avatar = Avatar(self.scene, avatar_res, avatar) self.transform(self.avatar.obj, 0, 0) # healthbar self.health_bar = HealthBar(self.scene, resource['health_bar']) self.transform(self.health_bar.bg_obj, 0, avatar_res.data['width'] + 5) self.transform(self.health_bar.fg_obj, 0, avatar_res.data['width'] + 5)
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 rot, scale = self.TRANSFORMS[self.actor_type] self.obj.position = to_scene(x, y) self.obj.rotation.rotatev(Vec(0, 1, 0), rot + -self.heading) self.obj.scale = Vec(scale, scale, scale) self.orientate() # play animation if self.current_anim: self.current_anim.play(dt)
def __init__(self, resource, scene, parameters): """Constructor. :param resource: Resource containing the object data. :type resource: :class:`resource_manager.Resource` :param scene: Scene to add the health bar to. :type scene: :class:`renderlib.scene.Scene` :param parameters: Parameters for the object. :type parameters: :class:`dict` """ super().__init__() mesh = resource['model'] texture = Texture.from_image( resource['texture'], Texture.TextureType.texture_2d) material = Material() material.texture = texture material.receive_light = True props = MeshProps() props.material = material props.cast_shadows = True props.receive_shadows = True self.obj = scene.add_mesh(mesh, props) self.obj.position = to_scene(*parameters['pos']) # FIXME: an added offset to match the level displacement self.obj.position.z += 1 if 'rotation' in parameters: self.obj.rotation.rotatev( Y_AXIS, parameters['rotation'] * pi / 180) # FIXME: hardcoded bounding box self._position = parameters['pos'] self._bounding_box = Vec(-0.5, 0.5, -0.5), Vec(0.5, 1.5, 0.5)
def intersect(pos, ray, bb): """Check if the ray starting from position pos intersects the bounding box. :param pos: The origin of the ray :type pos: :class:`matlib.Vec` :param ray: The ray :type ray: :class:`matlib.Vec` :param bb: The entity bounding box :type bb: :class:`tuple` """ # FIXME: please generalize me l, m = bb # front plane p = intersection(pos, ray, Vec(0, 0, -1), m.z) if l.x <= p.x <= m.x and l.y <= p.y <= m.y: return True # left plane p = intersection(pos, ray, Vec(1, 0, 0), l.x) if l.y <= p.y <= m.y and l.z <= p.z <= m.z: return True # right plane p = intersection(pos, ray, Vec(-1, 0, 0), m.x) if l.y <= p.y <= m.y and l.z <= p.z <= m.z: return True # top plane p = intersection(pos, ray, Vec(0, -1, 0), m.y) if l.x <= p.x <= m.x and l.z <= p.z <= m.z: return True # back plane p = intersection(pos, ray, Vec(1, 0, 0), l.z) if l.x <= p.x <= m.x and l.y <= p.y <= m.y: return True return False
def update(self, dt): """Update the building template. This method just applies the current position of the entity to the renderable transform. :param dt: Time delta from last update. :type dt: float """ x, y = self.pos m_x, m_y = to_matrix(x, y, self.scale_factor) if not in_matrix(self.matrix, m_x, m_y) or not self.matrix[m_y][m_x]: self.props.material.color = self.NON_BUILDABLE_COLOR else: self.props.material.color = self.BUILDABLE_COLOR self.obj.position = to_scene(x, y) self.obj.scale = Vec(1.05, 1.05, 1.05)
class BuildingTemplate(Entity): """Game entity which represents a building template.""" BUILDABLE_COLOR = Vec(0.0, 0.8, 0.4, 1) NON_BUILDABLE_COLOR = Vec(1, 0.0, 0.2, 1) def __init__(self, resource, scene, matrix, scale_factor): """Constructor. :param resource: The character resource :type resource: :class:`loaders.Resource` :type scene: :class:`renderlib.scene.Scene` :param scene: Scene to add the health bar to. :param matrix: The walkable matrix :type matrix: :class:`loaders.Resource` :param scale_factor: The scale factor of the grid. :type scale_factor: int """ super().__init__() self.pos = (0, 0) self.matrix = matrix self.scale_factor = scale_factor mesh = resource['model_complete'] # create material material = Material() material.color = self.BUILDABLE_COLOR # create render props container self.props = MeshProps() self.props.material = material # create components self.obj = scene.add_mesh(mesh, self.props) def remove(self): """Removes itself from the scene. """ LOG.debug('Remove building template {}'.format(self.e_id)) self.obj.remove() def update(self, dt): """Update the building template. This method just applies the current position of the entity to the renderable transform. :param dt: Time delta from last update. :type dt: float """ x, y = self.pos m_x, m_y = to_matrix(x, y, self.scale_factor) if not in_matrix(self.matrix, m_x, m_y) or not self.matrix[m_y][m_x]: self.props.material.color = self.NON_BUILDABLE_COLOR else: self.props.material.color = self.BUILDABLE_COLOR self.obj.position = to_scene(x, y) self.obj.scale = Vec(1.05, 1.05, 1.05)
def to_world(x, y, z): """Convert scene coordinates to world coordinates.""" return Vec(x, z, 0)
def to_scene(x, y): """Convert world coordinates to scene coordinates.""" return Vec(x, 0, y)
def bounding_box(self): l, m = self._bounding_box pos = self.position # FIXME: this offset here is due to the calculation of the walkable # matrix that adds one more walkable line on top of the scenario. return l + Vec(pos[0], 0, pos[1] + 1), m + Vec(pos[0], 0, pos[1] + 1)
from game.entities.entity import Entity from game.events import EntityPick from game.events import ObjectSpawn from math import pi from matlib.vec import Vec from network.message import Message from network.message import MessageField as MF from network.message import MessageType from renderlib.material import Material from renderlib.mesh import MeshProps from renderlib.texture import Texture from utils import to_scene import logging Y_AXIS = Vec(0, 1, 0) LOG = logging.getLogger(__name__) @unique class ObjectType(IntEnum): """Enumeration of the possible static objects""" coffee = 0 class MapObject(Entity): """Static object on the map.""" def __init__(self, resource, scene, parameters):