Esempio n. 1
0
 def __init__(self, event_manager, entity_id):
     SingleListener.__init__(self, event_manager)
     self.entity_id = entity_id
     self._area = None
     self._age = 0
     # This `exists` variable is funny.  It comes in play because of how the
     # physics engine is built.  Imagine that for some reason (creature
     # walks in lava, bonus gets picked up), an entity disappears from the
     # world due to its physical interaction with the environment.  The
     # natural thing to do is to remove that entity from the world. However,
     # that will break the physics engine since the dictionaries will change
     # size during iterations.  So instead, we mark the 'dead' entity by
     # setting its `exists` variable to False.  That saves the physics
     # engine, but now we must take care that it ignores every entity that
     # does not exist.
     self.exists = True
     # Physics.
     self.body = physics.CircularBody(self.BODY_MASS, geometry.Vector(),
                                      self.SOLID, materials.MATERIAL_FLESH,
                                      self.BODY_RADIUS)
     self._walk_force = physics.ConstantForce(geometry.Vector())
     self.friction_force = physics.KineticFrictionForce(0)
     self.body.forces.add(self._walk_force)
     self.body.forces.add(self.friction_force)
     self._walk_strentgh = self.WALK_STRENGTH
     self.is_moving = False
     # Final stuff.
     self.post(events.EntityCreatedEvent(entity_id))
     LOGGER.debug("Entity %i created.", entity_id)
Esempio n. 2
0
 def __init__(self, event_manager, entity_id):
     evtman.SingleListener.__init__(self, event_manager)
     self._entity_id = entity_id
     # EntityViews hold a weak reference to their AreaView.  This allows
     # them to create new EntityView such as special effects.
     self._area_view = None
     # World coordinates.  The apparent position is interpolated between
     # these two positions.
     self.old_pos = geometry.Vector()
     self.new_pos = geometry.Vector()
     self.int_pos = geometry.Vector()  # The interpolated one.
     #
     self.sprite = None
     self.createSprite()
     self._dirty = True
Esempio n. 3
0
 def __init__(self):
     object.__init__(self)
     self.zoom = 32
     # World coordinates are expected to be floats.
     self._ref_world = geometry.Vector()
     # While pixels are integers.
     self._ref_pix_x = 0
     self._ref_pix_y = 0
Esempio n. 4
0
 def moveEntity(self):
     """The player pushes his/her entity in a given direction."""
     x = self.going_east - self.going_west
     y = self.going_north - self.going_south
     if x and y:
         x /= 2 ** .5
         y /= 2 ** .5
     direction = geometry.Vector(x, y)
     self.post(models.events.MoveEntityRequest(self._entity_id, direction))
Esempio n. 5
0
 def detectCollisionsWithTiles(self, collider):
     """Return a set of Collision objects."""
     coords = self.pruneTiles(collider)
     collisions = set()
     for coord in coords:
         tile_nature = self.tile_map.tiles[coord].nature
         material = tile.MATERIALS[tile_nature]
         tile_body = physics.RectangularBody(float('inf'),
                                             geometry.Vector(coord), True,
                                             material, 1., 1.)
         collision = tile_body.collidesCircle(collider.body)
         if collision:
             collisions.add(collision)
     return collisions
Esempio n. 6
0
 def runPhysics(self, timestep):
     """Uses physics to move all the entities."""
     for entity in self.entities.itervalues():
         if not entity.exists:
             continue
         before = entity.body.pos
         self.moveEntityByPhysics(entity, timestep)
         after = entity.body.pos
         if before != after:
             entity.is_moving = True
             self.post(events.EntityMovedEvent(entity.entity_id, after))
             self.affectEntityWithTile(entity)
         if entity.is_moving:
             if entity.body.vel == geometry.Vector(0, 0):
                 entity.is_moving = False
                 self.post(events.EntityStoppedEvent(entity.entity_id))
