def reset_game(self): """Reset score and position.""" self.l_score = 0 self.r_score = 0 self.finish = False self.music.start_music() self.l_paddle = Paddle( coordinates=(PADDLE_SIDE, (HEIGHT - PADDLE_HEIGHT) // 2), colour=COL_PADDLE, width=PADDLE_WIDTH, height=PADDLE_HEIGHT, control_up=pyxel.KEY_W, control_down=pyxel.KEY_S, move_speed=PADDLE_MOVE_SPEED, dimensions=DIMENSIONS, ) self.r_paddle = Paddle( coordinates=( WIDTH - PADDLE_SIDE - PADDLE_WIDTH, (HEIGHT - PADDLE_HEIGHT) // 2, ), colour=COL_PADDLE, width=PADDLE_WIDTH, height=PADDLE_HEIGHT, control_up=pyxel.KEY_UP, control_down=pyxel.KEY_DOWN, move_speed=PADDLE_MOVE_SPEED, dimensions=DIMENSIONS, ) self.ball = Ball( coordinates=(WIDTH // 2, HEIGHT // 2), colour=COL_BALL, width=BALL_SIDE, height=BALL_SIDE, initial_velocity=BALL_INITIAL_VELOCITY, dimensions=DIMENSIONS, ) self.sparkler = ParticleEmitter(self.ball) pickup_types = { "sparkle": PickupType(14, self.sparkler.turn_on, self.sparkler.turn_off), "expand": PickupType(12, self.expand_paddle, self.contract_paddle), "slow": PickupType(8, self.slow_paddle, self.speed_paddle), "bounce": PickupType(11, self.ball.bounce_on, self.ball.bounce_off), "giantball": PickupType(10, self.ball.giant_on, self.ball.giant_off), } self.expand_stack = [] self.speed_stack = [] pickup_side_buffer = PADDLE_WIDTH + PADDLE_SIDE + 2 self.pickups = Pickups( pickup_types, self.music, pickup_side_buffer, WIDTH - pickup_side_buffer, 0, HEIGHT ) self.reset_after_score()
def game_loop(self): """Main simulation loop.""" # model to be subjected to the particle chamber self.model = Model(*self.WINDOW_RES, 'player_ship.png') self.models = pygame.sprite.Group() self.models.add(self.model) # Particle emitters self.particles = pygame.sprite.Group() self.emitters = [] for x_col in range( self.model.rect.left - (self.particle_x_step_res * 3), self.model.rect.right + (self.particle_x_step_res * 3), self.particle_x_step_res): emitter = ParticleEmitter(*self.WINDOW_RES, x_col, self.model.rect.top - 100, self.particles) self.emitters.append(emitter) # main loop while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() # Update sprites for emitter in self.emitters: emitter.update() self.model.update() for particle in self.particles: particle.update() # Draw sprites self.DISPLAYSURF.fill(self.BG_COLOR) self.model.draw(self.DISPLAYSURF) for particle in self.particles: particle.draw(self.DISPLAYSURF) # Detect collision between model and particles colliding_particles = pygame.sprite.groupcollide( self.particles, self.models, False, False, pygame.sprite.collide_mask) for particle in colliding_particles: if type(particle) is Particle: particle.bounce() pygame.display.update() self.FramePerSec.tick(self.FPS)
def add_component(self, type_): def fail(): raise Exception( f'Cannot add component {type_}, as another component is interfering with it.', 'sprite.Sprite.add_component(type_)') new_component = None if type_ == 'body': if self.get_component('body') is False: new_component = Body(self) else: fail() elif type_ == 'image': if self.get_component('image') is False and self.get_component( 'rect renderer') is False and \ self.get_component('circle renderer') is False: new_component = Image() else: fail() elif type_ == 'rect renderer': if self.get_component('image') is False and self.get_component( 'rect renderer') is False and \ self.get_component('circle renderer') is False: new_component = RectRenderer(self) else: fail() elif type_ == 'script': new_component = ScriptComponent() elif type_ == 'collider': if not self.get_component('collider') and not self.get_component( 'composite collider'): new_component = Collider(self) elif type_ == 'composite collider': if not self.get_component('collider') and not self.get_component( 'composite collider'): new_component = CompositeCollider(self) elif type_ == 'animation': if not self.get_component('animation'): new_component = Animation(self) elif type_ == 'particle emitter': if not self.get_component('particle emitter'): new_component = ParticleEmitter(self) if new_component is not None: self.components.append(new_component) return new_component else: raise Exception(f"component {type_} does not exist")
def __init__(self): pyxel.init(240, 160, caption='test game') self.levelname = 'level2' self.assets_dir = 'assets' self.assets = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__), self.assets_dir, self.levelname)) pyxel.image(0).load(0, 0, os.path.join(self.assets, '../animation.png')) pyxel.image(1).load(0, 0, os.path.join(self.assets, 'tileset.png')) pyxel.image(2).load(0, 0, os.path.join(self.assets, 'background.png')) self.level = Level(self.assets, 'mapfile.txt', 16) self.camera = Camera(self.level) self.player = Player() self.sparkle_emitter = ParticleEmitter(self.player) self.test_val = 0 pyxel.run(self.update, self.draw)
class App: def __init__(self): pyxel.init(240, 160, caption='test game') self.levelname = 'level1' self.assets = os.path.join( os.getcwd(), os.path.dirname(__file__), 'assets', ) pyxel.image(0).load(0, 0, os.path.join(self.assets, 'animation.png')) pyxel.image(1).load( 0, 0, os.path.join(self.assets, self.levelname, 'tileset.png')) pyxel.image(2).load( 0, 0, os.path.join(self.assets, self.levelname, 'background.png')) self.level = Level(os.path.join(self.assets, self.levelname), 'mapfile.txt', 16) self.camera = Camera(self.level) self.player = Player(self.assets) self.sparkle_emitter = ParticleEmitter(self.player) self.zero_frame = 0 pyxel.run(self.update, self.draw) def update(self): if pyxel.btn(pyxel.KEY_A): self.player.run(-1) if pyxel.btn(pyxel.KEY_D): self.player.run(1) if pyxel.btn(pyxel.KEY_W): if self.player.on_wall: self.player.climb(-1) if pyxel.btn(pyxel.KEY_S): if self.player.on_wall: self.player.climb(1) if pyxel.btnp(pyxel.KEY_L): self.player.attack() if pyxel.btnp(pyxel.KEY_SPACE): if self.player.on_wall: self.player.wall_jump() elif self.player.grounded: self.player.jump() elif self.player.double_primed: self.player.double_jump() if pyxel.btn(pyxel.KEY_ESCAPE): pyxel.quit() self.camera.update_last_offset() self.update_player() def draw(self): pyxel.cls(1) pyxel.blt(0, 0, 2, 0, 0, 240, 70, 1) # render the city # for i in range(2): # pyxel.blt(i * 240 - self.camera.offset_x/2, 39, 2, 0, 82, 240, 82, 1) # render the clouds for i in range(2): pyxel.blt(i * 240 - self.camera.offset_x // 50, 10 - self.camera.offset_y // 50, 2, 0, 168, 240, 40, 1) self.level.render(self.camera, self.level.background, 1) self.level.render(self.camera, self.level.collision, 1) self.sparkle_emitter.render_particles() self.player.update_anim() self.level.render(self.camera, self.level.foreground, 1) def update_player(self): self.player.x, self.camera.offset_x = update_axis( self.player.x, self.player.vx, self.camera.offset_x, self.camera.max_scroll_x, pyxel.width, ) self.player.x_collision(self.camera, self.level) self.player.y, self.camera.offset_y = update_axis( self.player.y, self.player.vy, self.camera.offset_y, self.camera.max_scroll_y, pyxel.height, ) self.player.y_collision(self.camera, self.level) self.player.update_gravity() self.sparkle_emitter.update_position(self.camera.offset_delta()) self.sparkle_emitter.sparkle(0, 1, 12)
class Pong: """The class that sets up and runs the game.""" def __init__(self): """Initiate pyxel, set up initial game variables, and run.""" pyxel.init(WIDTH, HEIGHT, caption="Pong!", scale=8, fps=60) self.music = Music() self.reset_game() pyxel.run(self.update, self.draw) def reset_game(self): """Reset score and position.""" self.l_score = 0 self.r_score = 0 self.finish = False self.music.start_music() self.l_paddle = Paddle( coordinates=(PADDLE_SIDE, (HEIGHT - PADDLE_HEIGHT) // 2), colour=COL_PADDLE, width=PADDLE_WIDTH, height=PADDLE_HEIGHT, control_up=pyxel.KEY_W, control_down=pyxel.KEY_S, move_speed=PADDLE_MOVE_SPEED, dimensions=DIMENSIONS, ) self.r_paddle = Paddle( coordinates=( WIDTH - PADDLE_SIDE - PADDLE_WIDTH, (HEIGHT - PADDLE_HEIGHT) // 2, ), colour=COL_PADDLE, width=PADDLE_WIDTH, height=PADDLE_HEIGHT, control_up=pyxel.KEY_UP, control_down=pyxel.KEY_DOWN, move_speed=PADDLE_MOVE_SPEED, dimensions=DIMENSIONS, ) self.ball = Ball( coordinates=(WIDTH // 2, HEIGHT // 2), colour=COL_BALL, width=BALL_SIDE, height=BALL_SIDE, initial_velocity=BALL_INITIAL_VELOCITY, dimensions=DIMENSIONS, ) self.sparkler = ParticleEmitter(self.ball) pickup_types = { "sparkle": PickupType(14, self.sparkler.turn_on, self.sparkler.turn_off), "expand": PickupType(12, self.expand_paddle, self.contract_paddle), "slow": PickupType(8, self.slow_paddle, self.speed_paddle), "bounce": PickupType(11, self.ball.bounce_on, self.ball.bounce_off), "giantball": PickupType(10, self.ball.giant_on, self.ball.giant_off), } self.expand_stack = [] self.speed_stack = [] pickup_side_buffer = PADDLE_WIDTH + PADDLE_SIDE + 2 self.pickups = Pickups( pickup_types, self.music, pickup_side_buffer, WIDTH - pickup_side_buffer, 0, HEIGHT ) self.reset_after_score() def reset_after_score(self): """Reset paddles and ball.""" self.start = pyxel.frame_count + 50 self.speed_up = self.start + SPEED_PERIOD self.ball.reset() ############## # Game logic # ############## def update(self): """Update logic of game. Updates the paddles, ball, and checks for scoring/win condition.""" self.l_paddle.update() self.r_paddle.update() self.sparkler.sparkle() if pyxel.frame_count > self.start and not self.finish: outcome = self.ball.update() if outcome: self.score(outcome) self.check_speed() if self.ball.check_collision([self.l_paddle, self.r_paddle]): self.music.sfx_hit() self.pickups.check_pickup() self.pickups.check_collision(self.ball) if pyxel.btn(pyxel.KEY_Q): pyxel.quit() if pyxel.btnp(pyxel.KEY_R): self.reset_game() def check_speed(self): """Adds velocity to the ball periodically.""" if pyxel.frame_count > self.speed_up: self.speed_up += SPEED_PERIOD self.ball.x_vol += SPEED_AMOUNT * sign(self.ball.x_vol) self.ball.y_vol += SPEED_AMOUNT * sign(self.ball.y_vol) def score(self, outcome): """Adds to the score if the ball hits the side. Check win condition.""" self.music.sfx_score() if outcome == "l": self.l_score += 1 elif outcome == "r": self.r_score += 1 if self.l_score >= WIN_CONDITION or self.r_score >= WIN_CONDITION: self.win_event() self.reset_after_score() def win_event(self): """What happens when someone wins the game!""" self.finish = True self.music.stop_music() self.music.sfx_finish() ###################### # Pickup controllers # ###################### def expand_paddle(self): """Expand the pandle temporarily.""" if self.ball.x_vol > 0: paddle = self.l_paddle else: paddle = self.r_paddle paddle.height = PADDLE_HEIGHT_EXPANDED paddle.y -= (PADDLE_HEIGHT_EXPANDED - PADDLE_HEIGHT) // 2 self.expand_stack.append(paddle) def contract_paddle(self): """Revert paddle side to normal.""" paddle = self.expand_stack.pop(0) if paddle not in self.expand_stack: paddle.height = PADDLE_HEIGHT paddle.y += (PADDLE_HEIGHT_EXPANDED - PADDLE_HEIGHT) // 2 def slow_paddle(self): """Slow the pandle temporarily.""" if self.ball.x_vol > 0: paddle = self.l_paddle else: paddle = self.r_paddle paddle.move_speed = PADDLE_MOVE_SPEED_SLOW paddle.colour = COL_PADDLE_SLOW self.speed_stack.append(paddle) def speed_paddle(self): """Speed the paddle back up to normal speed.""" paddle = self.speed_stack.pop(0) if paddle not in self.speed_stack: paddle.move_speed = PADDLE_MOVE_SPEED paddle.colour = COL_PADDLE ############## # Draw logic # ############## def draw(self): """Draw the paddles and ball OR the end screen.""" if self.finish: self.draw_end_screen() else: pyxel.cls(COL_BACKGROUND) self.sparkler.display() self.l_paddle.display() self.r_paddle.display() self.pickups.display() self.ball.display() self.draw_score() def draw_score(self): """Draw the score at the top.""" l_score = "{:01}".format(self.l_score) r_score = "{:01}".format(self.r_score) buffer = PADDLE_SIDE + PADDLE_WIDTH + 2 r_x_position = WIDTH - FONT_WIDTH - buffer pyxel.text(x=buffer, y=2, s=l_score, col=COL_SCORE) pyxel.text(x=r_x_position, y=2, s=r_score, col=COL_SCORE) def draw_end_screen(self): """Draw the final screen with the winner!""" pyxel.cls(col=COL_FINISH) display_text = TEXT_FINISH[:] if self.l_score >= WIN_CONDITION: winner = "The LEFT player!" else: winner = "The RIGHT player!" display_text.insert(1, winner) for i, text in enumerate(display_text): y_offset = (FONT_HEIGHT + 2) * i text_x = self.center_text(text, WIDTH) pyxel.text(text_x, HEIGHT_FINISH + y_offset, text, COL_FINISH_TEXT) @staticmethod def center_text(text, page_width, char_width=FONT_WIDTH): """Helper function for calcuating the start x value for centered text.""" text_width = len(text) * char_width return (page_width - text_width) // 2
class App: def __init__(self): pyxel.init(240, 160, caption='test game') self.levelname = 'level2' self.assets_dir = 'assets' self.assets = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__), self.assets_dir, self.levelname)) pyxel.image(0).load(0, 0, os.path.join(self.assets, '../animation.png')) pyxel.image(1).load(0, 0, os.path.join(self.assets, 'tileset.png')) pyxel.image(2).load(0, 0, os.path.join(self.assets, 'background.png')) self.level = Level(self.assets, 'mapfile.txt', 16) self.camera = Camera(self.level) self.player = Player() self.sparkle_emitter = ParticleEmitter(self.player) self.sound = Sound() self.sound.start_music() self.test_val = 0 pyxel.run(self.update, self.draw) def update(self): if pyxel.btn(pyxel.KEY_A): self.player.run(-1) if pyxel.btn(pyxel.KEY_D): self.player.run(1) if pyxel.btn(pyxel.KEY_I): self.test_val += 1 if pyxel.btn(pyxel.KEY_O): self.test_val -= 1 if pyxel.btnp(pyxel.KEY_S): if self.player.grounded: self.sound.sfx_buildup() if not pyxel.btn(pyxel.KEY_S): self.sound.sfx_stop() if pyxel.btnp(pyxel.KEY_S, 60, 30): print(pyxel.frame_count) if self.player.grounded: self.player.charge() if pyxel.btn(pyxel.KEY_SPACE): if self.player.grounded: self.player.jump() self.sound.sfx_jump() if pyxel.btn(pyxel.KEY_ESCAPE): pyxel.quit() if pyxel.btn(pyxel.KEY_T): pyxel.pal(1, 7) else: pyxel.pal() if pyxel.btn(pyxel.KEY_P): import pdb pdb.set_trace() self.camera.last_offset_x, self.camera.last_offset_y = self.camera.offset_x, self.camera.offset_y self.update_player() def draw(self): pyxel.cls(1) pyxel.blt(0, 0, 2, 0, 0, 240, 70, 1) # render the city for i in range(2): pyxel.blt(i * 240 - self.camera.offset_x / 2, 39, 2, 0, 82, 240, 82, 1) # render the clouds for i in range(2): pyxel.blt(i * 240 - self.camera.offset_x / 50, 10, 2, 0, 168, 240, 40, 1) self.level.render(self.camera, self.level.background, 1) self.level.render(self.camera, self.level.collision, 1) self.player.render() self.sparkle_emitter.render_particles() self.level.render(self.camera, self.level.foreground, 1) def update_player(self): self.player.x, self.camera.offset_x = update_axis( self.player.x, self.player.vx, self.camera.offset_x, self.camera.max_scroll_x, pyxel.width, ) self.player.x_collision(self.camera, self.level) self.player.y, self.camera.offset_y = update_axis( self.player.y, self.player.vy, self.camera.offset_y, self.camera.max_scroll_y, pyxel.height, ) self.player.y_collision(self.camera, self.level) self.sparkle_emitter.update_position(self.offset_delta()) self.player.vy = min(self.player.vy + 1, 7) if self.player.vx > 0: self.player.vx = self.player.vx - 1 elif self.player.vx < 0: self.player.vx = self.player.vx + 1 if self.player.jump_chg >= 4: self.sparkle_emitter.sparkle(self.test_val) self.sound.sfx_pickup() def offset_delta(self): return self.camera.offset_x - self.camera.last_offset_x, self.camera.offset_y - self.camera.last_offset_y