You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1435 lines
56 KiB
1435 lines
56 KiB
from __future__ import division
|
|
|
|
|
|
import pygame as pg
|
|
from .. import setup, tools
|
|
from .. import constants as c
|
|
from .. import game_sound
|
|
from .. components import mario
|
|
from .. components import collider
|
|
from .. components import bricks
|
|
from .. components import coin_box
|
|
from .. components import enemies
|
|
from .. components import checkpoint
|
|
from .. components import flagpole
|
|
from .. components import info
|
|
from .. components import score
|
|
from .. components import castle_flag
|
|
|
|
|
|
class Level1(tools._State):
|
|
def __init__(self):
|
|
tools._State.__init__(self)
|
|
|
|
def startup(self, current_time, persist):
|
|
"""Called when the State object is created"""
|
|
self.game_info = persist
|
|
self.persist = self.game_info
|
|
self.game_info[c.CURRENT_TIME] = current_time
|
|
self.game_info[c.LEVEL_STATE] = c.NOT_FROZEN
|
|
self.game_info[c.MARIO_DEAD] = False
|
|
|
|
self.state = c.NOT_FROZEN
|
|
self.death_timer = 0
|
|
self.flag_timer = 0
|
|
self.flag_score = None
|
|
self.flag_score_total = 0
|
|
|
|
self.moving_score_list = []
|
|
self.overhead_info_display = info.OverheadInfo(self.game_info, c.LEVEL)
|
|
self.sound_manager = game_sound.Sound(self.overhead_info_display)
|
|
|
|
self.setup_background()
|
|
self.setup_ground()
|
|
self.setup_pipes()
|
|
self.setup_steps()
|
|
self.setup_bricks()
|
|
self.setup_coin_boxes()
|
|
self.setup_flag_pole()
|
|
self.setup_enemies()
|
|
self.setup_mario()
|
|
self.setup_checkpoints()
|
|
self.setup_spritegroups()
|
|
|
|
|
|
def setup_background(self):
|
|
"""Sets the background image, rect and scales it to the correct
|
|
proportions"""
|
|
self.background = setup.GFX['level_1']
|
|
self.back_rect = self.background.get_rect()
|
|
self.background = pg.transform.scale(self.background,
|
|
(int(self.back_rect.width*c.BACKGROUND_MULTIPLER),
|
|
int(self.back_rect.height*c.BACKGROUND_MULTIPLER)))
|
|
self.back_rect = self.background.get_rect()
|
|
width = self.back_rect.width
|
|
height = self.back_rect.height
|
|
|
|
self.level = pg.Surface((width, height)).convert()
|
|
self.level_rect = self.level.get_rect()
|
|
self.viewport = setup.SCREEN.get_rect(bottom=self.level_rect.bottom)
|
|
self.viewport.x = self.game_info[c.CAMERA_START_X]
|
|
|
|
|
|
def setup_ground(self):
|
|
"""Creates collideable, invisible rectangles over top of the ground for
|
|
sprites to walk on"""
|
|
ground_rect1 = collider.Collider(0, c.GROUND_HEIGHT, 2953, 60)
|
|
ground_rect2 = collider.Collider(3048, c.GROUND_HEIGHT, 635, 60)
|
|
ground_rect3 = collider.Collider(3819, c.GROUND_HEIGHT, 2735, 60)
|
|
ground_rect4 = collider.Collider(6647, c.GROUND_HEIGHT, 2300, 60)
|
|
|
|
self.ground_group = pg.sprite.Group(ground_rect1,
|
|
ground_rect2,
|
|
ground_rect3,
|
|
ground_rect4)
|
|
|
|
|
|
def setup_pipes(self):
|
|
"""Create collideable rects for all the pipes"""
|
|
|
|
pipe1 = collider.Collider(1202, 452, 83, 82)
|
|
pipe2 = collider.Collider(1631, 409, 83, 140)
|
|
pipe3 = collider.Collider(1973, 366, 83, 170)
|
|
pipe4 = collider.Collider(2445, 366, 83, 170)
|
|
pipe5 = collider.Collider(6989, 452, 83, 82)
|
|
pipe6 = collider.Collider(7675, 452, 83, 82)
|
|
|
|
self.pipe_group = pg.sprite.Group(pipe1, pipe2,
|
|
pipe3, pipe4,
|
|
pipe5, pipe6)
|
|
|
|
|
|
def setup_steps(self):
|
|
"""Create collideable rects for all the steps"""
|
|
step1 = collider.Collider(5745, 495, 40, 44)
|
|
step2 = collider.Collider(5788, 452, 40, 44)
|
|
step3 = collider.Collider(5831, 409, 40, 44)
|
|
step4 = collider.Collider(5874, 366, 40, 176)
|
|
|
|
|
|
step5 = collider.Collider(6001, 366, 40, 176)
|
|
step6 = collider.Collider(6044, 408, 40, 40)
|
|
step7 = collider.Collider(6087, 452, 40, 40)
|
|
step8 = collider.Collider(6130, 495, 40, 40)
|
|
|
|
step9 = collider.Collider(6345, 495, 40, 40)
|
|
step10 = collider.Collider(6388, 452, 40, 40)
|
|
step11 = collider.Collider(6431, 409, 40, 40)
|
|
step12 = collider.Collider(6474, 366, 40, 40)
|
|
step13 = collider.Collider(6517, 366, 40, 176)
|
|
|
|
step14 = collider.Collider(6644, 366, 40, 176)
|
|
step15 = collider.Collider(6687, 408, 40, 40)
|
|
step16 = collider.Collider(6728, 452, 40, 40)
|
|
step17 = collider.Collider(6771, 495, 40, 40)
|
|
|
|
step18 = collider.Collider(7760, 495, 40, 40)
|
|
step19 = collider.Collider(7803, 452, 40, 40)
|
|
step20 = collider.Collider(7845, 409, 40, 40)
|
|
step21 = collider.Collider(7888, 366, 40, 40)
|
|
step22 = collider.Collider(7931, 323, 40, 40)
|
|
step23 = collider.Collider(7974, 280, 40, 40)
|
|
step24 = collider.Collider(8017, 237, 40, 40)
|
|
step25 = collider.Collider(8060, 194, 40, 40)
|
|
step26 = collider.Collider(8103, 194, 40, 360)
|
|
|
|
step27 = collider.Collider(8488, 495, 40, 40)
|
|
|
|
self.step_group = pg.sprite.Group(step1, step2,
|
|
step3, step4,
|
|
step5, step6,
|
|
step7, step8,
|
|
step9, step10,
|
|
step11, step12,
|
|
step13, step14,
|
|
step15, step16,
|
|
step17, step18,
|
|
step19, step20,
|
|
step21, step22,
|
|
step23, step24,
|
|
step25, step26,
|
|
step27)
|
|
|
|
|
|
def setup_bricks(self):
|
|
"""Creates all the breakable bricks for the level. Coin and
|
|
powerup groups are created so they can be passed to bricks."""
|
|
self.coin_group = pg.sprite.Group()
|
|
self.powerup_group = pg.sprite.Group()
|
|
self.brick_pieces_group = pg.sprite.Group()
|
|
|
|
brick1 = bricks.Brick(858, 365)
|
|
brick2 = bricks.Brick(944, 365)
|
|
brick3 = bricks.Brick(1030, 365)
|
|
brick4 = bricks.Brick(3299, 365)
|
|
brick5 = bricks.Brick(3385, 365)
|
|
brick6 = bricks.Brick(3430, 193)
|
|
brick7 = bricks.Brick(3473, 193)
|
|
brick8 = bricks.Brick(3516, 193)
|
|
brick9 = bricks.Brick(3559, 193)
|
|
brick10 = bricks.Brick(3602, 193)
|
|
brick11 = bricks.Brick(3645, 193)
|
|
brick12 = bricks.Brick(3688, 193)
|
|
brick13 = bricks.Brick(3731, 193)
|
|
brick14 = bricks.Brick(3901, 193)
|
|
brick15 = bricks.Brick(3944, 193)
|
|
brick16 = bricks.Brick(3987, 193)
|
|
brick17 = bricks.Brick(4030, 365, c.SIXCOINS, self.coin_group)
|
|
brick18 = bricks.Brick(4287, 365)
|
|
brick19 = bricks.Brick(4330, 365, c.STAR, self.powerup_group)
|
|
brick20 = bricks.Brick(5058, 365)
|
|
brick21 = bricks.Brick(5187, 193)
|
|
brick22 = bricks.Brick(5230, 193)
|
|
brick23 = bricks.Brick(5273, 193)
|
|
brick24 = bricks.Brick(5488, 193)
|
|
brick25 = bricks.Brick(5574, 193)
|
|
brick26 = bricks.Brick(5617, 193)
|
|
brick27 = bricks.Brick(5531, 365)
|
|
brick28 = bricks.Brick(5574, 365)
|
|
brick29 = bricks.Brick(7202, 365)
|
|
brick30 = bricks.Brick(7245, 365)
|
|
brick31 = bricks.Brick(7331, 365)
|
|
|
|
self.brick_group = pg.sprite.Group(brick1, brick2,
|
|
brick3, brick4,
|
|
brick5, brick6,
|
|
brick7, brick8,
|
|
brick9, brick10,
|
|
brick11, brick12,
|
|
brick13, brick14,
|
|
brick15, brick16,
|
|
brick17, brick18,
|
|
brick19, brick20,
|
|
brick21, brick22,
|
|
brick23, brick24,
|
|
brick25, brick26,
|
|
brick27, brick28,
|
|
brick29, brick30,
|
|
brick31)
|
|
|
|
|
|
def setup_coin_boxes(self):
|
|
"""Creates all the coin boxes and puts them in a sprite group"""
|
|
coin_box1 = coin_box.Coin_box(685, 365, c.COIN, self.coin_group)
|
|
coin_box2 = coin_box.Coin_box(901, 365, c.MUSHROOM, self.powerup_group)
|
|
coin_box3 = coin_box.Coin_box(987, 365, c.COIN, self.coin_group)
|
|
coin_box4 = coin_box.Coin_box(943, 193, c.COIN, self.coin_group)
|
|
coin_box5 = coin_box.Coin_box(3342, 365, c.MUSHROOM, self.powerup_group)
|
|
coin_box6 = coin_box.Coin_box(4030, 193, c.COIN, self.coin_group)
|
|
coin_box7 = coin_box.Coin_box(4544, 365, c.COIN, self.coin_group)
|
|
coin_box8 = coin_box.Coin_box(4672, 365, c.COIN, self.coin_group)
|
|
coin_box9 = coin_box.Coin_box(4672, 193, c.MUSHROOM, self.powerup_group)
|
|
coin_box10 = coin_box.Coin_box(4800, 365, c.COIN, self.coin_group)
|
|
coin_box11 = coin_box.Coin_box(5531, 193, c.COIN, self.coin_group)
|
|
coin_box12 = coin_box.Coin_box(7288, 365, c.COIN, self.coin_group)
|
|
|
|
self.coin_box_group = pg.sprite.Group(coin_box1, coin_box2,
|
|
coin_box3, coin_box4,
|
|
coin_box5, coin_box6,
|
|
coin_box7, coin_box8,
|
|
coin_box9, coin_box10,
|
|
coin_box11, coin_box12)
|
|
|
|
|
|
def setup_flag_pole(self):
|
|
"""Creates the flag pole at the end of the level"""
|
|
self.flag = flagpole.Flag(8505, 100)
|
|
|
|
pole0 = flagpole.Pole(8505, 97)
|
|
pole1 = flagpole.Pole(8505, 137)
|
|
pole2 = flagpole.Pole(8505, 177)
|
|
pole3 = flagpole.Pole(8505, 217)
|
|
pole4 = flagpole.Pole(8505, 257)
|
|
pole5 = flagpole.Pole(8505, 297)
|
|
pole6 = flagpole.Pole(8505, 337)
|
|
pole7 = flagpole.Pole(8505, 377)
|
|
pole8 = flagpole.Pole(8505, 417)
|
|
pole9 = flagpole.Pole(8505, 450)
|
|
|
|
finial = flagpole.Finial(8507, 97)
|
|
|
|
self.flag_pole_group = pg.sprite.Group(self.flag,
|
|
finial,
|
|
pole0,
|
|
pole1,
|
|
pole2,
|
|
pole3,
|
|
pole4,
|
|
pole5,
|
|
pole6,
|
|
pole7,
|
|
pole8,
|
|
pole9)
|
|
|
|
|
|
def setup_enemies(self):
|
|
"""Creates all the enemies and stores them in a list of lists."""
|
|
goomba0 = enemies.Goomba()
|
|
goomba1 = enemies.Goomba()
|
|
goomba2 = enemies.Goomba()
|
|
goomba3 = enemies.Goomba()
|
|
goomba4 = enemies.Goomba(193)
|
|
goomba5 = enemies.Goomba(193)
|
|
goomba6 = enemies.Goomba()
|
|
goomba7 = enemies.Goomba()
|
|
goomba8 = enemies.Goomba()
|
|
goomba9 = enemies.Goomba()
|
|
goomba10 = enemies.Goomba()
|
|
goomba11 = enemies.Goomba()
|
|
goomba12 = enemies.Goomba()
|
|
goomba13 = enemies.Goomba()
|
|
goomba14 = enemies.Goomba()
|
|
goomba15 = enemies.Goomba()
|
|
|
|
koopa0 = enemies.Koopa()
|
|
|
|
enemy_group1 = pg.sprite.Group(goomba0)
|
|
enemy_group2 = pg.sprite.Group(goomba1)
|
|
enemy_group3 = pg.sprite.Group(goomba2, goomba3)
|
|
enemy_group4 = pg.sprite.Group(goomba4, goomba5)
|
|
enemy_group5 = pg.sprite.Group(goomba6, goomba7)
|
|
enemy_group6 = pg.sprite.Group(koopa0)
|
|
enemy_group7 = pg.sprite.Group(goomba8, goomba9)
|
|
enemy_group8 = pg.sprite.Group(goomba10, goomba11)
|
|
enemy_group9 = pg.sprite.Group(goomba12, goomba13)
|
|
enemy_group10 = pg.sprite.Group(goomba14, goomba15)
|
|
|
|
self.enemy_group_list = [enemy_group1,
|
|
enemy_group2,
|
|
enemy_group3,
|
|
enemy_group4,
|
|
enemy_group5,
|
|
enemy_group6,
|
|
enemy_group7,
|
|
enemy_group8,
|
|
enemy_group9,
|
|
enemy_group10]
|
|
|
|
|
|
def setup_mario(self):
|
|
"""Places Mario at the beginning of the level"""
|
|
self.mario = mario.Mario()
|
|
self.mario.rect.x = self.viewport.x + 110
|
|
self.mario.rect.bottom = c.GROUND_HEIGHT
|
|
|
|
|
|
def setup_checkpoints(self):
|
|
"""Creates invisible checkpoints that when collided will trigger
|
|
the creation of enemies from the self.enemy_group_list"""
|
|
check1 = checkpoint.Checkpoint(510, "1")
|
|
check2 = checkpoint.Checkpoint(1400, '2')
|
|
check3 = checkpoint.Checkpoint(1740, '3')
|
|
check4 = checkpoint.Checkpoint(3080, '4')
|
|
check5 = checkpoint.Checkpoint(3750, '5')
|
|
check6 = checkpoint.Checkpoint(4150, '6')
|
|
check7 = checkpoint.Checkpoint(4470, '7')
|
|
check8 = checkpoint.Checkpoint(4950, '8')
|
|
check9 = checkpoint.Checkpoint(5100, '9')
|
|
check10 = checkpoint.Checkpoint(6800, '10')
|
|
check11 = checkpoint.Checkpoint(8504, '11', 5, 6)
|
|
check12 = checkpoint.Checkpoint(8775, '12')
|
|
check13 = checkpoint.Checkpoint(2740, 'secret_mushroom', 360, 40, 12)
|
|
|
|
self.check_point_group = pg.sprite.Group(check1, check2, check3,
|
|
check4, check5, check6,
|
|
check7, check8, check9,
|
|
check10, check11, check12,
|
|
check13)
|
|
|
|
|
|
def setup_spritegroups(self):
|
|
"""Sprite groups created for convenience"""
|
|
self.sprites_about_to_die_group = pg.sprite.Group()
|
|
self.shell_group = pg.sprite.Group()
|
|
self.enemy_group = pg.sprite.Group()
|
|
|
|
self.ground_step_pipe_group = pg.sprite.Group(self.ground_group,
|
|
self.pipe_group,
|
|
self.step_group)
|
|
|
|
self.mario_and_enemy_group = pg.sprite.Group(self.mario,
|
|
self.enemy_group)
|
|
|
|
|
|
def update(self, surface, keys, current_time):
|
|
"""Updates Entire level using states. Called by the control object"""
|
|
self.game_info[c.CURRENT_TIME] = self.current_time = current_time
|
|
self.handle_states(keys)
|
|
self.check_if_time_out()
|
|
self.blit_everything(surface)
|
|
self.sound_manager.update(self.game_info, self.mario)
|
|
|
|
|
|
|
|
def handle_states(self, keys):
|
|
"""If the level is in a FROZEN state, only mario will update"""
|
|
if self.state == c.FROZEN:
|
|
self.update_during_transition_state(keys)
|
|
elif self.state == c.NOT_FROZEN:
|
|
self.update_all_sprites(keys)
|
|
elif self.state == c.IN_CASTLE:
|
|
self.update_while_in_castle()
|
|
elif self.state == c.FLAG_AND_FIREWORKS:
|
|
self.update_flag_and_fireworks()
|
|
|
|
|
|
def update_during_transition_state(self, keys):
|
|
"""Updates mario in a transition state (like becoming big, small,
|
|
or dies). Checks if he leaves the transition state or dies to
|
|
change the level state back"""
|
|
self.mario.update(keys, self.game_info, self.powerup_group)
|
|
for score in self.moving_score_list:
|
|
score.update(self.moving_score_list, self.game_info)
|
|
if self.flag_score:
|
|
self.flag_score.update(None, self.game_info)
|
|
self.check_to_add_flag_score()
|
|
self.coin_box_group.update(self.game_info)
|
|
self.flag_pole_group.update(self.game_info)
|
|
self.check_if_mario_in_transition_state()
|
|
self.check_flag()
|
|
self.check_for_mario_death()
|
|
self.overhead_info_display.update(self.game_info, self.mario)
|
|
|
|
|
|
def check_if_mario_in_transition_state(self):
|
|
"""If mario is in a transition state, the level will be in a FREEZE
|
|
state"""
|
|
if self.mario.in_transition_state:
|
|
self.game_info[c.LEVEL_STATE] = self.state = c.FROZEN
|
|
elif self.mario.in_transition_state == False:
|
|
if self.state == c.FROZEN:
|
|
self.game_info[c.LEVEL_STATE] = self.state = c.NOT_FROZEN
|
|
|
|
|
|
def update_all_sprites(self, keys):
|
|
"""Updates the location of all sprites on the screen."""
|
|
self.mario.update(keys, self.game_info, self.powerup_group)
|
|
for score in self.moving_score_list:
|
|
score.update(self.moving_score_list, self.game_info)
|
|
if self.flag_score:
|
|
self.flag_score.update(None, self.game_info)
|
|
self.check_to_add_flag_score()
|
|
self.flag_pole_group.update()
|
|
self.check_points_check()
|
|
self.enemy_group.update(self.game_info)
|
|
self.sprites_about_to_die_group.update(self.game_info, self.viewport)
|
|
self.shell_group.update(self.game_info)
|
|
self.brick_group.update()
|
|
self.coin_box_group.update(self.game_info)
|
|
self.powerup_group.update(self.game_info, self.viewport)
|
|
self.coin_group.update(self.game_info, self.viewport)
|
|
self.brick_pieces_group.update()
|
|
self.adjust_sprite_positions()
|
|
self.check_if_mario_in_transition_state()
|
|
self.check_for_mario_death()
|
|
self.update_viewport()
|
|
self.overhead_info_display.update(self.game_info, self.mario)
|
|
|
|
|
|
def check_points_check(self):
|
|
"""Detect if checkpoint collision occurs, delete checkpoint,
|
|
add enemies to self.enemy_group"""
|
|
checkpoint = pg.sprite.spritecollideany(self.mario,
|
|
self.check_point_group)
|
|
if checkpoint:
|
|
checkpoint.kill()
|
|
|
|
for i in range(1,11):
|
|
if checkpoint.name == str(i):
|
|
for index, enemy in enumerate(self.enemy_group_list[i -1]):
|
|
enemy.rect.x = self.viewport.right + (index * 60)
|
|
self.enemy_group.add(self.enemy_group_list[i-1])
|
|
|
|
if checkpoint.name == '11':
|
|
self.mario.state = c.FLAGPOLE
|
|
self.mario.invincible = False
|
|
self.mario.flag_pole_right = checkpoint.rect.right
|
|
if self.mario.rect.bottom < self.flag.rect.y:
|
|
self.mario.rect.bottom = self.flag.rect.y
|
|
self.flag.state = c.SLIDE_DOWN
|
|
self.create_flag_points()
|
|
|
|
elif checkpoint.name == '12':
|
|
self.state = c.IN_CASTLE
|
|
self.mario.kill()
|
|
self.mario.state == c.STAND
|
|
self.mario.in_castle = True
|
|
self.overhead_info_display.state = c.FAST_COUNT_DOWN
|
|
|
|
|
|
elif checkpoint.name == 'secret_mushroom' and self.mario.y_vel < 0:
|
|
mushroom_box = coin_box.Coin_box(checkpoint.rect.x,
|
|
checkpoint.rect.bottom - 40,
|
|
'1up_mushroom',
|
|
self.powerup_group)
|
|
mushroom_box.start_bump(self.moving_score_list)
|
|
self.coin_box_group.add(mushroom_box)
|
|
|
|
self.mario.y_vel = 7
|
|
self.mario.rect.y = mushroom_box.rect.bottom
|
|
self.mario.state = c.FALL
|
|
|
|
self.mario_and_enemy_group.add(self.enemy_group)
|
|
|
|
|
|
def create_flag_points(self):
|
|
"""Creates the points that appear when Mario touches the
|
|
flag pole"""
|
|
x = 8518
|
|
y = c.GROUND_HEIGHT - 60
|
|
mario_bottom = self.mario.rect.bottom
|
|
|
|
if mario_bottom > (c.GROUND_HEIGHT - 40 - 40):
|
|
self.flag_score = score.Score(x, y, 100, True)
|
|
self.flag_score_total = 100
|
|
elif mario_bottom > (c.GROUND_HEIGHT - 40 - 160):
|
|
self.flag_score = score.Score(x, y, 400, True)
|
|
self.flag_score_total = 400
|
|
elif mario_bottom > (c.GROUND_HEIGHT - 40 - 240):
|
|
self.flag_score = score.Score(x, y, 800, True)
|
|
self.flag_score_total = 800
|
|
elif mario_bottom > (c.GROUND_HEIGHT - 40 - 360):
|
|
self.flag_score = score.Score(x, y, 2000, True)
|
|
self.flag_score_total = 2000
|
|
else:
|
|
self.flag_score = score.Score(x, y, 5000, True)
|
|
self.flag_score_total = 5000
|
|
|
|
|
|
def adjust_sprite_positions(self):
|
|
"""Adjusts sprites by their x and y velocities and collisions"""
|
|
self.adjust_mario_position()
|
|
self.adjust_enemy_position()
|
|
self.adjust_shell_position()
|
|
self.adjust_powerup_position()
|
|
|
|
|
|
def adjust_mario_position(self):
|
|
"""Adjusts Mario's position based on his x, y velocities and
|
|
potential collisions"""
|
|
self.last_x_position = self.mario.rect.right
|
|
self.mario.rect.x += round(self.mario.x_vel)
|
|
self.check_mario_x_collisions()
|
|
|
|
if self.mario.in_transition_state == False:
|
|
self.mario.rect.y += round(self.mario.y_vel)
|
|
self.check_mario_y_collisions()
|
|
|
|
if self.mario.rect.x < (self.viewport.x + 5):
|
|
self.mario.rect.x = (self.viewport.x + 5)
|
|
|
|
|
|
def check_mario_x_collisions(self):
|
|
"""Check for collisions after Mario is moved on the x axis"""
|
|
collider = pg.sprite.spritecollideany(self.mario, self.ground_step_pipe_group)
|
|
coin_box = pg.sprite.spritecollideany(self.mario, self.coin_box_group)
|
|
brick = pg.sprite.spritecollideany(self.mario, self.brick_group)
|
|
enemy = pg.sprite.spritecollideany(self.mario, self.enemy_group)
|
|
shell = pg.sprite.spritecollideany(self.mario, self.shell_group)
|
|
powerup = pg.sprite.spritecollideany(self.mario, self.powerup_group)
|
|
|
|
if coin_box:
|
|
self.adjust_mario_for_x_collisions(coin_box)
|
|
|
|
elif brick:
|
|
self.adjust_mario_for_x_collisions(brick)
|
|
|
|
elif collider:
|
|
self.adjust_mario_for_x_collisions(collider)
|
|
|
|
elif enemy:
|
|
if self.mario.invincible:
|
|
setup.SFX['kick'].play()
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(self.mario.rect.right - self.viewport.x,
|
|
self.mario.rect.y, 100))
|
|
enemy.kill()
|
|
enemy.start_death_jump(c.RIGHT)
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
elif self.mario.big:
|
|
setup.SFX['pipe'].play()
|
|
self.mario.fire = False
|
|
self.mario.y_vel = -1
|
|
self.mario.state = c.BIG_TO_SMALL
|
|
self.convert_fireflowers_to_mushrooms()
|
|
elif self.mario.hurt_invincible:
|
|
pass
|
|
else:
|
|
self.mario.start_death_jump(self.game_info)
|
|
self.state = c.FROZEN
|
|
|
|
elif shell:
|
|
self.adjust_mario_for_x_shell_collisions(shell)
|
|
|
|
elif powerup:
|
|
if powerup.name == c.STAR:
|
|
self.game_info[c.SCORE] += 1000
|
|
|
|
self.moving_score_list.append(
|
|
score.Score(self.mario.rect.centerx - self.viewport.x,
|
|
self.mario.rect.y, 1000))
|
|
self.mario.invincible = True
|
|
self.mario.invincible_start_timer = self.current_time
|
|
elif powerup.name == c.MUSHROOM:
|
|
setup.SFX['powerup'].play()
|
|
self.game_info[c.SCORE] += 1000
|
|
self.moving_score_list.append(
|
|
score.Score(self.mario.rect.centerx - self.viewport.x,
|
|
self.mario.rect.y - 20, 1000))
|
|
|
|
self.mario.y_vel = -1
|
|
self.mario.state = c.SMALL_TO_BIG
|
|
self.mario.in_transition_state = True
|
|
self.convert_mushrooms_to_fireflowers()
|
|
elif powerup.name == c.LIFE_MUSHROOM:
|
|
self.moving_score_list.append(
|
|
score.Score(powerup.rect.right - self.viewport.x,
|
|
powerup.rect.y,
|
|
c.ONEUP))
|
|
|
|
self.game_info[c.LIVES] += 1
|
|
setup.SFX['one_up'].play()
|
|
elif powerup.name == c.FIREFLOWER:
|
|
setup.SFX['powerup'].play()
|
|
self.game_info[c.SCORE] += 1000
|
|
self.moving_score_list.append(
|
|
score.Score(self.mario.rect.centerx - self.viewport.x,
|
|
self.mario.rect.y, 1000))
|
|
|
|
if self.mario.big and self.mario.fire == False:
|
|
self.mario.state = c.BIG_TO_FIRE
|
|
self.mario.in_transition_state = True
|
|
elif self.mario.big == False:
|
|
self.mario.state = c.SMALL_TO_BIG
|
|
self.mario.in_transition_state = True
|
|
self.convert_mushrooms_to_fireflowers()
|
|
|
|
if powerup.name != c.FIREBALL:
|
|
powerup.kill()
|
|
|
|
|
|
def convert_mushrooms_to_fireflowers(self):
|
|
"""When Mario becomees big, converts all fireflower powerups to
|
|
mushroom powerups"""
|
|
for brick in self.brick_group:
|
|
if brick.contents == c.MUSHROOM:
|
|
brick.contents = c.FIREFLOWER
|
|
for coin_box in self.coin_box_group:
|
|
if coin_box.contents == c.MUSHROOM:
|
|
coin_box.contents = c.FIREFLOWER
|
|
|
|
|
|
def convert_fireflowers_to_mushrooms(self):
|
|
"""When Mario becomes small, converts all mushroom powerups to
|
|
fireflower powerups"""
|
|
for brick in self.brick_group:
|
|
if brick.contents == c.FIREFLOWER:
|
|
brick.contents = c.MUSHROOM
|
|
for coin_box in self.coin_box_group:
|
|
if coin_box.contents == c.FIREFLOWER:
|
|
coin_box.contents = c.MUSHROOM
|
|
|
|
|
|
def adjust_mario_for_x_collisions(self, collider):
|
|
"""Puts Mario flush next to the collider after moving on the x axis"""
|
|
if self.mario.rect.x < collider.rect.x:
|
|
self.mario.rect.right = collider.rect.left
|
|
else:
|
|
self.mario.rect.left = collider.rect.right
|
|
|
|
self.mario.x_vel = 0
|
|
|
|
|
|
def adjust_mario_for_x_shell_collisions(self, shell):
|
|
"""Deals with Mario if he hits a shell moving on the x axis"""
|
|
if shell.state == c.JUMPED_ON:
|
|
if self.mario.rect.x < shell.rect.x:
|
|
self.game_info[c.SCORE] += 400
|
|
self.moving_score_list.append(
|
|
score.Score(shell.rect.centerx - self.viewport.x,
|
|
shell.rect.y,
|
|
400))
|
|
self.mario.rect.right = shell.rect.left
|
|
shell.direction = c.RIGHT
|
|
shell.x_vel = 5
|
|
shell.rect.x += 5
|
|
|
|
else:
|
|
self.mario.rect.left = shell.rect.right
|
|
shell.direction = c.LEFT
|
|
shell.x_vel = -5
|
|
shell.rect.x += -5
|
|
|
|
shell.state = c.SHELL_SLIDE
|
|
|
|
elif shell.state == c.SHELL_SLIDE:
|
|
if self.mario.big and not self.mario.invincible:
|
|
self.mario.state = c.BIG_TO_SMALL
|
|
elif self.mario.invincible:
|
|
self.game_info[c.SCORE] += 200
|
|
self.moving_score_list.append(
|
|
score.Score(shell.rect.right - self.viewport.x,
|
|
shell.rect.y, 200))
|
|
shell.kill()
|
|
self.sprites_about_to_die_group.add(shell)
|
|
shell.start_death_jump(c.RIGHT)
|
|
else:
|
|
if not self.mario.hurt_invincible and not self.mario.invincible:
|
|
self.state = c.FROZEN
|
|
self.mario.start_death_jump(self.game_info)
|
|
|
|
|
|
def check_mario_y_collisions(self):
|
|
"""Checks for collisions when Mario moves along the y-axis"""
|
|
ground_step_or_pipe = pg.sprite.spritecollideany(self.mario, self.ground_step_pipe_group)
|
|
enemy = pg.sprite.spritecollideany(self.mario, self.enemy_group)
|
|
shell = pg.sprite.spritecollideany(self.mario, self.shell_group)
|
|
brick = pg.sprite.spritecollideany(self.mario, self.brick_group)
|
|
coin_box = pg.sprite.spritecollideany(self.mario, self.coin_box_group)
|
|
powerup = pg.sprite.spritecollideany(self.mario, self.powerup_group)
|
|
|
|
brick, coin_box = self.prevent_collision_conflict(brick, coin_box)
|
|
|
|
if coin_box:
|
|
self.adjust_mario_for_y_coin_box_collisions(coin_box)
|
|
|
|
elif brick:
|
|
self.adjust_mario_for_y_brick_collisions(brick)
|
|
|
|
elif ground_step_or_pipe:
|
|
self.adjust_mario_for_y_ground_pipe_collisions(ground_step_or_pipe)
|
|
|
|
elif enemy:
|
|
if self.mario.invincible:
|
|
setup.SFX['kick'].play()
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
enemy.start_death_jump(c.RIGHT)
|
|
else:
|
|
self.adjust_mario_for_y_enemy_collisions(enemy)
|
|
|
|
elif shell:
|
|
self.adjust_mario_for_y_shell_collisions(shell)
|
|
|
|
elif powerup:
|
|
if powerup.name == c.STAR:
|
|
setup.SFX['powerup'].play()
|
|
powerup.kill()
|
|
self.mario.invincible = True
|
|
self.mario.invincible_start_timer = self.current_time
|
|
|
|
self.test_if_mario_is_falling()
|
|
|
|
|
|
def prevent_collision_conflict(self, obstacle1, obstacle2):
|
|
"""Allows collisions only for the item closest to marios centerx"""
|
|
if obstacle1 and obstacle2:
|
|
obstacle1_distance = self.mario.rect.centerx - obstacle1.rect.centerx
|
|
if obstacle1_distance < 0:
|
|
obstacle1_distance *= -1
|
|
obstacle2_distance = self.mario.rect.centerx - obstacle2.rect.centerx
|
|
if obstacle2_distance < 0:
|
|
obstacle2_distance *= -1
|
|
|
|
if obstacle1_distance < obstacle2_distance:
|
|
obstacle2 = False
|
|
else:
|
|
obstacle1 = False
|
|
|
|
return obstacle1, obstacle2
|
|
|
|
|
|
def adjust_mario_for_y_coin_box_collisions(self, coin_box):
|
|
"""Mario collisions with coin boxes on the y-axis"""
|
|
if self.mario.rect.y > coin_box.rect.y:
|
|
if coin_box.state == c.RESTING:
|
|
if coin_box.contents == c.COIN:
|
|
self.game_info[c.SCORE] += 200
|
|
coin_box.start_bump(self.moving_score_list)
|
|
if coin_box.contents == c.COIN:
|
|
self.game_info[c.COIN_TOTAL] += 1
|
|
else:
|
|
coin_box.start_bump(self.moving_score_list)
|
|
|
|
elif coin_box.state == c.OPENED:
|
|
pass
|
|
setup.SFX['bump'].play()
|
|
self.mario.y_vel = 7
|
|
self.mario.rect.y = coin_box.rect.bottom
|
|
self.mario.state = c.FALL
|
|
else:
|
|
self.mario.y_vel = 0
|
|
self.mario.rect.bottom = coin_box.rect.top
|
|
self.mario.state = c.WALK
|
|
|
|
|
|
def adjust_mario_for_y_brick_collisions(self, brick):
|
|
"""Mario collisions with bricks on the y-axis"""
|
|
if self.mario.rect.y > brick.rect.y:
|
|
if brick.state == c.RESTING:
|
|
if self.mario.big and brick.contents is None:
|
|
setup.SFX['brick_smash'].play()
|
|
self.check_if_enemy_on_brick(brick)
|
|
brick.kill()
|
|
self.brick_pieces_group.add(
|
|
bricks.BrickPiece(brick.rect.x,
|
|
brick.rect.y - (brick.rect.height/2),
|
|
-2, -12),
|
|
bricks.BrickPiece(brick.rect.right,
|
|
brick.rect.y - (brick.rect.height/2),
|
|
2, -12),
|
|
bricks.BrickPiece(brick.rect.x,
|
|
brick.rect.y,
|
|
-2, -6),
|
|
bricks.BrickPiece(brick.rect.right,
|
|
brick.rect.y,
|
|
2, -6))
|
|
else:
|
|
setup.SFX['bump'].play()
|
|
if brick.coin_total > 0:
|
|
self.game_info[c.COIN_TOTAL] += 1
|
|
self.game_info[c.SCORE] += 200
|
|
self.check_if_enemy_on_brick(brick)
|
|
brick.start_bump(self.moving_score_list)
|
|
elif brick.state == c.OPENED:
|
|
setup.SFX['bump'].play()
|
|
self.mario.y_vel = 7
|
|
self.mario.rect.y = brick.rect.bottom
|
|
self.mario.state = c.FALL
|
|
|
|
else:
|
|
self.mario.y_vel = 0
|
|
self.mario.rect.bottom = brick.rect.top
|
|
self.mario.state = c.WALK
|
|
|
|
|
|
def check_if_enemy_on_brick(self, brick):
|
|
"""Kills enemy if on a bumped or broken brick"""
|
|
brick.rect.y -= 5
|
|
|
|
enemy = pg.sprite.spritecollideany(brick, self.enemy_group)
|
|
|
|
if enemy:
|
|
setup.SFX['kick'].play()
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(enemy.rect.centerx - self.viewport.x,
|
|
enemy.rect.y,
|
|
100))
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
if self.mario.rect.centerx > brick.rect.centerx:
|
|
enemy.start_death_jump('right')
|
|
else:
|
|
enemy.start_death_jump('left')
|
|
|
|
brick.rect.y += 5
|
|
|
|
|
|
|
|
def adjust_mario_for_y_ground_pipe_collisions(self, collider):
|
|
"""Mario collisions with pipes on the y-axis"""
|
|
if collider.rect.bottom > self.mario.rect.bottom:
|
|
self.mario.y_vel = 0
|
|
self.mario.rect.bottom = collider.rect.top
|
|
if self.mario.state == c.END_OF_LEVEL_FALL:
|
|
self.mario.state = c.WALKING_TO_CASTLE
|
|
else:
|
|
self.mario.state = c.WALK
|
|
elif collider.rect.top < self.mario.rect.top:
|
|
self.mario.y_vel = 7
|
|
self.mario.rect.top = collider.rect.bottom
|
|
self.mario.state = c.FALL
|
|
|
|
|
|
def test_if_mario_is_falling(self):
|
|
"""Changes Mario to a FALL state if more than a pixel above a pipe,
|
|
ground, step or box"""
|
|
self.mario.rect.y += 1
|
|
test_collide_group = pg.sprite.Group(self.ground_step_pipe_group,
|
|
self.brick_group,
|
|
self.coin_box_group)
|
|
|
|
|
|
if pg.sprite.spritecollideany(self.mario, test_collide_group) is None:
|
|
if self.mario.state != c.JUMP \
|
|
and self.mario.state != c.DEATH_JUMP \
|
|
and self.mario.state != c.SMALL_TO_BIG \
|
|
and self.mario.state != c.BIG_TO_FIRE \
|
|
and self.mario.state != c.BIG_TO_SMALL \
|
|
and self.mario.state != c.FLAGPOLE \
|
|
and self.mario.state != c.WALKING_TO_CASTLE \
|
|
and self.mario.state != c.END_OF_LEVEL_FALL:
|
|
self.mario.state = c.FALL
|
|
elif self.mario.state == c.WALKING_TO_CASTLE or \
|
|
self.mario.state == c.END_OF_LEVEL_FALL:
|
|
self.mario.state = c.END_OF_LEVEL_FALL
|
|
|
|
self.mario.rect.y -= 1
|
|
|
|
|
|
def adjust_mario_for_y_enemy_collisions(self, enemy):
|
|
"""Mario collisions with all enemies on the y-axis"""
|
|
if self.mario.y_vel > 0:
|
|
setup.SFX['stomp'].play()
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(enemy.rect.centerx - self.viewport.x,
|
|
enemy.rect.y, 100))
|
|
enemy.state = c.JUMPED_ON
|
|
enemy.kill()
|
|
if enemy.name == c.GOOMBA:
|
|
enemy.death_timer = self.current_time
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
elif enemy.name == c.KOOPA:
|
|
self.shell_group.add(enemy)
|
|
|
|
self.mario.rect.bottom = enemy.rect.top
|
|
self.mario.state = c.JUMP
|
|
self.mario.y_vel = -7
|
|
|
|
|
|
|
|
def adjust_mario_for_y_shell_collisions(self, shell):
|
|
"""Mario collisions with Koopas in their shells on the y axis"""
|
|
if self.mario.y_vel > 0:
|
|
self.game_info[c.SCORE] += 400
|
|
self.moving_score_list.append(
|
|
score.Score(self.mario.rect.centerx - self.viewport.x,
|
|
self.mario.rect.y, 400))
|
|
if shell.state == c.JUMPED_ON:
|
|
setup.SFX['kick'].play()
|
|
shell.state = c.SHELL_SLIDE
|
|
if self.mario.rect.centerx < shell.rect.centerx:
|
|
shell.direction = c.RIGHT
|
|
shell.rect.left = self.mario.rect.right + 5
|
|
else:
|
|
shell.direction = c.LEFT
|
|
shell.rect.right = self.mario.rect.left - 5
|
|
else:
|
|
shell.state = c.JUMPED_ON
|
|
|
|
|
|
def adjust_enemy_position(self):
|
|
"""Moves all enemies along the x, y axes and check for collisions"""
|
|
for enemy in self.enemy_group:
|
|
enemy.rect.x += enemy.x_vel
|
|
self.check_enemy_x_collisions(enemy)
|
|
|
|
enemy.rect.y += enemy.y_vel
|
|
self.check_enemy_y_collisions(enemy)
|
|
self.delete_if_off_screen(enemy)
|
|
|
|
|
|
def check_enemy_x_collisions(self, enemy):
|
|
"""Enemy collisions along the x axis. Removes enemy from enemy group
|
|
in order to check against all other enemies then adds it back."""
|
|
enemy.kill()
|
|
|
|
collider = pg.sprite.spritecollideany(enemy, self.ground_step_pipe_group)
|
|
enemy_collider = pg.sprite.spritecollideany(enemy, self.enemy_group)
|
|
|
|
if collider:
|
|
if enemy.direction == c.RIGHT:
|
|
enemy.rect.right = collider.rect.left
|
|
enemy.direction = c.LEFT
|
|
enemy.x_vel = -2
|
|
elif enemy.direction == c.LEFT:
|
|
enemy.rect.left = collider.rect.right
|
|
enemy.direction = c.RIGHT
|
|
enemy.x_vel = 2
|
|
|
|
|
|
elif enemy_collider:
|
|
if enemy.direction == c.RIGHT:
|
|
enemy.rect.right = enemy_collider.rect.left
|
|
enemy.direction = c.LEFT
|
|
enemy_collider.direction = c.RIGHT
|
|
enemy.x_vel = -2
|
|
enemy_collider.x_vel = 2
|
|
elif enemy.direction == c.LEFT:
|
|
enemy.rect.left = enemy_collider.rect.right
|
|
enemy.direction = c.RIGHT
|
|
enemy_collider.direction = c.LEFT
|
|
enemy.x_vel = 2
|
|
enemy_collider.x_vel = -2
|
|
|
|
self.enemy_group.add(enemy)
|
|
self.mario_and_enemy_group.add(self.enemy_group)
|
|
|
|
|
|
def check_enemy_y_collisions(self, enemy):
|
|
"""Enemy collisions on the y axis"""
|
|
collider = pg.sprite.spritecollideany(enemy, self.ground_step_pipe_group)
|
|
brick = pg.sprite.spritecollideany(enemy, self.brick_group)
|
|
coin_box = pg.sprite.spritecollideany(enemy, self.coin_box_group)
|
|
|
|
if collider:
|
|
if enemy.rect.bottom > collider.rect.bottom:
|
|
enemy.y_vel = 7
|
|
enemy.rect.top = collider.rect.bottom
|
|
enemy.state = c.FALL
|
|
elif enemy.rect.bottom < collider.rect.bottom:
|
|
|
|
enemy.y_vel = 0
|
|
enemy.rect.bottom = collider.rect.top
|
|
enemy.state = c.WALK
|
|
|
|
elif brick:
|
|
if brick.state == c.BUMPED:
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
if self.mario.rect.centerx > brick.rect.centerx:
|
|
enemy.start_death_jump('right')
|
|
else:
|
|
enemy.start_death_jump('left')
|
|
|
|
elif enemy.rect.x > brick.rect.x:
|
|
enemy.y_vel = 7
|
|
enemy.rect.top = brick.rect.bottom
|
|
enemy.state = c.FALL
|
|
else:
|
|
enemy.y_vel = 0
|
|
enemy.rect.bottom = brick.rect.top
|
|
enemy.state = c.WALK
|
|
|
|
elif coin_box:
|
|
if coin_box.state == c.BUMPED:
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(enemy.rect.centerx - self.viewport.x,
|
|
enemy.rect.y, 100))
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
if self.mario.rect.centerx > coin_box.rect.centerx:
|
|
enemy.start_death_jump('right')
|
|
else:
|
|
enemy.start_death_jump('left')
|
|
|
|
elif enemy.rect.x > coin_box.rect.x:
|
|
enemy.y_vel = 7
|
|
enemy.rect.top = coin_box.rect.bottom
|
|
enemy.state = c.FALL
|
|
else:
|
|
enemy.y_vel = 0
|
|
enemy.rect.bottom = coin_box.rect.top
|
|
enemy.state = c.WALK
|
|
|
|
|
|
else:
|
|
enemy.rect.y += 1
|
|
test_group = pg.sprite.Group(self.ground_step_pipe_group,
|
|
self.coin_box_group,
|
|
self.brick_group)
|
|
if pg.sprite.spritecollideany(enemy, test_group) is None:
|
|
if enemy.state != c.JUMP:
|
|
enemy.state = c.FALL
|
|
|
|
enemy.rect.y -= 1
|
|
|
|
|
|
def adjust_shell_position(self):
|
|
"""Moves any koopa in a shell along the x, y axes and checks for
|
|
collisions"""
|
|
for shell in self.shell_group:
|
|
shell.rect.x += shell.x_vel
|
|
self.check_shell_x_collisions(shell)
|
|
|
|
shell.rect.y += shell.y_vel
|
|
self.check_shell_y_collisions(shell)
|
|
self.delete_if_off_screen(shell)
|
|
|
|
|
|
def check_shell_x_collisions(self, shell):
|
|
"""Shell collisions along the x axis"""
|
|
collider = pg.sprite.spritecollideany(shell, self.ground_step_pipe_group)
|
|
enemy = pg.sprite.spritecollideany(shell, self.enemy_group)
|
|
|
|
if collider:
|
|
setup.SFX['bump'].play()
|
|
if shell.x_vel > 0:
|
|
shell.direction = c.LEFT
|
|
shell.rect.right = collider.rect.left
|
|
else:
|
|
shell.direction = c.RIGHT
|
|
shell.rect.left = collider.rect.right
|
|
|
|
if enemy:
|
|
setup.SFX['kick'].play()
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(enemy.rect.right - self.viewport.x,
|
|
enemy.rect.y, 100))
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy)
|
|
enemy.start_death_jump(shell.direction)
|
|
|
|
|
|
def check_shell_y_collisions(self, shell):
|
|
"""Shell collisions along the y axis"""
|
|
collider = pg.sprite.spritecollideany(shell, self.ground_step_pipe_group)
|
|
|
|
if collider:
|
|
shell.y_vel = 0
|
|
shell.rect.bottom = collider.rect.top
|
|
shell.state = c.SHELL_SLIDE
|
|
|
|
else:
|
|
shell.rect.y += 1
|
|
if pg.sprite.spritecollideany(shell, self.ground_step_pipe_group) is None:
|
|
shell.state = c.FALL
|
|
shell.rect.y -= 1
|
|
|
|
|
|
def adjust_powerup_position(self):
|
|
"""Moves mushrooms, stars and fireballs along the x, y axes"""
|
|
for powerup in self.powerup_group:
|
|
if powerup.name == c.MUSHROOM:
|
|
self.adjust_mushroom_position(powerup)
|
|
elif powerup.name == c.STAR:
|
|
self.adjust_star_position(powerup)
|
|
elif powerup.name == c.FIREBALL:
|
|
self.adjust_fireball_position(powerup)
|
|
elif powerup.name == '1up_mushroom':
|
|
self.adjust_mushroom_position(powerup)
|
|
|
|
|
|
def adjust_mushroom_position(self, mushroom):
|
|
"""Moves mushroom along the x, y axes."""
|
|
if mushroom.state != c.REVEAL:
|
|
mushroom.rect.x += mushroom.x_vel
|
|
self.check_mushroom_x_collisions(mushroom)
|
|
|
|
mushroom.rect.y += mushroom.y_vel
|
|
self.check_mushroom_y_collisions(mushroom)
|
|
self.delete_if_off_screen(mushroom)
|
|
|
|
|
|
def check_mushroom_x_collisions(self, mushroom):
|
|
"""Mushroom collisions along the x axis"""
|
|
collider = pg.sprite.spritecollideany(mushroom, self.ground_step_pipe_group)
|
|
brick = pg.sprite.spritecollideany(mushroom, self.brick_group)
|
|
coin_box = pg.sprite.spritecollideany(mushroom, self.coin_box_group)
|
|
|
|
if collider:
|
|
self.adjust_mushroom_for_collision_x(mushroom, collider)
|
|
|
|
elif brick:
|
|
self.adjust_mushroom_for_collision_x(mushroom, brick)
|
|
|
|
elif coin_box:
|
|
self.adjust_mushroom_for_collision_x(mushroom, coin_box)
|
|
|
|
|
|
def check_mushroom_y_collisions(self, mushroom):
|
|
"""Mushroom collisions along the y axis"""
|
|
collider = pg.sprite.spritecollideany(mushroom, self.ground_step_pipe_group)
|
|
brick = pg.sprite.spritecollideany(mushroom, self.brick_group)
|
|
coin_box = pg.sprite.spritecollideany(mushroom, self.coin_box_group)
|
|
|
|
if collider:
|
|
self.adjust_mushroom_for_collision_y(mushroom, collider)
|
|
elif brick:
|
|
self.adjust_mushroom_for_collision_y(mushroom, brick)
|
|
elif coin_box:
|
|
self.adjust_mushroom_for_collision_y(mushroom, coin_box)
|
|
else:
|
|
self.check_if_falling(mushroom, self.ground_step_pipe_group)
|
|
self.check_if_falling(mushroom, self.brick_group)
|
|
self.check_if_falling(mushroom, self.coin_box_group)
|
|
|
|
|
|
def adjust_mushroom_for_collision_x(self, item, collider):
|
|
"""Changes mushroom direction if collision along x axis"""
|
|
if item.rect.x < collider.rect.x:
|
|
item.rect.right = collider.rect.x
|
|
item.direction = c.LEFT
|
|
else:
|
|
item.rect.x = collider.rect.right
|
|
item.direction = c.RIGHT
|
|
|
|
|
|
def adjust_mushroom_for_collision_y(self, item, collider):
|
|
"""Changes mushroom state to SLIDE after hitting ground from fall"""
|
|
item.rect.bottom = collider.rect.y
|
|
item.state = c.SLIDE
|
|
item.y_vel = 0
|
|
|
|
|
|
def adjust_star_position(self, star):
|
|
"""Moves invincible star along x, y axes and checks for collisions"""
|
|
if star.state == c.BOUNCE:
|
|
star.rect.x += star.x_vel
|
|
self.check_mushroom_x_collisions(star)
|
|
star.rect.y += star.y_vel
|
|
self.check_star_y_collisions(star)
|
|
star.y_vel += star.gravity
|
|
self.delete_if_off_screen(star)
|
|
|
|
|
|
def check_star_y_collisions(self, star):
|
|
"""Invincible star collisions along y axis"""
|
|
collider = pg.sprite.spritecollideany(star, self.ground_step_pipe_group)
|
|
brick = pg.sprite.spritecollideany(star, self.brick_group)
|
|
coin_box = pg.sprite.spritecollideany(star, self.coin_box_group)
|
|
|
|
if collider:
|
|
self.adjust_star_for_collision_y(star, collider)
|
|
elif brick:
|
|
self.adjust_star_for_collision_y(star, brick)
|
|
elif coin_box:
|
|
self.adjust_star_for_collision_y(star, coin_box)
|
|
|
|
|
|
def adjust_star_for_collision_y(self, star, collider):
|
|
"""Allows for a star bounce off the ground and on the bottom of a
|
|
box"""
|
|
if star.rect.y > collider.rect.y:
|
|
star.rect.y = collider.rect.bottom
|
|
star.y_vel = 0
|
|
else:
|
|
star.rect.bottom = collider.rect.top
|
|
star.start_bounce(-8)
|
|
|
|
|
|
def adjust_fireball_position(self, fireball):
|
|
"""Moves fireball along the x, y axes and checks for collisions"""
|
|
if fireball.state == c.FLYING:
|
|
fireball.rect.x += fireball.x_vel
|
|
self.check_fireball_x_collisions(fireball)
|
|
fireball.rect.y += fireball.y_vel
|
|
self.check_fireball_y_collisions(fireball)
|
|
elif fireball.state == c.BOUNCING:
|
|
fireball.rect.x += fireball.x_vel
|
|
self.check_fireball_x_collisions(fireball)
|
|
fireball.rect.y += fireball.y_vel
|
|
self.check_fireball_y_collisions(fireball)
|
|
fireball.y_vel += fireball.gravity
|
|
self.delete_if_off_screen(fireball)
|
|
|
|
|
|
def bounce_fireball(self, fireball):
|
|
"""Simulates fireball bounce off ground"""
|
|
fireball.y_vel = -8
|
|
if fireball.direction == c.RIGHT:
|
|
fireball.x_vel = 15
|
|
else:
|
|
fireball.x_vel = -15
|
|
|
|
if fireball in self.powerup_group:
|
|
fireball.state = c.BOUNCING
|
|
|
|
|
|
def check_fireball_x_collisions(self, fireball):
|
|
"""Fireball collisions along x axis"""
|
|
collide_group = pg.sprite.Group(self.ground_group,
|
|
self.pipe_group,
|
|
self.step_group,
|
|
self.coin_box_group,
|
|
self.brick_group)
|
|
|
|
collider = pg.sprite.spritecollideany(fireball, collide_group)
|
|
|
|
if collider:
|
|
fireball.kill()
|
|
self.sprites_about_to_die_group.add(fireball)
|
|
fireball.explode_transition()
|
|
|
|
|
|
|
|
def check_fireball_y_collisions(self, fireball):
|
|
"""Fireball collisions along y axis"""
|
|
collide_group = pg.sprite.Group(self.ground_group,
|
|
self.pipe_group,
|
|
self.step_group,
|
|
self.coin_box_group,
|
|
self.brick_group)
|
|
|
|
collider = pg.sprite.spritecollideany(fireball, collide_group)
|
|
enemy = pg.sprite.spritecollideany(fireball, self.enemy_group)
|
|
shell = pg.sprite.spritecollideany(fireball, self.shell_group)
|
|
|
|
if collider and (fireball in self.powerup_group):
|
|
fireball.rect.bottom = collider.rect.y
|
|
self.bounce_fireball(fireball)
|
|
|
|
elif enemy:
|
|
self.fireball_kill(fireball, enemy)
|
|
|
|
elif shell:
|
|
self.fireball_kill(fireball, shell)
|
|
|
|
|
|
def fireball_kill(self, fireball, enemy):
|
|
"""Kills enemy if hit with fireball"""
|
|
setup.SFX['kick'].play()
|
|
self.game_info[c.SCORE] += 100
|
|
self.moving_score_list.append(
|
|
score.Score(enemy.rect.centerx - self.viewport.x,
|
|
enemy.rect.y,100))
|
|
fireball.kill()
|
|
enemy.kill()
|
|
self.sprites_about_to_die_group.add(enemy, fireball)
|
|
enemy.start_death_jump(fireball.direction)
|
|
fireball.explode_transition()
|
|
|
|
|
|
def check_if_falling(self, sprite, sprite_group):
|
|
"""Checks if sprite should enter a falling state"""
|
|
sprite.rect.y += 1
|
|
|
|
if pg.sprite.spritecollideany(sprite, sprite_group) is None:
|
|
if sprite.state != c.JUMP:
|
|
sprite.state = c.FALL
|
|
|
|
sprite.rect.y -= 1
|
|
|
|
|
|
def delete_if_off_screen(self, enemy):
|
|
"""Removes enemy from sprite groups if 500 pixels left off the screen,
|
|
underneath the bottom of the screen, or right of the screen if shell"""
|
|
if enemy.rect.x < (self.viewport.x - 300):
|
|
enemy.kill()
|
|
|
|
elif enemy.rect.y > (self.viewport.bottom):
|
|
enemy.kill()
|
|
|
|
elif enemy.state == c.SHELL_SLIDE:
|
|
if enemy.rect.x > (self.viewport.right + 500):
|
|
enemy.kill()
|
|
|
|
|
|
def check_flag(self):
|
|
"""Adjusts mario's state when the flag is at the bottom"""
|
|
if (self.flag.state == c.BOTTOM_OF_POLE
|
|
and self.mario.state == c.FLAGPOLE):
|
|
self.mario.set_state_to_bottom_of_pole()
|
|
|
|
|
|
def check_to_add_flag_score(self):
|
|
"""Adds flag score if at top"""
|
|
if self.flag_score.y_vel == 0:
|
|
self.game_info[c.SCORE] += self.flag_score_total
|
|
self.flag_score_total = 0
|
|
|
|
|
|
def check_for_mario_death(self):
|
|
"""Restarts the level if Mario is dead"""
|
|
if self.mario.rect.y > c.SCREEN_HEIGHT and not self.mario.in_castle:
|
|
self.mario.dead = True
|
|
self.mario.x_vel = 0
|
|
self.state = c.FROZEN
|
|
self.game_info[c.MARIO_DEAD] = True
|
|
|
|
if self.mario.dead:
|
|
self.play_death_song()
|
|
|
|
|
|
def play_death_song(self):
|
|
if self.death_timer == 0:
|
|
self.death_timer = self.current_time
|
|
elif (self.current_time - self.death_timer) > 3000:
|
|
self.set_game_info_values()
|
|
self.done = True
|
|
|
|
|
|
def set_game_info_values(self):
|
|
"""sets the new game values after a player's death"""
|
|
if self.game_info[c.SCORE] > self.persist[c.TOP_SCORE]:
|
|
self.persist[c.TOP_SCORE] = self.game_info[c.SCORE]
|
|
if self.mario.dead:
|
|
self.persist[c.LIVES] -= 1
|
|
|
|
if self.persist[c.LIVES] == 0:
|
|
self.next = c.GAME_OVER
|
|
self.game_info[c.CAMERA_START_X] = 0
|
|
elif self.mario.dead == False:
|
|
self.next = c.MAIN_MENU
|
|
self.game_info[c.CAMERA_START_X] = 0
|
|
elif self.overhead_info_display.time == 0:
|
|
self.next = c.TIME_OUT
|
|
else:
|
|
if self.mario.rect.x > 3670 \
|
|
and self.game_info[c.CAMERA_START_X] == 0:
|
|
self.game_info[c.CAMERA_START_X] = 3440
|
|
self.next = c.LOAD_SCREEN
|
|
|
|
|
|
def check_if_time_out(self):
|
|
"""Check if time has run down to 0"""
|
|
if self.overhead_info_display.time <= 0 \
|
|
and not self.mario.dead \
|
|
and not self.mario.in_castle:
|
|
self.state = c.FROZEN
|
|
self.mario.start_death_jump(self.game_info)
|
|
|
|
|
|
def update_viewport(self):
|
|
"""Changes the view of the camera"""
|
|
third = self.viewport.x + self.viewport.w//3
|
|
mario_center = self.mario.rect.centerx
|
|
mario_right = self.mario.rect.right
|
|
|
|
if self.mario.x_vel > 0 and mario_center >= third:
|
|
mult = 0.5 if mario_right < self.viewport.centerx else 1
|
|
new = self.viewport.x + mult * self.mario.x_vel
|
|
highest = self.level_rect.w - self.viewport.w
|
|
self.viewport.x = min(highest, new)
|
|
|
|
|
|
def update_while_in_castle(self):
|
|
"""Updates while Mario is in castle at the end of the level"""
|
|
for score in self.moving_score_list:
|
|
score.update(self.moving_score_list, self.game_info)
|
|
self.overhead_info_display.update(self.game_info)
|
|
|
|
if self.overhead_info_display.state == c.END_OF_LEVEL:
|
|
self.state = c.FLAG_AND_FIREWORKS
|
|
self.flag_pole_group.add(castle_flag.Flag(8745, 322))
|
|
|
|
|
|
def update_flag_and_fireworks(self):
|
|
"""Updates the level for the fireworks and castle flag"""
|
|
for score in self.moving_score_list:
|
|
score.update(self.moving_score_list, self.game_info)
|
|
self.overhead_info_display.update(self.game_info)
|
|
self.flag_pole_group.update()
|
|
|
|
self.end_game()
|
|
|
|
|
|
def end_game(self):
|
|
"""End the game"""
|
|
if self.flag_timer == 0:
|
|
self.flag_timer = self.current_time
|
|
elif (self.current_time - self.flag_timer) > 2000:
|
|
self.set_game_info_values()
|
|
self.next = c.GAME_OVER
|
|
self.sound_manager.stop_music()
|
|
self.done = True
|
|
|
|
|
|
def blit_everything(self, surface):
|
|
"""Blit all sprites to the main surface"""
|
|
self.level.blit(self.background, self.viewport, self.viewport)
|
|
if self.flag_score:
|
|
self.flag_score.draw(self.level)
|
|
self.powerup_group.draw(self.level)
|
|
self.coin_group.draw(self.level)
|
|
self.brick_group.draw(self.level)
|
|
self.coin_box_group.draw(self.level)
|
|
self.sprites_about_to_die_group.draw(self.level)
|
|
self.shell_group.draw(self.level)
|
|
#self.check_point_group.draw(self.level)
|
|
self.brick_pieces_group.draw(self.level)
|
|
self.flag_pole_group.draw(self.level)
|
|
self.mario_and_enemy_group.draw(self.level)
|
|
|
|
surface.blit(self.level, (0,0), self.viewport)
|
|
self.overhead_info_display.draw(surface)
|
|
for score in self.moving_score_list:
|
|
score.draw(surface)
|
|
|
|
|