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.
SuperMario/pythonProject1/data/states/level1.py

1435 lines
56 KiB

6 months ago
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)