예제 #1
0
class PostProcessingStep(object):
    def __init__(self, width, height, flip_y=True):
        super().__init__()

        self._fbo = FrameBuffer(width, height)
        self._drawable = QuadDrawable()
        self._drawable.size = Vector2(width, height)
        self._drawable.flip_y = flip_y
        self._drawable.pos = Vector2(0, height)
        self._drawable.invalidate_matrices()
        self._drawable.texture = self._fbo.texture

    def draw(self, screen):
        self._drawable.draw(screen)

    @property
    def fbo(self):
        return self._fbo

    @property
    def drawable(self):
        return self._drawable

    @drawable.setter
    def drawable(self, drawable):
        self._drawable = drawable
예제 #2
0
class SideTrail(Entity):
    def __init__(self, ship, offset_x, offset_y, offset_angle):
        self._ship = ship
        self.offset_x = offset_x
        self.offset_y = offset_y
        self.offset_angle = offset_angle

        self.side_trail_dimensions = Vector2(56 * self._ship.size,
                                             11 * self._ship.size)
        self.side_trail = QuadDrawable(0, 0, self.side_trail_dimensions.x,
                                       self.side_trail_dimensions.y)
        self.side_trail.texture = Texture.load_from_file(
            'resources/images/ship/side_trail.png')
        self.side_trail.anchor = Vector2(56 * self._ship.size,
                                         5 * self._ship.size)
        self.side_trail.angle = offset_angle

        self.update(0, 0)

    def draw(self, screen):
        self.side_trail.draw(screen)

    def update(self, game_speed, axis):
        if axis > 0:
            self.side_trail.size = self.side_trail_dimensions
            self.side_trail.pos = PHYSICS_SCALE * (
                self._ship._physicsShip.body.transform *
                (self.offset_x / PHYSICS_SCALE, self.offset_y / PHYSICS_SCALE))
            self.side_trail.angle = self.offset_angle + self._ship._quad.angle
        else:
            self.side_trail.size = Vector2(0, 0)
예제 #3
0
class Bullet(Entity):
    def __init__(self, bullet_mgr, world):
        super().__init__(world, 0, 0, 0)
        # The visual representation of the bullet.
        self.owner = None
        self._world = world
        self._quad = QuadDrawable()
        self._quad.texture = Texture.load_from_file(
            'resources/images/bullet.png')
        self._quad.size = Vector2(self._quad.texture.width,
                                  self._quad.texture.height)
        self._quad.anchor_to_center()
        # Attach physics only in the initialize method
        self.bullet_radius = min(self._quad.size.x,
                                 self._quad.size.y) / PHYSICS_SCALE / 2
        self._angle = None
        self.bullet_mgr = bullet_mgr

    def initialize(self, x, y, direction, speed, owner):
        self.owner = owner
        self._physics = PhysicsBullet(self, self._world.physicsWorld,
                                      x / PHYSICS_SCALE, y / PHYSICS_SCALE,
                                      self.bullet_radius, owner)

        # Physics object corresponding to the bullet
        # self._physics.body.userData = {'type': 'bullet', 'obj': self, 'owner': owner}
        # self._physics.body.position = (x / PHYSICS_SCALE, y / PHYSICS_SCALE)
        self._physics.body.angle = math.atan2(-direction.x, direction.y)
        force_dir = b2Vec2(float(direction.x), float(direction.y))
        force_pos = self._physics.body.GetWorldPoint(localPoint=(0.0, 0.0))
        self._physics.body.ApplyLinearImpulse(force_dir * speed, force_pos,
                                              True)

    def draw(self, screen):
        self._quad.draw(screen)

    def update(self, screen):
        pos = self._physics.body.position
        if pos.x < 0 or pos.x > self._world.bounds.w / PHYSICS_SCALE or \
                        pos.y < 0 or pos.y > self._world.bounds.h / PHYSICS_SCALE:
            # Bullet is outside the screen
            self.remove_bullet()
        else:
            # Update the position of the bullet
            pos *= PHYSICS_SCALE
            self._quad.pos = Vector2(pos[0], pos[1])
            self._quad.angle = self._physics.body.angle
            pos /= PHYSICS_SCALE

    def collide(self, other, began=False, **kwargs):
        # Don't do anything if a bullet is hitting a bullet.
        if isinstance(other, type(self)):
            return
        # If a bullet is hit by anything else, recycle it.
        if not began:
            self.remove_bullet()

    def remove_bullet(self):
        # Mark the associated physical object for deletion
        self.bullet_mgr.mark_for_recycle(self)
예제 #4
0
class StageDemo(StageSky):
    def __init__(self, width, height):
        super().__init__(width, height)
        texture = Texture.load_from_file('resources/images/logo.png')
        self._logo = QuadDrawable(0, 0, texture.width, texture.height)
        self._logo.anchor = Vector2(texture.width / 2, texture.height / 2)
        self._logo.texture = texture

    def update(self, game_speed):
        super().update(game_speed)
        self._logo.pos = Vector2(self.width / 2, self.height / 2)

    def draw_foreground(self, surface, window_x, window_y):
        super().draw_foreground(surface, window_x, window_y)

        self._logo.draw(surface)