Esempio n. 7
0
 def renderTiles(self):
     """Displays the tiles."""
     # We do not want to process ALL the tiles of the tile map.  So we look
     # for those that have coordinates matching our view.
     # I did try other methods:
     # * Blit everything, hoping that pygame is smart enough to do nothing
     #   when there is nothing to do: good result on 32*32 maps.
     # * Test for the intersection of the tile rect with the view rect:
     #   horrible all the time.
     # And of course it did not scale well at all, a 128*128 map was
     # bringing me down to 5 FPS.  So we do not look at all the tiles
     # anymore, we prune.
     size = self._visible_tiles_region.size
     # The weird mix of max and min is due to the fact that the y axis
     # is reversed on the display.
     x_min, y_max = self._coord_conv.pixToWorld((0, 0))
     x_max, y_min = self._coord_conv.pixToWorld(size)
     x_min = int(math.floor(x_min))
     y_min = int(math.floor(y_min))
     x_max = int(math.ceil(x_max))
     y_max = int(math.ceil(y_max))
     tile_rect = pygame.Rect((0, 0), (32, 32))
     image = self.sprite.image
     for y in xrange(y_min, y_max + 1):
         for x in xrange(x_min, x_max + 1):
             try:
                 tile = self._tilemap[(x, y)]
             except KeyError:
                 pass
             else:
                 pos = self._coord_conv.worldToPix(geometry.Vector(x, y))
                 tile_rect.center = pos
                 if tile[1]:
                     tile_image = TILE_IMAGES_HIGH
                 else:
                     tile_image = TILE_IMAGES_LOW
                 tile_image = tile_image[tile[0]]  # 0: nature.
                 image.blit(tile_image, tile_rect)
Esempio n. 8
0
class CoordinatesConverter(object):
    """Converts world coordinates to screen coordinates.

    To a fixed reference point on the screen corresponds a reference point in
    the world that can vary.  For example, you can wish to center the view on
    the character the player is controlling, so the center of the screen
    (fixed) corresponds to a varying world position.

    Furthermore, there is a conversion factor to translate distances in the
    world to a number of pixels on the screen.

    The world position is given by a geometry.Vector object because that is
    what is used in the physics engine.  However, these Vector objects are not
    practical for screen coordinates: pygame prefers Rect or tuples.  So we
    use tuples.

    """
    def __init__(self):
        object.__init__(self)
        self.zoom = 32
        # World coordinates are expected to be floats.
        self._ref_world = geometry.Vector()
        # While pixels are integers.
        self._ref_pix_x = 0
        self._ref_pix_y = 0

    def setRefWorld(self, pos_vector):
        """Set the reference world coordinates.

        If you have defined the reference pixel coordinates to be the center
        of your view, then calling setRefWorld centers your view on the given
        position.  For example, setRefWorld(entity.pos) will center the world
        on that entity.

        """
        self._ref_world.icopy(pos_vector)

    def setRefPix(self, xytuple):
        """Set the reference pixel coordinates.

        Any tuple of two integers is valid.  However, very few are handy.
        The one I suggest is the middle point of the view area.  It allows
        you to very easily center the view on any point of the world.

        setRefPix(AreaView.sprite.rect.width // 2,
                  AreaView.sprite.rect.height // 2)

        """
        self._ref_pix_x, self._ref_pix_y = xytuple

    def worldToPix(self, pos_vector):
        """Convert world coordinates to pixel coordinates."""
        offset = (pos_vector - self._ref_world) * self.zoom
        # The minus sign comes from my convention.  I consider that the world
        # Y axis increases when we move to the North.  However, the display
        # says otherwise.
        return (self._ref_pix_x + int(round(offset.x)),
                self._ref_pix_y - int(round(offset.y)))

    def pixToWorld(self, (pix_x, pix_y)):
        """Return the world coordinates corresponding to the given pixel."""
        offset_x = pix_x - self._ref_pix_x
        offset_y = self._ref_pix_y - pix_y
        offset = geometry.Vector(offset_x, offset_y)
        pos_vector = offset / self.zoom + self._ref_world
        return pos_vector