def __init__(self, velocity=None, force=None, mass=0.0, **kwargs): super(DynamicPhysicEntity, self).__init__(**kwargs) self.velocity = velocity or get_vec_fact().vector2() self.force = force or get_vec_fact().vector2() self.mass = mass # TODO: introduce the notion of actually infinite mass. 99999 is not infinite enough self.rev_mass = 1 / float(mass) if mass else 99999
def vertices(self): return ( self.position + get_vec_fact().vector2(self.size.x, 0), self.position + self.size, self.position + get_vec_fact().vector2(0, self.size.y), self.position, )
def _get_collision(self, entity, time_delta): velocity = entity.velocity.len() if not velocity: return entity_offset = get_vec_fact().vector2(entity.velocity.x * time_delta, entity.velocity.y * time_delta) collision_candidates = self._get_collision_candidates( entity, entity_offset) point_projections = [ (point, get_vec_fact().vector2(point.x + entity_offset.x, point.y + entity_offset.y)) for point in entity.vertices() ] rev_velocity = 1.0 / entity.velocity.len() collisions = [] for candidate in collision_candidates: for point_proj in point_projections: for side, edge in candidate.edges().items(): cross_point = self._get_cross_point(point_proj, edge) if cross_point is not None: collision_time = (cross_point - point_proj[0]).len() * rev_velocity if self._eq(collision_time, 0): collision_time = 0.0 collisions.append( CollisionParams(side, collision_time, candidate)) if collisions: return min(collisions, key=lambda x: x.time) return None
def __init__(self, position=None, projectile_force=None, color=(255, 255, 255), **kwargs): size = get_vec_fact().vector2(2, 2) super(Projectile, self).__init__(position=position, size=size, placeholder_size=size, color=color, **kwargs) self.projectile_force = projectile_force or get_vec_fact().vector2()
def draw(self, viewport): center = self.position + (self.placeholder_size / 2) self.renderer.fill_polygon( viewport=viewport, color=self.color, pointlist=( self.position.rotated_around(self.rotation, center).point(), # (self.position + get_vec_fact().vector2(self.placeholder_size.x, 0.0)).rotated_around(self.rotation, center).point(), (self.position + get_vec_fact().vector2( self.placeholder_size.x, self.placeholder_size.y / 2.0) ).rotated_around(self.rotation, center).point(), (self.position + get_vec_fact().vector2( 0.0, self.placeholder_size.y)).rotated_around( self.rotation, center).point(), ), )
def __init__(self, rect, screen_rect): super(Viewport, self).__init__() self._rect = rect self._screen_rect = screen_rect self._world_to_screen_transform = get_vec_fact().vector2( float(screen_rect[2]) / float(rect[2]), float(screen_rect[3]) / float(rect[3]), ) self._screen_to_world_transform = get_vec_fact().vector2( float(rect[2]) / float(screen_rect[2]), float(rect[3]) / float(screen_rect[3]), ) self._world_to_screen_translate = get_vec_fact().vector2( -rect[0], -rect[1]) self._screen_to_world_translate = get_vec_fact().vector2( -screen_rect[0], -screen_rect[1]) self._tmp = get_vec_fact().vector2()
def __init__(self, position, movement_force=1, hp=2, z=0, **kwargs): size = get_vec_fact().vector2(20, 10) super(DummyEnemy, self).__init__(position=position, z=z, size=size, placeholder_size=size, mass=10, **kwargs) self.movement_force = movement_force self.hp = hp self._player = entity_registry.get_by_class(FmPlayer)[0]
def __init__(self, player_input, position, z=0, collision_category=None, projectile_collision_category=None): size = get_vec_fact().vector2(20, 10) super(FmPlayer, self).__init__(player_input=player_input, placeholder_size=size, position=position, mass=10.0, size=size, z=z, collision_category=collision_category) self.projectile_collision_category = projectile_collision_category self.fire_cooldown = 0.2 self._last_shot_time = 0 self._game_time = entity_registry.get_by_class(GameTime)[0]
def shoot(self): if self._game_time.now - self._last_shot_time < self.fire_cooldown: return center = self.position + (self.size / 2) projectile_spawn_position = (self.position + get_vec_fact().vector2( self.size.x + 1, self.size.y / 2)).rotated_around( self.rotation, center) projectile_direction = self._calc_normalized_projectile_direction( projectile_spawn_position) entity_registry.add( Projectile(projectile_spawn_position, projectile_direction * 1000, (0, 0, 255), velocity=projectile_direction * 300, mass=1, z=self.z, collision_category=self.projectile_collision_category)) self._last_shot_time = self._game_time.now
def initialize(self): key_mapping = KeyMapping({ FmPlayer.ACT_MOVE_RIGHT: [(Keyboard, KEYS.d)], FmPlayer.ACT_MOVE_LEFT: [(Keyboard, KEYS.a)], FmPlayer.ACT_MOVE_UP: [(Keyboard, KEYS.w)], FmPlayer.ACT_MOVE_DOWN: [(Keyboard, KEYS.s)], FmPlayer.ACT_EXIT: [(Keyboard, KEYS.esc)], FmPlayer.ACT_FIRE: [(Keyboard, KEYS.space), (Mouse, MBUTTONS.lmb)], }) keyboard = entity_registry.get_by_class(Keyboard)[0] mouse = entity_registry.get_by_class(Mouse)[0] self._player = FmPlayer( PlayerInput([keyboard, mouse], key_mapping), get_vec_fact().vector2(1, 200), z=1, collision_category=self.COLLSION_CAT_PLAYER, projectile_collision_category=self.COLLSION_CAT_PLAYER_PROJECTILE) entity_registry.add(self._player) entity_registry.add( Wall(get_vec_fact().vector2(-1, -1), get_vec_fact().vector2(1000, 1000), (200, 200, 255), z=2, collision_category=self.COLLSION_CAT_BACKGROUND)) entity_registry.add( DummyEnemy(get_vec_fact().vector2(300, 300), 1000, 2, z=1, collision_category=self.COLLSION_CAT_ENEMY, color=(255, 0, 0))) physics = SpacecraftPhysics() physics.set_collidable_categories(self.COLLSION_CAT_BACKGROUND, []) physics.set_collidable_categories(self.COLLSION_CAT_PLAYER, []) physics.set_collidable_categories(self.COLLSION_CAT_PLAYER_PROJECTILE, [self.COLLSION_CAT_ENEMY]) entity_registry.add(physics) entity_registry.add(ActorDriver(20)) entity_registry.add(FpsCounter()) screen = entity_registry.get_by_class(Screen)[0] screen.set_resolution(400, 500) renderer = entity_registry.get_by_class(Renderer2d)[0] viewport = renderer.create_viewport((0, 0, 400, 500), (0, 0, 400, 500)) entity_registry.add(viewport) mouse.set_viewport(viewport) entity_registry.add( Hud(get_vec_fact().vector2(0, 0), get_vec_fact().vector2(400, 100), self._player)) self._game_time = entity_registry.get_by_class(GameTime)[0]
def _get_cross_point(self, line1, line2): x1 = line1[0].x x2 = line1[1].x x3 = line2[0].x x4 = line2[1].x y1 = line1[0].y y2 = line1[1].y y3 = line2[0].y y4 = line2[1].y denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if self._eq(denominator, 0): return None cross_point = get_vec_fact().vector2( ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denominator, ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denominator) if self._point_is_on_line(cross_point, line1) and self._point_is_on_line( cross_point, line2): return cross_point return None
def __init__(self, placeholder_size=None, color=(255, 255, 255), **kwargs): super(Placeholder, self).__init__(**kwargs) self.placeholder_size = placeholder_size or get_vec_fact().vector2() self.color = color
def __init__(self, size=None, collision_category=None, **kwargs): super(PhysicEntity, self).__init__(**kwargs) self.size = size or get_vec_fact().vector2() self.collision_category = collision_category self.collision = None
def __mul__(self, scalar): scalar = float(scalar) return get_vec_fact().vector2(self.x * scalar, self.y * scalar)
def __init__(self, position=None): super(WorldEntity, self).__init__() self.position = position or get_vec_fact().vector2() self.rotation = 0
def __sub__(self, other): return get_vec_fact().vector2(self.x - other.x, self.y - other.y)
def _calc_normalized_projectile_direction(self, spawn_position): mouse_position = self.player_input.get_mouse_world_pos() direction = get_vec_fact().vector2(*mouse_position) - spawn_position direction.normalize() return direction
def _update_rotation(self): mouse_pos = self.player_input.get_mouse_world_pos() center = self.position + (self.size / 2) direction = get_vec_fact().vector2(mouse_pos[0] - center.x, mouse_pos[1] - center.y) self.rotation = math.atan2(direction.y, direction.x)
def __add__(self, other): return get_vec_fact().vector2(self.x + other.x, self.y + other.y)
def __div__(self, scalar): return get_vec_fact().vector2(self.x / scalar, self.y / scalar)
def normalized(self, norm=1.0): normalized_vector = get_vec_fact().vector2(self.x, self.y) normalized_vector.normalize(norm) return normalized_vector
def rotated(self, angle): return get_vec_fact().vector2( self.x * math.cos(angle) - self.y * math.sin(angle), self.x * math.sin(angle) + self.y * math.cos(angle), )
def copy(self): return get_vec_fact().vector2(self.x, self.y)