예제 #5
0
class Trail(Entity):
    def __init__(self, ship, offset_x, offset_y):
        self._isBoosting = False
        self._ship = ship
        self.offset_x = offset_x
        self.offset_y = offset_y

        self.engine_trail_dimensions = Vector2(130 * self._ship.size,
                                               344 * self._ship.size)
        self.engine_trail = QuadDrawable(0, 0, self.engine_trail_dimensions.x,
                                         self.engine_trail_dimensions.y)
        self.engine_trail.texture = Texture.load_from_file(
            'resources/images/ship/trail.png')
        # Don't ask why 173...
        self.engine_trail.anchor = Vector2(65 * self._ship.size,
                                           173 * self._ship.size)
        self.engine_trail.shader = ShaderProgram.from_files(
            vert_file='resources/shaders/base.vert',
            frag_file='resources/shaders/rgba.frag')

        self.update(0, 0, False)

    def draw(self, screen):
        self.engine_trail.shader.bind()

        self.engine_trail.shader.set_uniform_1f(
            'mul_r', 0 if self._isBoosting else 0.49)
        self.engine_trail.shader.set_uniform_1f(
            'mul_g', .9 if self._isBoosting else 0.332)
        self.engine_trail.shader.set_uniform_1f(
            'mul_b', .9 if self._isBoosting else 0.059)

        self.engine_trail.draw(screen)

    def update(self, game_speed, trigger_intensity, boost):
        self._isBoosting = boost
        """`trigger_intensity` is a number from 0 to 1 representing how much a player is
        pressing the controller's right trigger.
        """
        self.engine_trail.size = self.engine_trail_dimensions * (
            1 if boost else trigger_intensity)
        self.engine_trail.pos = Vector2(
            self._ship._quad.pos.x + self.offset_x,
            self._ship._quad.pos.y + self.offset_y,
        )
        self.engine_trail.angle = self._ship._quad._angle
예제 #6
0
class Stage1(Stage):
    def __init__(self, width, height):
        super().__init__(width, height)

        self.quad = QuadDrawable(0, 0, width, height)
        self.quad.texture = Texture.load_from_file('resources/images/bg.png')

    def get_width(self):
        return self.width

    def update(self, game_speed):
        pass

    def draw_background(self, surface, window_x, window_y):
        self.quad.draw(surface)

    def draw_foreground(self, surface, window_x, window_y):
        pass
예제 #7
0
class HealthBar(Entity):
    def __init__(self, ship, world):
        super().__init__(world, ship.position.x, ship.position.y)
        self._ship = ship
        self._quad = QuadDrawable(0, 0, ship._dim.x, 5)
        self._quad.texture = Texture.load_from_file(
            'resources/images/health.png')

    def update(self, game_speed):
        self._quad.size = Vector2(
            self._ship._dim.x * self._ship.ship_state.energy /
            ShipState.MAX_ENERGY,
            self._quad.size.y,
        )
        self._quad.pos = self._position + Vector2(-self._ship._dim.x / 2,
                                                  -self._ship._dim.y / 3)

    def draw(self, screen):
        self._quad.draw(screen)
예제 #8
0
class Laser:
    def __init__(self, x, y, length, angle):
        # self.quadb = QuadDrawable(x, y, 36/8, 100/8, angle)
        # self.quadb.texture = Texture.load_from_file('resources/images/burst_b.png')
        self.quadm = QuadDrawable(x + 36 / 8, y, length, 100 / 8, angle)
        self.quadm.texture = Texture.load_from_file('resources/images/burst_m.png')
        # self.quade = QuadDrawable(x+36/8+100-4, y, 64/8, 100/8, angle)
        # self.quade.texture = Texture.load_from_file('resources/images/burst_e.png')
        self.should_be_removed = False

    def update(self, screen):
        self.quadm.size = Vector2(self.quadm.scale.x, self.quadm.scale.y * 0.9)
        if self.quadm.scale.x < 0.01:
            self.should_be_removed = True
            self.quadm.size = Vector2(0, 0)

    def draw(self, screen):
        # self.quadb.draw(screen)
        self.quadm.draw(screen)
예제 #9
0
class Sprite:
    DEBUG = False

    def __init__(self, frames_store):
        self._frames_store = frames_store
        self._x = 0
        self._y = 0
        self._flags = 0
        self._angle = 0
        self._scale = Vector2(1, 1)

        # Collision detection
        self._attack_box = None
        self._hit_box = None

        # Frames and animations
        self._frame = None
        self._animation = None
        self._animation_name = None
        self._animation_frame_index = None
        self._animation_frame_delay = 0
        self._animation_speed = 1
        self._animating = False

        # Drawing
        self._drawable = QuadDrawable()

    def draw(self, screen):
        if self._frame is None:
            return

        self._drawable.pos = Vector2(
            self._x, self._y)  # - camera.offset.x, self._y - camera.offset.y)
        self._drawable.draw(screen)

        # DEBUG boxes
        if Sprite.DEBUG:
            # TODO: !!!
            pass
            # anchor_x = self.frame.rect['x'] + self.frame.anchor['x'] - window_x
            # anchor_y = self.frame.rect['y'] + self.frame.anchor['y'] - window_y
            # pygame.draw.rect(surface, (255, 255, 255), pygame.Rect(anchor_x, anchor_y, 1, 1), 1)

            # if self.hit_box and self.hit_box.w > 0 and self.hit_box.h > 0:
            #     pygame.draw.rect(surface, (0, 200, 0), self.hit_box.move(-window_x, -window_y), 1)
            # if self.attack_box and self.attack_box.w > 0 and self.attack_box.h > 0:
            #     pygame.draw.rect(surface, (200, 0, 0), self.attack_box.move(-window_x, -window_y), 1)

    def set_frame(self, frame_name):
        self.stop_animation()
        self._animation = None
        self._frame = self._frames_store.get_frame(frame_name)

    def stop_animation(self):
        self._animation_frame_delay = 0
        self._animation_frame_index = 0
        self._animating = False

    def play_animation(self, animation_name, flags=0, speed=1):
        if (self._flags & FramesStore.FLAG_LOOP_ANIMATION) > 0 and \
                        self._flags == flags and animation_name == self._animation_name:
            return

        self._animating = True
        self._animation_speed = speed
        self._animation_name = animation_name
        self._flags = flags
        self._set_animation_frame(0)

    def skip_to_last_animation_frame(self):
        if not self._animating:
            return

        self._animating = False
        self._set_animation_frame(len(self._animation.frames) - 1)

    def update(self, game_speed):
        self._update_collision_boxes()
        if not self._animating:
            return

        if self._animation_frame_delay <= 0:
            self.next_animation_frame()
            return
        else:
            self._animation_frame_delay -= game_speed * self._animation_speed
            return

    def next_animation_frame(self):
        new_animation_frame_index = self._animation_frame_index + 1
        if new_animation_frame_index > len(self._animation.frames) - 1:
            if not (self._flags & FramesStore.FLAG_LOOP_ANIMATION) > 0:
                self._animating = False
                return
            else:
                new_animation_frame_index = 0

        self._set_animation_frame(new_animation_frame_index)

    def previous_animation_frame(self):
        new_animation_frame_index = self._animation_frame_index - 1
        if new_animation_frame_index < 0:
            new_animation_frame_index = len(self._animation.frames) - 1

        self._set_animation_frame(new_animation_frame_index)

    def _set_animation_frame(self, frame_index):
        self._animation = self._frames_store.get_animation(
            self._animation_name)
        self._animation_frame_index = frame_index
        self.animation_frame = self._animation.frames[
            self._animation_frame_index]
        new_frame = self._animation.frames[frame_index]
        self._animation_frame_delay = new_frame.delay
        self._frame = self._frames_store.get_frame(new_frame.frame_name)

        # Override animation flip if the frame is also flipped
        flags = self._flags
        if self.animation_frame.flip_x:
            flags |= FramesStore.FLAG_FLIP_X
        if self.animation_frame.flip_y:
            flags |= FramesStore.FLAG_FLIP_Y

        # Updates the drawable
        self._drawable.texture = self._frame.image
        self._drawable.scale = Vector2(self._frame.rect.w,
                                       self._frame.rect.h).dot(self._scale)
        self._drawable.anchor = self._frame.anchor.dot(self._scale)
        self._drawable.flip_x = (flags & FramesStore.FLAG_FLIP_X > 0)
        self._drawable.flip_y = (flags & FramesStore.FLAG_FLIP_Y > 0)

    def _update_collision_boxes(self):
        if not self._animating:
            self._attack_box = None
            self._hit_box = None

        # TODO: flip_y should be handled as well
        animation_frame = self._animation.frames[self._animation_frame_index]
        flip_x = ((self._flags & FramesStore.FLAG_FLIP_X) >
                  0) ^ animation_frame.flip_x

        if self._frame.hit_box:
            self._hit_box = self._frame.hit_box.copy()
            if flip_x:
                self._hit_box.x = -self._hit_box.x - self._hit_box.width
            self._hit_box.move_ip(self._x, self._y)
        else:
            self._hit_box = None

        if self._frame.attack_box:
            self._attack_box = self._frame.attack_box.copy()
            if flip_x:
                self._attack_box.x = -self._attack_box.x - self._attack_box.width
            self._attack_box.move_ip(self._x, self._y)
        else:
            self._attack_box = None

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

    @property
    def angle(self):
        return self._angle

    @angle.setter
    def angle(self, value):
        self._angle = value
        self._drawable.angle = value

    @property
    def scale(self):
        return self._scale

    @scale.setter
    def scale(self, value):
        self._scale = value
        self._drawable.scale *= value

    @property
    def hit_box(self):
        return self._hit_box

    @property
    def attack_box(self):
        return self._attack_box

    @property
    def animating(self):
        return self._animating

    @property
    def shader(self):
        return self._drawable.shader

    @shader.setter
    def shader(self, shader):
        self._drawable.shader = shader
예제 #10
0
class Ship(Entity):
    def __init__(
            self,
            world,
            bullet_mgr,
            controllers,
            x,
            y,
            z=0,
            angle=0,
            color='standard',
    ):
        super().__init__(world, x, y, z)
        self.world = world

        self._dim = Vector2(130 * SCALE, 344 * SCALE)
        self._angle = angle
        self._physicsShip = PhysicsShip(
            self,
            world.physicsWorld,
            x / config.PHYSICS_SCALE,
            y / config.PHYSICS_SCALE,
            angle=angle,
        )

        # Used by ship components to scale themselves
        self.size = SCALE

        self._quad = QuadDrawable(0, 0, self._dim.x, self._dim.y)
        self._quad.pos = self._position
        self._quad.anchor = self._dim.__div__(2.0)

        texture_file = SHIP_TEXTURES.get(color, SHIP_TEXTURES['standard'])
        self._quad.texture = Texture.load_from_file(texture_file)
        self._quad.shader = ShaderProgram.from_files(vert_file='resources/shaders/base.vert', frag_file='resources/shaders/rgba.frag')

        self.controllers = controllers
        self.pilotController = controllers[0] if len(controllers) else None
        self.shieldController = controllers[1] if len(controllers) > 1 else None
        self.turretController = controllers[2] if len(controllers) > 2 else None

        self.shields = [
            Shield(self, world),
            Shield(self, world),
        ]

        self.turret_right = Turret(self, bullet_mgr, offset_x=-59 * SCALE, offset_y=2 * SCALE)
        self.turret_left = Turret(self, bullet_mgr, offset_x=59 * SCALE, offset_y=2 * SCALE)

        self.ship_state = ShipState(self)

        self.trail = Trail(self, 0, 0)
        self.side_trail_left = SideTrail(self, 28 * SCALE, 40 * SCALE, -45)
        self.side_trail_right = SideTrail(self, -25 * SCALE, 40 * SCALE, 225)

        # self._healthbar = HealthBar(self, world)

    def update(self, game_speed):
        self._physicsShip.update_forces(self.pilotController)
        for c in self.controllers:
            c.update()
            # if c.is_button_pressed(GameController.BUTTON_DIR_PAD_UP):
            #     if self.turretController == c:
            #         self.turretController = None
            #     if self.shieldController == c:
            #         self.shieldController = None
            #     self.pilotController = c
            # elif c.is_button_pressed(GameController.BUTTON_DIR_PAD_DOWN):
            #     if self.pilotController == c:
            #         self.pilotController = None
            #     if self.shieldController == c:
            #         self.shieldController = None
            #     self.turretController = c
            # elif c.is_button_pressed(GameController.BUTTON_DIR_PAD_LEFT):
            #     if self.turretController == c:
            #         self.turretController = None
            #     if self.pilotController == c:
            #         self.pilotController = None
            #     self.shieldController = c

        if self.pilotController and self.ship_state.state == ShipState.LIVE:
            boost = self.pilotController.is_button_down(GameController.BUTTON_A)

            trigger_intensity = self.pilotController.get_axis(GameController.AXIS_TRIGGER_RIGHT) or 0.0
            self.trail.update(game_speed, trigger_intensity, boost)

            axis_intensity = self.pilotController.get_axis(GameController.AXIS_LEFT_X) or 0.0
            self.side_trail_left.update(game_speed, axis_intensity)
            self.side_trail_right.update(game_speed, -axis_intensity)

        if self.shieldController and self.ship_state.state == ShipState.LIVE:
            shield0_input_values = (
                self.shieldController.get_axis(GameController.AXIS_LEFT_X) or 0.0,
                self.shieldController.get_axis(GameController.AXIS_LEFT_Y) or 0.0, 0.0,
            )
            shield1_input_values = (
                self.shieldController.get_axis(GameController.AXIS_RIGHT_X) or 0.0,
                self.shieldController.get_axis(GameController.AXIS_RIGHT_Y) or 0.0, 0.0,
            )
        else:
            shield0_input_values = (0.0, 0.0, 0.0)
            shield1_input_values = (0.0, 0.0, 0.0)

        self.shields[0].update(game_speed, shield0_input_values)
        self.shields[1].update(game_speed, shield1_input_values)

        if self.turretController and self.ship_state.state == ShipState.LIVE:
            turret_left_x, turret_left_y = (
                self.turretController.get_axis(GameController.AXIS_LEFT_X) or 0.0,
                self.turretController.get_axis(GameController.AXIS_LEFT_Y) or 0.0,
            )
            turret_right_x, turret_right_y = (
                self.turretController.get_axis(GameController.AXIS_RIGHT_X) or 0.0,
                self.turretController.get_axis(GameController.AXIS_RIGHT_Y) or 0.0,
            )

            threshold = 0.2
            turret_left_fire = (self.turretController.get_axis(GameController.AXIS_TRIGGER_LEFT) or 0.0) > threshold
            turret_right_fire = (self.turretController.get_axis(GameController.AXIS_TRIGGER_RIGHT) or 0.0) > threshold

        else:
            turret_left_x, turret_left_y = (0, 0)
            turret_right_x, turret_right_y = (0, 0)
            turret_left_fire = turret_right_fire = False

        self.turret_left.update(
            game_speed,
            turret_left_x,
            turret_left_y,
            turret_left_fire,
            is_right_wing=False,
        )
        self.turret_right.update(
            game_speed,
            turret_right_x,
            turret_right_y,
            turret_right_fire,
            is_right_wing=True,
        )

        self._angle = self._physicsShip.body.angle + math.pi
        pos = self._physicsShip.body.position * config.PHYSICS_SCALE
        self._position = Vector2(pos[0], pos[1])
        self._quad.pos = self._position
        self._quad.angle = self._angle

        self.ship_state.update(
            time_passed_ms=(game_speed * config.GAME_FRAME_MS),
        )

        # self._healthbar.update(game_speed)

    def draw(self, screen):
        if self.is_live():
            for shield in self.shields:
                shield.draw(screen)

            self.trail.draw(screen)
            self.side_trail_left.draw(screen)
            self.side_trail_right.draw(screen)

            if self.has_recent_damage():
                energy_ratio = self.ship_state.energy / self.ship_state.MAX_ENERGY
                damage_ratio = 1.0 - energy_ratio
                self._quad.shader.bind()
                self._quad.shader.set_uniform_1f('mul_r', 0.0)
                self._quad.shader.set_uniform_1f('mul_g', 0.2 + 0.8 * damage_ratio)
                self._quad.shader.set_uniform_1f('mul_b', 0.2 + 0.8 * damage_ratio)
            else:
                self._quad.shader.bind()
                self._quad.shader.set_uniform_1f('mul_r', 0.0)
                self._quad.shader.set_uniform_1f('mul_g', 0.0)
                self._quad.shader.set_uniform_1f('mul_b', 0.0)

            self.turret_left.draw(screen)
            self.turret_right.draw(screen)

            # Important: this has to be drawn AFTER the trails and turrets (to
            # be positioned on top of them)
            self._quad.draw(screen)

    def destroy_ship(self):
        pos = self._physicsShip.body.position * config.PHYSICS_SCALE
        x, y = pos

        self.world.asteroids.append(Asteroid(
            self.world,
            x, y - 30,
            Vector2(random() * 30 - 15, random() * -100),
               random() * 3.0,
            'resources/images/derelict/part_01.png', config.SHIP_SCALE
        ))
        self.world.asteroids.append(Asteroid(
            self.world,
            x + 30, y + 30,
            Vector2(random() * 60 + 30, random() * 60 + 30),
            random() * 3.0,
            'resources/images/derelict/part_02.png', config.SHIP_SCALE
        ))
        self.world.asteroids.append(Asteroid(
            self.world,
            x - 30, y + 30,
            Vector2(random() * -60 - 30, random() * 60 + 30),
            random() * 3.0,
            'resources/images/derelict/part_03.png', config.SHIP_SCALE
        ))

        self.world.asteroids.append(Asteroid(
            self.world,
            x, y - 30,
            Vector2(random() * 3.0 - 1.5, random() * -10),
               random() * 3.0,
            'resources/images/people/pilot.png', config.SHIP_SCALE
        ))
        self.world.asteroids.append(Asteroid(
            self.world,
            x + 30, y + 30,
            Vector2(random() * 6.0 + 3.0, random() * 6.0 + 3.0),
            random() * 3.0,
            'resources/images/people/gunner.png', config.SHIP_SCALE
        ))
        self.world.asteroids.append(Asteroid(
            self.world,
            x - 30, y + 30,
            Vector2(random() * -6.0 - 3.0, random() * 6.0 + 3.0),
            random() * 3.0,
            'resources/images/people/technician.png', config.SHIP_SCALE
        ))

    def is_live(self):
        return self.ship_state.state == ShipState.LIVE

    def has_recent_damage(self):
        return self.ship_state.has_recent_damage

    def collide(self, other, intensity=10.0, **kwargs):
        # TODO: Calculate the damage:
        # Collision between shield and bullet (sensor)
        # Collision between shield and everything else
        self.ship_state.damage(energy=10.0)

    def heal(self, amount):
        self.ship_state.heal(amount)
예제 #11
0
파일: font.py 프로젝트: maxfish/mgl2d
class Font:
    def __init__(self):
        self._font_faces = {}
        self._page_textures = {}
        self._character_program = ShaderProgram.from_sources(
            vert_source=self.vert_shader_base,
            frag_source=self.frag_shader_texture)
        self._quad = QuadDrawable()
        self._quad.shader = self._character_program

    def load_bmfont_file(self, filename):
        base_dir = dirname(filename)
        font_def = BMFontDef(filename)
        self._font_faces[font_def.size] = font_def
        self._page_textures[font_def.size] = []
        for file in font_def.page_files:
            path = base_dir + '/' + file
            self._page_textures[font_def.size].append(
                Texture().load_from_file(path))

    def draw_string(self, screen, font_size, string, x, y, scale=1):
        font = self._font_faces[font_size]
        for char in string:
            c = font.get_char(char)
            self._quad.texture = self._page_textures[font_size][c.page_index]
            self._quad.size = Vector2(c.width, c.height) * scale
            self._quad.pos = Vector2(x + c.offset_x * scale,
                                     y + c.offset_y * scale)
            self._character_program.bind()
            self._character_program.set_uniform_2f('area_pos',
                                                   c.x / font.page_width,
                                                   c.y / font.page_height)
            self._character_program.set_uniform_2f('area_size',
                                                   c.width / font.page_width,
                                                   c.height / font.page_height)
            self._quad.draw(screen)
            x += c.advance_x * scale

    def draw_char(self, screen, font_size, char, x, y, scale=1):
        font = self._font_faces[font_size]
        c = font.get_char(char)
        s = self._character_program

        self._quad.texture = self._page_textures[font_size][c.page_index]
        self._quad.size = Vector2(c.width, c.height) * scale
        self._quad.pos = Vector2(x, y + c.offset_y * scale)
        self._quad.shader = s
        s.bind()
        s.set_uniform_matrix4('projection', screen.projection_matrix.m)
        s.set_uniform_2f('area_pos', c.x / font.page_width,
                         c.y / font.page_height)
        s.set_uniform_2f('area_size', c.width / font.page_width,
                         c.height / font.page_height)
        self._quad.draw(screen)

        return c.advance_x

    vert_shader_base = """
        #version 330 core

        uniform mat4 model;
        uniform mat4 projection;
        uniform vec2 area_pos;
        uniform vec2 area_size;

        layout(location=0) in vec2 vertex;
        layout(location=1) in vec2 uv;

        out vec2 uv_out;

        void main() {
            vec2 texture_out = uv;
            if (gl_VertexID == 0) {
                texture_out = area_pos;
            } else if (gl_VertexID == 1) {
                texture_out = vec2(area_pos.x, area_pos.y+area_size.y);
            } else if (gl_VertexID == 2) {
                texture_out = vec2(area_pos.x+area_size.x, area_pos.y+area_size.y);
            } else if (gl_VertexID == 3) {
                texture_out = vec2(area_pos.x+area_size.x, area_pos.y);
            }
            
            vec4 vertex_world = model * vec4(vertex, 1, 1);
            gl_Position = projection * vertex_world;
            uv_out = texture_out;
        }
        """

    frag_shader_texture = """
예제 #12
0
class StageSky(Stage):
    def __init__(self, width, height):
        super().__init__(width, height)
        self.quad = QuadDrawable(0, 0, width, height)
        self.quad.texture = Texture.load_from_file('resources/images/bg.png')
        number_of_planets = 9
        self.planets = []
        number_of_clouds_background = 5
        number_of_clouds_foreground = 5

        self.clouds_background = []
        self.clouds_foreground = []

        # Generate the list of planets
        self.generate_planets(number_of_planets, width, height)
        # Generate the list of clouds
        self.generate_clouds_background(number_of_clouds_background, width, height)
        self.generate_clouds_foreground(number_of_clouds_foreground, width, height)

    def get_width(self):
        return self.width

    def update(self, game_speed):
        for planet in self.planets:
            planet.update(game_speed)
        for cloud in self.clouds_foreground:
            cloud.update(game_speed)
        for cloud in self.clouds_background:
            cloud.update(game_speed)

    def draw_background(self, surface, window_x, window_y):
        self.quad.draw(surface)
        for planet in self.planets:
            planet.draw(surface)
        for cloud in self.clouds_background:
            cloud.draw(surface)

    def draw_foreground(self, surface, window_x, window_y):
        for cloud in self.clouds_foreground:
            cloud.draw(surface)

    def generate_planets(self, number_of_planets, width, height):
        planet_picture_list = [f for f in listdir('resources/images/planets') if
                               isfile(join('resources/images/planets', f))]
        number_per_areas = number_of_planets // 4
        for x in range(0, number_per_areas):
            p = Planet(width / 2, height / 2, width, height, planet_picture_list)
            self.planets.append(p)
        for x in range(number_per_areas, number_per_areas * 2):
            p = Planet(width / 2, 0, width, height, planet_picture_list)
            self.planets.append(p)
        for x in range(number_per_areas * 2, number_per_areas * 3):
            p = Planet(0, height / 2, width, height, planet_picture_list)
            self.planets.append(p)
        for x in range(number_per_areas * 3, number_per_areas * 4):
            p = Planet(0, 0, width, height, planet_picture_list)
            self.planets.append(p)

    def generate_clouds_background(self, number_of_clouds, width, height):
        planet_picture_list = [f for f in listdir('resources/images/clouds') if
                               isfile(join('resources/images/clouds', f))]
        for x in range(0, number_of_clouds):
            cloud = Cloud(width, height, planet_picture_list)
            self.clouds_background.append(cloud)

    def generate_clouds_foreground(self, number_of_clouds, width, height):
        planet_picture_list = [f for f in listdir('resources/images/clouds') if
                               isfile(join('resources/images/clouds', f))]
        for x in range(0, number_of_clouds):
            cloud = Cloud(width, height, planet_picture_list)
            self.clouds_foreground.append(cloud)
예제 #13
0
파일: tmx_map.py 프로젝트: maxfish/mgl2d
class TMXMap(object):
    def __init__(self, filename):
        self._tmx_data = pytmx.TiledMap(filename,
                                        invert_y=True,
                                        image_loader=self._image_loader)
        self._size = self._tmx_data.width * self._tmx_data.tilewidth, self._tmx_data.height * self._tmx_data.tileheight
        self._layer_offsets = [
            Vector2(0, 0) for _ in range(0, len(self._tmx_data.layers))
        ]
        self._drawable = QuadDrawable()

    @staticmethod
    def _image_loader(filename, colorkey, **kwargs):
        if colorkey:
            logger.error('colorkey not implemented')

        image = Texture.load_from_file(filename)

        def load_image(rect=None, flags=None):
            if rect:
                try:
                    x, y, w, h = rect
                    y = image.height - y - h
                    tile = image.get_region(x, y, w, h)
                except:
                    logger.error('cannot get region %s of image', rect)
                    raise
            else:
                tile = image

            if flags:
                logger.error('tile flags are not implemented')

            return tile

        return load_image

    @property
    def width_in_pixels(self):
        return self._size[0]

    @property
    def height_in_pixels(self):
        return self._size[1]

    def draw(self, screen):
        self.draw_layers_range(screen, 0, len(self._tmx_data.layers))

    def draw_layers_range(self, screen, start, how_many):
        for index in range(start, start + how_many):
            layer = self._tmx_data.layers[index]
            if layer.visible == 0:
                continue

            offset_x = layer.offsetx + self._layer_offsets[index].x
            offset_y = layer.offsety + self._layer_offsets[index].y

            if isinstance(layer, pytmx.TiledTileLayer):
                # for x, y, image in layer.tiles():
                pass
            elif isinstance(layer, pytmx.TiledObjectGroup):
                for obj in layer:
                    if hasattr(obj, 'points'):
                        # draw_lines(poly_color, obj.closed, obj.points, 3)
                        pass
                    elif obj.image:
                        self._drawable.texture = obj.image
                        self._drawable.scale = Vector2(obj.width, obj.height)
                        self._drawable.pos = Vector2(obj.x - offset_x,
                                                     obj.y - offset_y)
                        self._drawable.draw(screen)

                        # obj.image.blit(obj.x - offset_x, (Gfx.screen_height - obj.y) - offset_y, 0, w, h)
                    else:
                        # draw_rect(rect_color, (obj.x, obj.y, obj.width, obj.height), 3)
                        pass
            elif isinstance(layer, pytmx.TiledImageLayer):
                if layer.image:
                    pass

    def set_layer_offset(self, layer_index, x, y):
        self._layer_offsets[layer_index].x = x
        self._layer_offsets[layer_index].y = y

    def all_objects_as_dict(self, layer_name):
        # Note: there shouldn't be duplicate or missing names
        if layer_name not in self._tmx_data.layernames:
            return {}

        objects = dict()
        layer = self._tmx_data.layernames[layer_name]
        for obj in layer:
            objects[obj.name] = obj

        return objects

    def all_objects_as_list(self, layer_name):
        if layer_name not in self._tmx_data.layernames:
            return []

        return list(self._tmx_data.layernames[layer_name])
예제 #14
0
class Shield(Entity):
    def __init__(self, ship, world):
        super().__init__(ship._world, 0, 0)
        self._ship = ship

        self._quad = QuadDrawable(0, 0, 0, 0)
        self._quad.texture = Texture.load_from_file(
            'resources/images/shield_arc.png')
        self._quad.shader = ShaderProgram.from_files(
            vert_file='resources/shaders/base.vert',
            frag_file='resources/shaders/rgba.frag')
        self._quad.size = Vector2(self._quad.texture.width,
                                  self._quad.texture.height) * 0.67
        self._quad.anchor = Vector2(0, self._quad.size.y / 2)

        self._physicsShield = PhysicsShield(
            self,
            ship._physicsShip,
            world.physicsWorld,
            center=self._ship._physicsShip.body.position,
            radius=(self._quad.size.x / PHYSICS_SCALE) * 1.1,
        )
        self._collision_timer = 0

        self._rad1 = ship._dim.y / 2.9
        self._rad2 = ship._dim.y / 2.9
        self._angle = 0
        self._angle_speed = 1
        self._enable = False
        self._charge = 0
        self.shield_state = ShieldState(self)
        self.update(0, (0.0, 0.0, 0.0))

    def calc_angle(self, x, y):
        if INERTIA:
            mag = math.sqrt(x * x + y * y)
            self._angle_speed = max(1, self._angle_speed * mag)

            if mag > 0.001:
                theta = math.atan2(y, x)
                self._angle_speed = min(self._angle_speed * 1.01, 6)
            else:
                return self._angle

            delta = theta - self._angle
            delta = (delta + math.pi) % (2 * math.pi) - math.pi
            step = delta * self._angle_speed / 8.0
            return self._angle + step
        else:
            return math.atan2(y, x)

    def update(self, game_speed, input_values):
        x, y, trigger = input_values
        if input_values == (0.0, 0.0, 0.0):
            # If the shields aren't being used, don't display them
            self._enable = False
        else:
            self._enable = True
            self.update_angle_position(x, y)

        self._physicsShield.body.position = self._ship._physicsShip.body.position
        self.shield_state.advance_time(time_passed_ms=(game_speed *
                                                       config.GAME_FRAME_MS), )
        self._collision_timer -= game_speed * config.GAME_FRAME_MS

    def update_angle_position(self, x, y):
        self._angle = self.calc_angle(x, y)
        self._quad.pos = self._ship._position
        self._quad.angle = self._angle

    def draw(self, screen):
        if not self._enable:
            return

        self._quad.shader.bind()
        if self._collision_timer > 0:
            self._quad.shader.set_uniform_1f('mul_r', 0)
            self._quad.shader.set_uniform_1f('mul_g', 0.8)
            self._quad.shader.set_uniform_1f('mul_b', 0.8)
        else:
            self._quad.shader.set_uniform_1f('mul_g', 0)
            self._quad.shader.set_uniform_1f('mul_b', 1)
            self._quad.shader.set_uniform_1f('mul_r', 1)

        # if self.shield_state.is_healthy:
        self._quad.draw(screen)

    def collide(self, other, intensity=0.0, began=False, **kwargs):
        if not self._enable:
            return

        body = kwargs['body']
        other_body = kwargs['other_body']
        # Collision between shield and everything else
        self.shield_state.damage(energy=10.0)
        # Heal the ship so it has a purpose -- take less damage
        # self._ship.heal(5.0)
        if began:
            incoming_pos = other_body.position
            vector = incoming_pos - body.position
            direction = b2Vec2(vector.x, vector.y)
            direction.Normalize()
            incoming_angle = math.atan2(direction.y, direction.x)
            incoming_angle = (incoming_angle + math.pi * 2) % (math.pi * 2)
            shield_angle = (self._angle + math.pi * 2) % (math.pi * 2)
            shield_angle2 = (self._angle + math.pi * 2) % (math.pi * 2) + (
                math.pi * 2)
            shield_angle3 = (self._angle + math.pi * 2) % (math.pi * 2) - (
                math.pi * 2)
            if (shield_angle - HALF_ARC_DEGREES < incoming_angle < shield_angle + HALF_ARC_DEGREES) or \
                    (shield_angle2 - HALF_ARC_DEGREES < incoming_angle < shield_angle2 + HALF_ARC_DEGREES) or \
                    (shield_angle3 - HALF_ARC_DEGREES < incoming_angle < shield_angle3 + HALF_ARC_DEGREES):
                self._collision_timer = 400
예제 #15
0
class Asteroid(Entity):
    def __init__(
            self,
            world,
            x,
            y,
            speed,
            torque,
            asset='resources/images/asteroides/asteroid_01.png',
            scale=1,
    ):
        super().__init__(world, x, y, 0)
        # Slightly smaller than the image
        texture = Texture.load_from_file(asset)
        image_size = min(texture.width, texture.height)

        radius = ((image_size / PHYSICS_SCALE) / 2) * 0.8

        self._quad = QuadDrawable(x, y, texture.width * scale, texture.height * scale)
        self._quad.anchor_to_center()
        self._quad.texture = texture
        self._quad.shader = ShaderProgram.from_files(vert_file='resources/shaders/base.vert', frag_file='resources/shaders/rgba.frag')

        self._physicAsteroid = PhysicsAsteroid(
            self,
            world.physicsWorld,
            center=Vector2(x / PHYSICS_SCALE, y / PHYSICS_SCALE),
            radius=radius,
            speed=speed,
            torque=torque,
        )

    def update(self, game_speed):
        self._physicAsteroid.update_forces()
        self._quad.pos = self._physicAsteroid.body.position * PHYSICS_SCALE
        self._quad.angle = self._physicAsteroid.body.angle
        pass

    def draw(self, screen):
        self._quad.shader.bind()
        self._quad.shader.set_uniform_1f('mul_r', 0.3)
        self._quad.shader.set_uniform_1f('mul_g', 0.3)
        self._quad.shader.set_uniform_1f('mul_b', 0.3)
        self._quad.draw(screen)
        pass

    def collide(self, other, **kwargs):
        pass

    def destroy(self):
        goes_to_left = self._physicAsteroid.body.linearVelocity.x < 0
        goes_to_right = not goes_to_left
        goes_to_top = self._physicAsteroid.body.linearVelocity.y < 0
        goes_to_bottom = not goes_to_top

        return (goes_to_left and
                self._physicAsteroid.body.position.x <
                0 - self._physicAsteroid.shape.radius) or \
               (goes_to_right and
                (self._physicAsteroid.body.position.x * PHYSICS_SCALE >
                 SCREEN_WIDTH + self._physicAsteroid.shape.radius)) or \
               (goes_to_top and
                (self._physicAsteroid.body.position.y <
                 0 - self._physicAsteroid.shape.radius)) or \
               (goes_to_bottom and
                (self._physicAsteroid.body.position.y * PHYSICS_SCALE >
                 SCREEN_HEIGHT + - self._physicAsteroid.shape.radius))
예제 #16
0
class World:
    SCENE_NONE = 0
    SCENE_TITLE = 1
    SCENE_GAME = 2
    SCENE_GAME_OVER = 4

    def __init__(self, bounds, controllers, stage, debug=0):
        self.scene = self.SCENE_TITLE
        self.game_over_timer = 0
        self.stage = stage

        self.game_over_quad = QuadDrawable(
            SCREEN_WIDTH / 2 - 496 / 2,
            SCREEN_HEIGHT / 2 - 321 / 2,
            496,
            321,
        )
        self.game_over_quad.texture = Texture.load_from_file(
            'resources/images/game_over.png')

        self.bounds = bounds
        self.debug = debug

        self.window_x = 0
        self.window_y = 0

        self.physicsWorld = b2World(gravity=(0, 0),
                                    contactListener=ContactListener())
        # Physical bodies should be deleted outside the simulation step.
        self.physics_to_delete = []
        self._shapes = Shapes()

        self.controllers = controllers

        self.bullet_mgr = bullet_mgr = BulletManager(self)

        self.players = []
        self.entities = [bullet_mgr]

        def batch(iterable, n=1):
            l = len(iterable)
            for ndx in range(0, l, n):
                yield iterable[ndx:min(ndx + n, l)]

        quadrant = 0
        for cs in batch(controllers, 3):
            x = 300 + (SCREEN_WIDTH -
                       600) * (quadrant & 1) + 100 * random.uniform(-1, 1)
            y = 200 + (SCREEN_HEIGHT -
                       400) * (quadrant >> 1 & 1) + 50 * random.uniform(-1, 1)
            ship = Ship(
                self,
                bullet_mgr,
                controllers=cs,
                x=x,
                y=y,
                # angle=math.degrees(math.atan2(y, x)) - 180
                color=SHIP_TEXTURES[list(SHIP_TEXTURES.keys())[quadrant]],
            )
            self.players.append(ship)
            self.entities.append(ship)
            quadrant += 1

        self.asteroids = []
        # self.generate_asteroid()

    def restart_game(self):
        # This is not enough, you need to re-init players
        self.__init__(
            bounds=self.bounds,
            controllers=self.controllers,
            stage=self.stage,
            debug=self.debug,
        )

    def begin(self):
        self.scene = self.SCENE_GAME
        # for character in self.characters:
        #     character.begin()

    def update(self, game_speed):
        time_delta = game_speed * config.GAME_FRAME_MS
        alive = 0
        for p in self.players:
            if p.is_live():
                alive += 1

        if alive <= 1 and self.game_over_timer <= 0:
            self.game_over_timer = 5000

        if self.game_over_timer > 0 and self.game_over_timer < time_delta:
            self.restart_game()
            return

        self.game_over_timer -= time_delta

        if self.game_over_timer <= 0:
            self.game_over_timer = 0

        self.stage.update(game_speed)
        for e in self.asteroids:
            e.update(game_speed)
        for e in self.entities:
            e.update(game_speed)

        if random.randint(0, 10000) < 100:
            self.generate_asteroid()

        self.check_asteroids()

        # Check position of physical objects
        for e in self.entities:
            if not isinstance(e, Ship):
                continue

            pos = e._physicsShip.body.position
            force_dir = Vector2()
            if pos.x < 0:
                force_dir = Vector2(1, 0)
            elif pos.x > self.bounds.w / PHYSICS_SCALE:
                force_dir = Vector2(-1, 0)
            elif pos.y < 0:
                force_dir = Vector2(0, 1)
            elif pos.y > self.bounds.h / PHYSICS_SCALE:
                force_dir = Vector2(0, -1)

            intensity = 100
            force_dir *= intensity
            force_apply_pos = e._physicsShip.body.GetWorldPoint(
                localPoint=(0.0, 0.0))
            e._physicsShip.body.ApplyLinearImpulse((force_dir.x, force_dir.y),
                                                   force_apply_pos, True)

    def draw(self, screen):
        self.stage.draw_background(screen, self.window_x, self.window_y)

        for e in self.asteroids:
            e.draw(screen)
        for e in self.entities:
            e.draw(screen)

        self.stage.draw_foreground(screen, self.window_x, self.window_y)
        if config.PHYSICS_DEBUG_DRAW_BODIES:
            self._draw_physics_bodies(screen)

        if self.game_over_timer > 0:
            self.game_over_quad.draw(screen)

    def _draw_physics_bodies(self, screen):
        for body in self.physicsWorld.bodies:
            for fixture in body.fixtures:
                if isinstance(fixture.shape, b2PolygonShape):
                    vertices = [(body.transform * v) * PHYSICS_SCALE
                                for v in fixture.shape.vertices]
                    vertices = [(v[0], v[1]) for v in vertices]
                    # Add the first point again to close the polygon
                    vertices.append(vertices[0])
                    self._shapes.draw_polyline(screen, vertices,
                                               Color(1, 0, 0, 1))
                elif isinstance(fixture.shape, b2CircleShape):
                    center = (body.transform *
                              fixture.shape.pos) * PHYSICS_SCALE
                    radius = fixture.shape.radius * PHYSICS_SCALE
                    self._shapes.draw_circle(screen,
                                             center.x,
                                             center.y,
                                             radius,
                                             Color(1, 0, 0, 1),
                                             start_angle=body.angle)

    def game_over(self):
        self.scene = self.SCENE_GAME_OVER

    def generate_asteroid(self):
        # Picks a random movement direction
        direction = Vector2()
        angle = random.random() * math.pi * 2
        direction.x = math.cos(angle)
        direction.y = math.sin(angle)

        # Places the asteroid outside of the screen
        position = Vector2()
        position.x = SCREEN_WIDTH / 2 + direction.x * (SCREEN_WIDTH / 1.5)
        position.y = SCREEN_HEIGHT / 2 + direction.y * (SCREEN_HEIGHT / 1.5)

        speed = -Vector2(direction.x, direction.y) * 1000 * random.random()
        torque = 1 * random.random()
        asteroid = Asteroid(self,
                            position.x,
                            position.y,
                            speed=speed,
                            torque=torque)
        self.asteroids.append(asteroid)

    def check_asteroids(self):
        for asteroid in self.asteroids:
            if asteroid.destroy():
                self.asteroids.remove(asteroid)