@ -0,0 +1,3 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.11 (pythonProject1)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (pythonProject1)" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/pythonProject1.iml" filepath="$PROJECT_DIR$/.idea/pythonProject1.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,197 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
from . import powerups
|
||||||
|
from . import coin
|
||||||
|
|
||||||
|
|
||||||
|
class Brick(pg.sprite.Sprite):
|
||||||
|
"""Bricks that can be destroyed"""
|
||||||
|
def __init__(self, x, y, contents=None, powerup_group=None, name='brick'):
|
||||||
|
"""Initialize the object"""
|
||||||
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
self.sprite_sheet = setup.GFX['tile_set']
|
||||||
|
|
||||||
|
self.frames = []
|
||||||
|
self.frame_index = 0
|
||||||
|
self.setup_frames()
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.mask = pg.mask.from_surface(self.image)
|
||||||
|
self.bumped_up = False
|
||||||
|
self.rest_height = y
|
||||||
|
self.state = c.RESTING
|
||||||
|
self.y_vel = 0
|
||||||
|
self.gravity = 1.2
|
||||||
|
self.name = name
|
||||||
|
self.contents = contents
|
||||||
|
self.setup_contents()
|
||||||
|
self.group = powerup_group
|
||||||
|
self.powerup_in_box = True
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts the image from the sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Set the frames to a list"""
|
||||||
|
self.frames.append(self.get_image(16, 0, 16, 16))
|
||||||
|
self.frames.append(self.get_image(432, 0, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def setup_contents(self):
|
||||||
|
"""Put 6 coins in contents if needed"""
|
||||||
|
if self.contents == '6coins':
|
||||||
|
self.coin_total = 6
|
||||||
|
else:
|
||||||
|
self.coin_total = 0
|
||||||
|
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Updates the brick"""
|
||||||
|
self.handle_states()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_states(self):
|
||||||
|
"""Determines brick behavior based on state"""
|
||||||
|
if self.state == c.RESTING:
|
||||||
|
self.resting()
|
||||||
|
elif self.state == c.BUMPED:
|
||||||
|
self.bumped()
|
||||||
|
elif self.state == c.OPENED:
|
||||||
|
self.opened()
|
||||||
|
|
||||||
|
|
||||||
|
def resting(self):
|
||||||
|
"""State when not moving"""
|
||||||
|
if self.contents == '6coins':
|
||||||
|
if self.coin_total == 0:
|
||||||
|
self.state == c.OPENED
|
||||||
|
|
||||||
|
|
||||||
|
def bumped(self):
|
||||||
|
"""Action during a BUMPED state"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
if self.rect.y >= (self.rest_height + 5):
|
||||||
|
self.rect.y = self.rest_height
|
||||||
|
if self.contents == 'star':
|
||||||
|
self.state = c.OPENED
|
||||||
|
elif self.contents == '6coins':
|
||||||
|
if self.coin_total == 0:
|
||||||
|
self.state = c.OPENED
|
||||||
|
else:
|
||||||
|
self.state = c.RESTING
|
||||||
|
else:
|
||||||
|
self.state = c.RESTING
|
||||||
|
|
||||||
|
|
||||||
|
def start_bump(self, score_group):
|
||||||
|
"""Transitions brick into BUMPED state"""
|
||||||
|
self.y_vel = -6
|
||||||
|
|
||||||
|
if self.contents == '6coins':
|
||||||
|
setup.SFX['coin'].play()
|
||||||
|
|
||||||
|
if self.coin_total > 0:
|
||||||
|
self.group.add(coin.Coin(self.rect.centerx, self.rect.y, score_group))
|
||||||
|
self.coin_total -= 1
|
||||||
|
if self.coin_total == 0:
|
||||||
|
self.frame_index = 1
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
elif self.contents == 'star':
|
||||||
|
setup.SFX['powerup_appears'].play()
|
||||||
|
self.frame_index = 1
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
self.state = c.BUMPED
|
||||||
|
|
||||||
|
|
||||||
|
def opened(self):
|
||||||
|
"""Action during OPENED state"""
|
||||||
|
self.frame_index = 1
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
if self.contents == 'star' and self.powerup_in_box:
|
||||||
|
self.group.add(powerups.Star(self.rect.centerx, self.rest_height))
|
||||||
|
self.powerup_in_box = False
|
||||||
|
|
||||||
|
|
||||||
|
class BrickPiece(pg.sprite.Sprite):
|
||||||
|
"""Pieces that appear when bricks are broken"""
|
||||||
|
def __init__(self, x, y, xvel, yvel):
|
||||||
|
super(BrickPiece, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.setup_frames()
|
||||||
|
self.frame_index = 0
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.x_vel = xvel
|
||||||
|
self.y_vel = yvel
|
||||||
|
self.gravity = .8
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""create the frame list"""
|
||||||
|
self.frames = []
|
||||||
|
|
||||||
|
image = self.get_image(68, 20, 8, 8)
|
||||||
|
reversed_image = pg.transform.flip(image, True, False)
|
||||||
|
|
||||||
|
self.frames.append(image)
|
||||||
|
self.frames.append(reversed_image)
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extract image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Update brick piece"""
|
||||||
|
self.rect.x += self.x_vel
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
self.check_if_off_screen()
|
||||||
|
|
||||||
|
def check_if_off_screen(self):
|
||||||
|
"""Remove from sprite groups if off screen"""
|
||||||
|
if self.rect.y > c.SCREEN_HEIGHT:
|
||||||
|
self.kill()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
class Flag(pg.sprite.Sprite):
|
||||||
|
"""Flag on the castle"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
"""Initialize object"""
|
||||||
|
super(Flag, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.image = self.get_image(129, 2, 14, 14)
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.state = 'rising'
|
||||||
|
self.y_vel = -2
|
||||||
|
self.target_height = y
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
def update(self, *args):
|
||||||
|
"""Updates flag position"""
|
||||||
|
if self.state == 'rising':
|
||||||
|
self.rising()
|
||||||
|
elif self.state == 'resting':
|
||||||
|
self.resting()
|
||||||
|
|
||||||
|
def rising(self):
|
||||||
|
"""State when flag is rising to be on the castle"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
if self.rect.bottom <= self.target_height:
|
||||||
|
self.state = 'resting'
|
||||||
|
|
||||||
|
def resting(self):
|
||||||
|
"""State when the flag is stationary doing nothing"""
|
||||||
|
pass
|
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
class Checkpoint(pg.sprite.Sprite):
|
||||||
|
"""Invisible sprite used to add enemies, special boxes
|
||||||
|
and trigger sliding down the flag pole"""
|
||||||
|
def __init__(self, x, name, y=0, width=10, height=600):
|
||||||
|
super(Checkpoint, self).__init__()
|
||||||
|
self.image = pg.Surface((width, height))
|
||||||
|
self.image.fill(c.BLACK)
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
from . import score
|
||||||
|
|
||||||
|
|
||||||
|
class Coin(pg.sprite.Sprite):
|
||||||
|
"""Coins found in boxes and bricks"""
|
||||||
|
def __init__(self, x, y, score_group):
|
||||||
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.frames = []
|
||||||
|
self.frame_index = 0
|
||||||
|
self.animation_timer = 0
|
||||||
|
self.state = c.SPIN
|
||||||
|
self.setup_frames()
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.centerx = x
|
||||||
|
self.rect.bottom = y - 5
|
||||||
|
self.gravity = 1
|
||||||
|
self.y_vel = -15
|
||||||
|
self.initial_height = self.rect.bottom - 5
|
||||||
|
self.score_group = score_group
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Get the image frames from the sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""create the frame list"""
|
||||||
|
self.frames.append(self.get_image(52, 113, 8, 14))
|
||||||
|
self.frames.append(self.get_image(4, 113, 8, 14))
|
||||||
|
self.frames.append(self.get_image(20, 113, 8, 14))
|
||||||
|
self.frames.append(self.get_image(36, 113, 8, 14))
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info, viewport):
|
||||||
|
"""Update the coin's behavior"""
|
||||||
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
|
self.viewport = viewport
|
||||||
|
if self.state == c.SPIN:
|
||||||
|
self.spinning()
|
||||||
|
|
||||||
|
|
||||||
|
def spinning(self):
|
||||||
|
"""Action when the coin is in the SPIN state"""
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
if (self.current_time - self.animation_timer) > 80:
|
||||||
|
if self.frame_index < 3:
|
||||||
|
self.frame_index += 1
|
||||||
|
else:
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
|
||||||
|
if self.rect.bottom > self.initial_height:
|
||||||
|
self.kill()
|
||||||
|
self.score_group.append(score.Score(self.rect.centerx - self.viewport.x,
|
||||||
|
self.rect.y,
|
||||||
|
200))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
from . import powerups
|
||||||
|
from . import coin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Coin_box(pg.sprite.Sprite):
|
||||||
|
"""Coin box sprite"""
|
||||||
|
def __init__(self, x, y, contents='coin', group=None):
|
||||||
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
self.sprite_sheet = setup.GFX['tile_set']
|
||||||
|
self.frames = []
|
||||||
|
self.setup_frames()
|
||||||
|
self.frame_index = 0
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.mask = pg.mask.from_surface(self.image)
|
||||||
|
self.animation_timer = 0
|
||||||
|
self.first_half = True # First half of animation cycle
|
||||||
|
self.state = c.RESTING
|
||||||
|
self.rest_height = y
|
||||||
|
self.gravity = 1.2
|
||||||
|
self.y_vel = 0
|
||||||
|
self.contents = contents
|
||||||
|
self.group = group
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extract image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Create frame list"""
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(384, 0, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(400, 0, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(416, 0, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(432, 0, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info):
|
||||||
|
"""Update coin box behavior"""
|
||||||
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
|
self.handle_states()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_states(self):
|
||||||
|
"""Determine action based on RESTING, BUMPED or OPENED
|
||||||
|
state"""
|
||||||
|
if self.state == c.RESTING:
|
||||||
|
self.resting()
|
||||||
|
elif self.state == c.BUMPED:
|
||||||
|
self.bumped()
|
||||||
|
elif self.state == c.OPENED:
|
||||||
|
self.opened()
|
||||||
|
|
||||||
|
|
||||||
|
def resting(self):
|
||||||
|
"""Action when in the RESTING state"""
|
||||||
|
if self.first_half:
|
||||||
|
if self.frame_index == 0:
|
||||||
|
if (self.current_time - self.animation_timer) > 375:
|
||||||
|
self.frame_index += 1
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
elif self.frame_index < 2:
|
||||||
|
if (self.current_time - self.animation_timer) > 125:
|
||||||
|
self.frame_index += 1
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
elif self.frame_index == 2:
|
||||||
|
if (self.current_time - self.animation_timer) > 125:
|
||||||
|
self.frame_index -= 1
|
||||||
|
self.first_half = False
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
else:
|
||||||
|
if self.frame_index == 1:
|
||||||
|
if (self.current_time - self.animation_timer) > 125:
|
||||||
|
self.frame_index -= 1
|
||||||
|
self.first_half = True
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
|
||||||
|
def bumped(self):
|
||||||
|
"""Action after Mario has bumped the box from below"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
if self.rect.y > self.rest_height + 5:
|
||||||
|
self.rect.y = self.rest_height
|
||||||
|
self.state = c.OPENED
|
||||||
|
if self.contents == 'mushroom':
|
||||||
|
self.group.add(powerups.Mushroom(self.rect.centerx, self.rect.y))
|
||||||
|
elif self.contents == 'fireflower':
|
||||||
|
self.group.add(powerups.FireFlower(self.rect.centerx, self.rect.y))
|
||||||
|
elif self.contents == '1up_mushroom':
|
||||||
|
self.group.add(powerups.LifeMushroom(self.rect.centerx, self.rect.y))
|
||||||
|
|
||||||
|
|
||||||
|
self.frame_index = 3
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
|
||||||
|
def start_bump(self, score_group):
|
||||||
|
"""Transitions box into BUMPED state"""
|
||||||
|
self.y_vel = -6
|
||||||
|
self.state = c.BUMPED
|
||||||
|
|
||||||
|
if self.contents == 'coin':
|
||||||
|
self.group.add(coin.Coin(self.rect.centerx,
|
||||||
|
self.rect.y,
|
||||||
|
score_group))
|
||||||
|
setup.SFX['coin'].play()
|
||||||
|
else:
|
||||||
|
setup.SFX['powerup_appears'].play()
|
||||||
|
|
||||||
|
|
||||||
|
def opened(self):
|
||||||
|
"""Placeholder for OPENED state"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
class Collider(pg.sprite.Sprite):
|
||||||
|
"""Invisible sprites placed overtop background parts
|
||||||
|
that can be collided with (pipes, steps, ground, etc."""
|
||||||
|
def __init__(self, x, y, width, height, name='collider'):
|
||||||
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
self.image = pg.Surface((width, height)).convert()
|
||||||
|
#self.image.fill(c.RED)
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.state = None
|
||||||
|
|
@ -0,0 +1,215 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
class Enemy(pg.sprite.Sprite):
|
||||||
|
"""Base class for all enemies (Goombas, Koopas, etc.)"""
|
||||||
|
def __init__(self):
|
||||||
|
pg.sprite.Sprite.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_enemy(self, x, y, direction, name, setup_frames):
|
||||||
|
"""Sets up various values for enemy"""
|
||||||
|
self.sprite_sheet = setup.GFX['smb_enemies_sheet']
|
||||||
|
self.frames = []
|
||||||
|
self.frame_index = 0
|
||||||
|
self.animate_timer = 0
|
||||||
|
self.death_timer = 0
|
||||||
|
self.gravity = 1.5
|
||||||
|
self.state = c.WALK
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.direction = direction
|
||||||
|
setup_frames()
|
||||||
|
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.bottom = y
|
||||||
|
self.set_velocity()
|
||||||
|
|
||||||
|
|
||||||
|
def set_velocity(self):
|
||||||
|
"""Sets velocity vector based on direction"""
|
||||||
|
if self.direction == c.LEFT:
|
||||||
|
self.x_vel = -2
|
||||||
|
else:
|
||||||
|
self.x_vel = 2
|
||||||
|
|
||||||
|
self.y_vel = 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Get the image frames from the sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Enemy behavior based on state"""
|
||||||
|
if self.state == c.WALK:
|
||||||
|
self.walking()
|
||||||
|
elif self.state == c.FALL:
|
||||||
|
self.falling()
|
||||||
|
elif self.state == c.JUMPED_ON:
|
||||||
|
self.jumped_on()
|
||||||
|
elif self.state == c.SHELL_SLIDE:
|
||||||
|
self.shell_sliding()
|
||||||
|
elif self.state == c.DEATH_JUMP:
|
||||||
|
self.death_jumping()
|
||||||
|
|
||||||
|
|
||||||
|
def walking(self):
|
||||||
|
"""Default state of moving sideways"""
|
||||||
|
if (self.current_time - self.animate_timer) > 125:
|
||||||
|
if self.frame_index == 0:
|
||||||
|
self.frame_index += 1
|
||||||
|
elif self.frame_index == 1:
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
self.animate_timer = self.current_time
|
||||||
|
|
||||||
|
|
||||||
|
def falling(self):
|
||||||
|
"""For when it falls off a ledge"""
|
||||||
|
if self.y_vel < 10:
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
|
||||||
|
def jumped_on(self):
|
||||||
|
"""Placeholder for when the enemy is stomped on"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def death_jumping(self):
|
||||||
|
"""Death animation"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
self.rect.x += self.x_vel
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
if self.rect.y > 600:
|
||||||
|
self.kill()
|
||||||
|
|
||||||
|
|
||||||
|
def start_death_jump(self, direction):
|
||||||
|
"""Transitions enemy into a DEATH JUMP state"""
|
||||||
|
self.y_vel = -8
|
||||||
|
if direction == c.RIGHT:
|
||||||
|
self.x_vel = 2
|
||||||
|
else:
|
||||||
|
self.x_vel = -2
|
||||||
|
self.gravity = .5
|
||||||
|
self.frame_index = 3
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.state = c.DEATH_JUMP
|
||||||
|
|
||||||
|
|
||||||
|
def animation(self):
|
||||||
|
"""Basic animation, switching between two frames"""
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info, *args):
|
||||||
|
"""Updates enemy behavior"""
|
||||||
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
|
self.handle_state()
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Goomba(Enemy):
|
||||||
|
|
||||||
|
def __init__(self, y=c.GROUND_HEIGHT, x=0, direction=c.LEFT, name='goomba'):
|
||||||
|
Enemy.__init__(self)
|
||||||
|
self.setup_enemy(x, y, direction, name, self.setup_frames)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Put the image frames in a list to be animated"""
|
||||||
|
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(0, 4, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(30, 4, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(61, 0, 16, 16))
|
||||||
|
self.frames.append(pg.transform.flip(self.frames[1], False, True))
|
||||||
|
|
||||||
|
|
||||||
|
def jumped_on(self):
|
||||||
|
"""When Mario squishes him"""
|
||||||
|
self.frame_index = 2
|
||||||
|
|
||||||
|
if (self.current_time - self.death_timer) > 500:
|
||||||
|
self.kill()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Koopa(Enemy):
|
||||||
|
|
||||||
|
def __init__(self, y=c.GROUND_HEIGHT, x=0, direction=c.LEFT, name='koopa'):
|
||||||
|
Enemy.__init__(self)
|
||||||
|
self.setup_enemy(x, y, direction, name, self.setup_frames)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Sets frame list"""
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(150, 0, 16, 24))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(180, 0, 16, 24))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(360, 5, 16, 15))
|
||||||
|
self.frames.append(pg.transform.flip(self.frames[2], False, True))
|
||||||
|
|
||||||
|
|
||||||
|
def jumped_on(self):
|
||||||
|
"""When Mario jumps on the Koopa and puts him in his shell"""
|
||||||
|
self.x_vel = 0
|
||||||
|
self.frame_index = 2
|
||||||
|
shell_y = self.rect.bottom
|
||||||
|
shell_x = self.rect.x
|
||||||
|
self.rect = self.frames[self.frame_index].get_rect()
|
||||||
|
self.rect.x = shell_x
|
||||||
|
self.rect.bottom = shell_y
|
||||||
|
|
||||||
|
|
||||||
|
def shell_sliding(self):
|
||||||
|
"""When the koopa is sliding along the ground in his shell"""
|
||||||
|
if self.direction == c.RIGHT:
|
||||||
|
self.x_vel = 10
|
||||||
|
elif self.direction == c.LEFT:
|
||||||
|
self.x_vel = -10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
class Flag(pg.sprite.Sprite):
|
||||||
|
"""Flag on top of the flag pole at the end of the level"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Flag, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.setup_images()
|
||||||
|
self.image = self.frames[0]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.right = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.state = c.TOP_OF_POLE
|
||||||
|
|
||||||
|
|
||||||
|
def setup_images(self):
|
||||||
|
"""Sets up a list of image frames"""
|
||||||
|
self.frames = []
|
||||||
|
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(128, 32, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, *args):
|
||||||
|
"""Updates behavior"""
|
||||||
|
self.handle_state()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Determines behavior based on state"""
|
||||||
|
if self.state == c.TOP_OF_POLE:
|
||||||
|
self.image = self.frames[0]
|
||||||
|
elif self.state == c.SLIDE_DOWN:
|
||||||
|
self.sliding_down()
|
||||||
|
elif self.state == c.BOTTOM_OF_POLE:
|
||||||
|
self.image = self.frames[0]
|
||||||
|
|
||||||
|
|
||||||
|
def sliding_down(self):
|
||||||
|
"""State when Mario reaches flag pole"""
|
||||||
|
self.y_vel = 5
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
|
||||||
|
if self.rect.bottom >= 485:
|
||||||
|
self.state = c.BOTTOM_OF_POLE
|
||||||
|
|
||||||
|
|
||||||
|
class Pole(pg.sprite.Sprite):
|
||||||
|
"""Pole that the flag is on top of"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Pole, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['tile_set']
|
||||||
|
self.setup_frames()
|
||||||
|
self.image = self.frames[0]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Create the frame list"""
|
||||||
|
self.frames = []
|
||||||
|
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(263, 144, 2, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, *args):
|
||||||
|
"""Placeholder for update, since there is nothing to update"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Finial(pg.sprite.Sprite):
|
||||||
|
"""The top of the flag pole"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Finial, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['tile_set']
|
||||||
|
self.setup_frames()
|
||||||
|
self.image = self.frames[0]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.centerx = x
|
||||||
|
self.rect.bottom = y
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Creates the self.frames list"""
|
||||||
|
self.frames = []
|
||||||
|
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(228, 120, 8, 8))
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
class Coin(pg.sprite.Sprite):
|
||||||
|
"""Flashing coin next to coin total info"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Coin, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.create_frames()
|
||||||
|
self.image = self.frames[0]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.x = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.timer = 0
|
||||||
|
self.first_half = True
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
|
||||||
|
def create_frames(self):
|
||||||
|
"""Extract coin images from sprite sheet and assign them to a list"""
|
||||||
|
self.frames = []
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
self.frames.append(self.get_image(1, 160, 5, 8))
|
||||||
|
self.frames.append(self.get_image(9, 160, 5, 8))
|
||||||
|
self.frames.append(self.get_image(17, 160, 5, 8))
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, current_time):
|
||||||
|
"""Animates flashing coin"""
|
||||||
|
if self.first_half:
|
||||||
|
if self.frame_index == 0:
|
||||||
|
if (current_time - self.timer) > 375:
|
||||||
|
self.frame_index += 1
|
||||||
|
self.timer = current_time
|
||||||
|
elif self.frame_index < 2:
|
||||||
|
if (current_time - self.timer) > 125:
|
||||||
|
self.frame_index += 1
|
||||||
|
self.timer = current_time
|
||||||
|
elif self.frame_index == 2:
|
||||||
|
if (current_time - self.timer) > 125:
|
||||||
|
self.frame_index -= 1
|
||||||
|
self.first_half = False
|
||||||
|
self.timer = current_time
|
||||||
|
else:
|
||||||
|
if self.frame_index == 1:
|
||||||
|
if (current_time - self.timer) > 125:
|
||||||
|
self.frame_index -= 1
|
||||||
|
self.first_half = True
|
||||||
|
self.timer = current_time
|
||||||
|
|
||||||
|
self.image = self.frames[self.frame_index]
|
@ -0,0 +1,462 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
from . import flashing_coin
|
||||||
|
|
||||||
|
|
||||||
|
class Character(pg.sprite.Sprite):
|
||||||
|
"""Parent class for all characters used for the overhead level info"""
|
||||||
|
def __init__(self, image):
|
||||||
|
super(Character, self).__init__()
|
||||||
|
self.image = image
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
|
||||||
|
|
||||||
|
class OverheadInfo(object):
|
||||||
|
"""Class for level information like score, coin total,
|
||||||
|
and time remaining"""
|
||||||
|
def __init__(self, game_info, state):
|
||||||
|
self.sprite_sheet = setup.GFX['text_images']
|
||||||
|
self.coin_total = game_info[c.COIN_TOTAL]
|
||||||
|
self.time = 401
|
||||||
|
self.current_time = 0
|
||||||
|
self.total_lives = game_info[c.LIVES]
|
||||||
|
self.top_score = game_info[c.TOP_SCORE]
|
||||||
|
self.state = state
|
||||||
|
self.special_state = None
|
||||||
|
self.game_info = game_info
|
||||||
|
|
||||||
|
self.create_image_dict()
|
||||||
|
self.create_score_group()
|
||||||
|
self.create_info_labels()
|
||||||
|
self.create_load_screen_labels()
|
||||||
|
self.create_countdown_clock()
|
||||||
|
self.create_coin_counter()
|
||||||
|
self.create_flashing_coin()
|
||||||
|
self.create_mario_image()
|
||||||
|
self.create_game_over_label()
|
||||||
|
self.create_time_out_label()
|
||||||
|
self.create_main_menu_labels()
|
||||||
|
|
||||||
|
|
||||||
|
def create_image_dict(self):
|
||||||
|
"""Creates the initial images for the score"""
|
||||||
|
self.image_dict = {}
|
||||||
|
image_list = []
|
||||||
|
|
||||||
|
image_list.append(self.get_image(3, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(12, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(19, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(27, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(35, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(43, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(51, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(59, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(67, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(75, 230, 7, 7))
|
||||||
|
|
||||||
|
image_list.append(self.get_image(83, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(91, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(99, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(107, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(115, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(123, 230, 7, 7))
|
||||||
|
image_list.append(self.get_image(3, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(11, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(20, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(27, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(35, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(44, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(51, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(59, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(67, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(75, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(83, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(91, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(99, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(108, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(115, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(123, 238, 7, 7))
|
||||||
|
image_list.append(self.get_image(3, 246, 7, 7))
|
||||||
|
image_list.append(self.get_image(11, 246, 7, 7))
|
||||||
|
image_list.append(self.get_image(20, 246, 7, 7))
|
||||||
|
image_list.append(self.get_image(27, 246, 7, 7))
|
||||||
|
image_list.append(self.get_image(48, 248, 7, 7))
|
||||||
|
|
||||||
|
image_list.append(self.get_image(68, 249, 6, 2))
|
||||||
|
image_list.append(self.get_image(75, 247, 6, 6))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
character_string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -*'
|
||||||
|
|
||||||
|
for character, image in zip(character_string, image_list):
|
||||||
|
self.image_dict[character] = image
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey((92, 148, 252))
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*2.9),
|
||||||
|
int(rect.height*2.9)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def create_score_group(self):
|
||||||
|
"""Creates the initial empty score (000000)"""
|
||||||
|
self.score_images = []
|
||||||
|
self.create_label(self.score_images, '000000', 75, 55)
|
||||||
|
|
||||||
|
|
||||||
|
def create_info_labels(self):
|
||||||
|
"""Creates the labels that describe each info"""
|
||||||
|
self.mario_label = []
|
||||||
|
self.world_label = []
|
||||||
|
self.time_label = []
|
||||||
|
self.stage_label = []
|
||||||
|
|
||||||
|
|
||||||
|
self.create_label(self.mario_label, 'MARIO', 75, 30)
|
||||||
|
self.create_label(self.world_label, 'WORLD', 450, 30)
|
||||||
|
self.create_label(self.time_label, 'TIME', 625, 30)
|
||||||
|
self.create_label(self.stage_label, '1-1', 472, 55)
|
||||||
|
|
||||||
|
self.label_list = [self.mario_label,
|
||||||
|
self.world_label,
|
||||||
|
self.time_label,
|
||||||
|
self.stage_label]
|
||||||
|
|
||||||
|
|
||||||
|
def create_load_screen_labels(self):
|
||||||
|
"""Creates labels for the center info of a load screen"""
|
||||||
|
world_label = []
|
||||||
|
number_label = []
|
||||||
|
|
||||||
|
self.create_label(world_label, 'WORLD', 280, 200)
|
||||||
|
self.create_label(number_label, '1-1', 430, 200)
|
||||||
|
|
||||||
|
self.center_labels = [world_label, number_label]
|
||||||
|
|
||||||
|
|
||||||
|
def create_countdown_clock(self):
|
||||||
|
"""Creates the count down clock for the level"""
|
||||||
|
self.count_down_images = []
|
||||||
|
self.create_label(self.count_down_images, str(self.time), 645, 55)
|
||||||
|
|
||||||
|
|
||||||
|
def create_label(self, label_list, string, x, y):
|
||||||
|
"""Creates a label (WORLD, TIME, MARIO)"""
|
||||||
|
for letter in string:
|
||||||
|
label_list.append(Character(self.image_dict[letter]))
|
||||||
|
|
||||||
|
self.set_label_rects(label_list, x, y)
|
||||||
|
|
||||||
|
|
||||||
|
def set_label_rects(self, label_list, x, y):
|
||||||
|
"""Set the location of each individual character"""
|
||||||
|
for i, letter in enumerate(label_list):
|
||||||
|
letter.rect.x = x + ((letter.rect.width + 3) * i)
|
||||||
|
letter.rect.y = y
|
||||||
|
if letter.image == self.image_dict['-']:
|
||||||
|
letter.rect.y += 7
|
||||||
|
letter.rect.x += 2
|
||||||
|
|
||||||
|
|
||||||
|
def create_coin_counter(self):
|
||||||
|
"""Creates the info that tracks the number of coins Mario collects"""
|
||||||
|
self.coin_count_images = []
|
||||||
|
self.create_label(self.coin_count_images, '*00', 300, 55)
|
||||||
|
|
||||||
|
|
||||||
|
def create_flashing_coin(self):
|
||||||
|
"""Creates the flashing coin next to the coin total"""
|
||||||
|
self.flashing_coin = flashing_coin.Coin(280, 53)
|
||||||
|
|
||||||
|
|
||||||
|
def create_mario_image(self):
|
||||||
|
"""Get the mario image"""
|
||||||
|
self.life_times_image = self.get_image(75, 247, 6, 6)
|
||||||
|
self.life_times_rect = self.life_times_image.get_rect(center=(378, 295))
|
||||||
|
self.life_total_label = []
|
||||||
|
self.create_label(self.life_total_label, str(self.total_lives),
|
||||||
|
450, 285)
|
||||||
|
|
||||||
|
self.sprite_sheet = setup.GFX['mario_bros']
|
||||||
|
self.mario_image = self.get_image(178, 32, 12, 16)
|
||||||
|
self.mario_rect = self.mario_image.get_rect(center=(320, 290))
|
||||||
|
|
||||||
|
|
||||||
|
def create_game_over_label(self):
|
||||||
|
"""Create the label for the GAME OVER screen"""
|
||||||
|
game_label = []
|
||||||
|
over_label = []
|
||||||
|
|
||||||
|
self.create_label(game_label, 'GAME', 280, 300)
|
||||||
|
self.create_label(over_label, 'OVER', 400, 300)
|
||||||
|
|
||||||
|
self.game_over_label = [game_label, over_label]
|
||||||
|
|
||||||
|
|
||||||
|
def create_time_out_label(self):
|
||||||
|
"""Create the label for the time out screen"""
|
||||||
|
time_out_label = []
|
||||||
|
|
||||||
|
self.create_label(time_out_label, 'TIME OUT', 290, 310)
|
||||||
|
self.time_out_label = [time_out_label]
|
||||||
|
|
||||||
|
|
||||||
|
def create_main_menu_labels(self):
|
||||||
|
"""Create labels for the MAIN MENU screen"""
|
||||||
|
player_one_game = []
|
||||||
|
player_two_game = []
|
||||||
|
top = []
|
||||||
|
top_score = []
|
||||||
|
|
||||||
|
self.create_label(player_one_game, '1 PLAYER GAME', 272, 360)
|
||||||
|
self.create_label(player_two_game, '2 PLAYER GAME', 272, 405)
|
||||||
|
self.create_label(top, 'TOP - ', 290, 465)
|
||||||
|
self.create_label(top_score, '000000', 400, 465)
|
||||||
|
|
||||||
|
self.main_menu_labels = [player_one_game, player_two_game,
|
||||||
|
top, top_score]
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, level_info, mario=None):
|
||||||
|
"""Updates all overhead info"""
|
||||||
|
self.mario = mario
|
||||||
|
self.handle_level_state(level_info)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_level_state(self, level_info):
|
||||||
|
"""Updates info based on what state the game is in"""
|
||||||
|
if self.state == c.MAIN_MENU:
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
self.update_score_images(self.main_menu_labels[3], self.top_score)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
self.flashing_coin.update(level_info[c.CURRENT_TIME])
|
||||||
|
|
||||||
|
elif self.state == c.LOAD_SCREEN:
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
|
||||||
|
elif self.state == c.LEVEL:
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
if level_info[c.LEVEL_STATE] != c.FROZEN \
|
||||||
|
and self.mario.state != c.WALKING_TO_CASTLE \
|
||||||
|
and self.mario.state != c.END_OF_LEVEL_FALL \
|
||||||
|
and not self.mario.dead:
|
||||||
|
self.update_count_down_clock(level_info)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
self.flashing_coin.update(level_info[c.CURRENT_TIME])
|
||||||
|
|
||||||
|
elif self.state == c.TIME_OUT:
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
|
||||||
|
elif self.state == c.GAME_OVER:
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
|
||||||
|
elif self.state == c.FAST_COUNT_DOWN:
|
||||||
|
level_info[c.SCORE] += 50
|
||||||
|
self.score = level_info[c.SCORE]
|
||||||
|
self.update_count_down_clock(level_info)
|
||||||
|
self.update_score_images(self.score_images, self.score)
|
||||||
|
self.update_coin_total(level_info)
|
||||||
|
self.flashing_coin.update(level_info[c.CURRENT_TIME])
|
||||||
|
if self.time == 0:
|
||||||
|
self.state = c.END_OF_LEVEL
|
||||||
|
|
||||||
|
elif self.state == c.END_OF_LEVEL:
|
||||||
|
self.flashing_coin.update(level_info[c.CURRENT_TIME])
|
||||||
|
|
||||||
|
|
||||||
|
def update_score_images(self, images, score):
|
||||||
|
"""Updates what numbers are to be blitted for the score"""
|
||||||
|
index = len(images) - 1
|
||||||
|
|
||||||
|
for digit in reversed(str(score)):
|
||||||
|
rect = images[index].rect
|
||||||
|
images[index] = Character(self.image_dict[digit])
|
||||||
|
images[index].rect = rect
|
||||||
|
index -= 1
|
||||||
|
|
||||||
|
|
||||||
|
def update_count_down_clock(self, level_info):
|
||||||
|
"""Updates current time"""
|
||||||
|
if self.state == c.FAST_COUNT_DOWN:
|
||||||
|
self.time -= 1
|
||||||
|
|
||||||
|
elif (level_info[c.CURRENT_TIME] - self.current_time) > 400:
|
||||||
|
self.current_time = level_info[c.CURRENT_TIME]
|
||||||
|
self.time -= 1
|
||||||
|
self.count_down_images = []
|
||||||
|
self.create_label(self.count_down_images, str(self.time), 645, 55)
|
||||||
|
if len(self.count_down_images) < 2:
|
||||||
|
for i in range(2):
|
||||||
|
self.count_down_images.insert(0, Character(self.image_dict['0']))
|
||||||
|
self.set_label_rects(self.count_down_images, 645, 55)
|
||||||
|
elif len(self.count_down_images) < 3:
|
||||||
|
self.count_down_images.insert(0, Character(self.image_dict['0']))
|
||||||
|
self.set_label_rects(self.count_down_images, 645, 55)
|
||||||
|
|
||||||
|
|
||||||
|
def update_coin_total(self, level_info):
|
||||||
|
"""Updates the coin total and adjusts label accordingly"""
|
||||||
|
self.coin_total = level_info[c.COIN_TOTAL]
|
||||||
|
|
||||||
|
coin_string = str(self.coin_total)
|
||||||
|
if len(coin_string) < 2:
|
||||||
|
coin_string = '*0' + coin_string
|
||||||
|
elif len(coin_string) > 2:
|
||||||
|
coin_string = '*00'
|
||||||
|
else:
|
||||||
|
coin_string = '*' + coin_string
|
||||||
|
|
||||||
|
x = self.coin_count_images[0].rect.x
|
||||||
|
y = self.coin_count_images[0].rect.y
|
||||||
|
|
||||||
|
self.coin_count_images = []
|
||||||
|
|
||||||
|
self.create_label(self.coin_count_images, coin_string, x, y)
|
||||||
|
|
||||||
|
|
||||||
|
def draw(self, surface):
|
||||||
|
"""Draws overhead info based on state"""
|
||||||
|
if self.state == c.MAIN_MENU:
|
||||||
|
self.draw_main_menu_info(surface)
|
||||||
|
elif self.state == c.LOAD_SCREEN:
|
||||||
|
self.draw_loading_screen_info(surface)
|
||||||
|
elif self.state == c.LEVEL:
|
||||||
|
self.draw_level_screen_info(surface)
|
||||||
|
elif self.state == c.GAME_OVER:
|
||||||
|
self.draw_game_over_screen_info(surface)
|
||||||
|
elif self.state == c.FAST_COUNT_DOWN:
|
||||||
|
self.draw_level_screen_info(surface)
|
||||||
|
elif self.state == c.END_OF_LEVEL:
|
||||||
|
self.draw_level_screen_info(surface)
|
||||||
|
elif self.state == c.TIME_OUT:
|
||||||
|
self.draw_time_out_screen_info(surface)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def draw_main_menu_info(self, surface):
|
||||||
|
"""Draws info for main menu"""
|
||||||
|
for info in self.score_images:
|
||||||
|
surface.blit(info.image, info.rect)
|
||||||
|
|
||||||
|
for label in self.main_menu_labels:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
for character in self.coin_count_images:
|
||||||
|
surface.blit(character.image, character.rect)
|
||||||
|
|
||||||
|
for label in self.label_list:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
surface.blit(self.flashing_coin.image, self.flashing_coin.rect)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_loading_screen_info(self, surface):
|
||||||
|
"""Draws info for loading screen"""
|
||||||
|
for info in self.score_images:
|
||||||
|
surface.blit(info.image, info.rect)
|
||||||
|
|
||||||
|
for word in self.center_labels:
|
||||||
|
for letter in word:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
for word in self.life_total_label:
|
||||||
|
surface.blit(word.image, word.rect)
|
||||||
|
|
||||||
|
surface.blit(self.mario_image, self.mario_rect)
|
||||||
|
surface.blit(self.life_times_image, self.life_times_rect)
|
||||||
|
|
||||||
|
for character in self.coin_count_images:
|
||||||
|
surface.blit(character.image, character.rect)
|
||||||
|
|
||||||
|
for label in self.label_list:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
surface.blit(self.flashing_coin.image, self.flashing_coin.rect)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_level_screen_info(self, surface):
|
||||||
|
"""Draws info during regular game play"""
|
||||||
|
for info in self.score_images:
|
||||||
|
surface.blit(info.image, info.rect)
|
||||||
|
|
||||||
|
for digit in self.count_down_images:
|
||||||
|
surface.blit(digit.image, digit.rect)
|
||||||
|
|
||||||
|
for character in self.coin_count_images:
|
||||||
|
surface.blit(character.image, character.rect)
|
||||||
|
|
||||||
|
for label in self.label_list:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
surface.blit(self.flashing_coin.image, self.flashing_coin.rect)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_game_over_screen_info(self, surface):
|
||||||
|
"""Draws info when game over"""
|
||||||
|
for info in self.score_images:
|
||||||
|
surface.blit(info.image, info.rect)
|
||||||
|
|
||||||
|
for word in self.game_over_label:
|
||||||
|
for letter in word:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
for character in self.coin_count_images:
|
||||||
|
surface.blit(character.image, character.rect)
|
||||||
|
|
||||||
|
for label in self.label_list:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
surface.blit(self.flashing_coin.image, self.flashing_coin.rect)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_time_out_screen_info(self, surface):
|
||||||
|
"""Draws info when on the time out screen"""
|
||||||
|
for info in self.score_images:
|
||||||
|
surface.blit(info.image, info.rect)
|
||||||
|
|
||||||
|
for word in self.time_out_label:
|
||||||
|
for letter in word:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
for character in self.coin_count_images:
|
||||||
|
surface.blit(character.image, character.rect)
|
||||||
|
|
||||||
|
for label in self.label_list:
|
||||||
|
for letter in label:
|
||||||
|
surface.blit(letter.image, letter.rect)
|
||||||
|
|
||||||
|
surface.blit(self.flashing_coin.image, self.flashing_coin.rect)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,360 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import constants as c
|
||||||
|
from .. import setup
|
||||||
|
|
||||||
|
|
||||||
|
class Powerup(pg.sprite.Sprite):
|
||||||
|
"""Base class for all powerup_group"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Powerup, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_powerup(self, x, y, name, setup_frames):
|
||||||
|
"""This separate setup function allows me to pass a different
|
||||||
|
setup_frames method depending on what the powerup is"""
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.frames = []
|
||||||
|
self.frame_index = 0
|
||||||
|
setup_frames()
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.centerx = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.state = c.REVEAL
|
||||||
|
self.y_vel = -1
|
||||||
|
self.x_vel = 0
|
||||||
|
self.direction = c.RIGHT
|
||||||
|
self.box_height = y
|
||||||
|
self.gravity = 1
|
||||||
|
self.max_y_vel = 8
|
||||||
|
self.animate_timer = 0
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Get the image frames from the sprite sheet"""
|
||||||
|
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info, *args):
|
||||||
|
"""Updates powerup behavior"""
|
||||||
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
|
self.handle_state()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def revealing(self, *args):
|
||||||
|
"""Action when powerup leaves the coin box or brick"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
|
||||||
|
if self.rect.bottom <= self.box_height:
|
||||||
|
self.rect.bottom = self.box_height
|
||||||
|
self.y_vel = 0
|
||||||
|
self.state = c.SLIDE
|
||||||
|
|
||||||
|
|
||||||
|
def sliding(self):
|
||||||
|
"""Action for when powerup slides along the ground"""
|
||||||
|
if self.direction == c.RIGHT:
|
||||||
|
self.x_vel = 3
|
||||||
|
else:
|
||||||
|
self.x_vel = -3
|
||||||
|
|
||||||
|
|
||||||
|
def falling(self):
|
||||||
|
"""When powerups fall of a ledge"""
|
||||||
|
if self.y_vel < self.max_y_vel:
|
||||||
|
self.y_vel += self.gravity
|
||||||
|
|
||||||
|
|
||||||
|
class Mushroom(Powerup):
|
||||||
|
"""Powerup that makes Mario become bigger"""
|
||||||
|
def __init__(self, x, y, name='mushroom'):
|
||||||
|
super(Mushroom, self).__init__(x, y)
|
||||||
|
self.setup_powerup(x, y, name, self.setup_frames)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Sets up frame list"""
|
||||||
|
self.frames.append(self.get_image(0, 0, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Handles behavior based on state"""
|
||||||
|
if self.state == c.REVEAL:
|
||||||
|
self.revealing()
|
||||||
|
elif self.state == c.SLIDE:
|
||||||
|
self.sliding()
|
||||||
|
elif self.state == c.FALL:
|
||||||
|
self.falling()
|
||||||
|
|
||||||
|
|
||||||
|
class LifeMushroom(Mushroom):
|
||||||
|
"""1up mushroom"""
|
||||||
|
def __init__(self, x, y, name='1up_mushroom'):
|
||||||
|
super(LifeMushroom, self).__init__(x, y)
|
||||||
|
self.setup_powerup(x, y, name, self.setup_frames)
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
self.frames.append(self.get_image(16, 0, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
class FireFlower(Powerup):
|
||||||
|
"""Powerup that allows Mario to throw fire balls"""
|
||||||
|
def __init__(self, x, y, name=c.FIREFLOWER):
|
||||||
|
super(FireFlower, self).__init__(x, y)
|
||||||
|
self.setup_powerup(x, y, name, self.setup_frames)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Sets up frame list"""
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(0, 32, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(16, 32, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(32, 32, 16, 16))
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(48, 32, 16, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Handle behavior based on state"""
|
||||||
|
if self.state == c.REVEAL:
|
||||||
|
self.revealing()
|
||||||
|
elif self.state == c.RESTING:
|
||||||
|
self.resting()
|
||||||
|
|
||||||
|
|
||||||
|
def revealing(self):
|
||||||
|
"""Animation of flower coming out of box"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
|
||||||
|
if self.rect.bottom <= self.box_height:
|
||||||
|
self.rect.bottom = self.box_height
|
||||||
|
self.state = c.RESTING
|
||||||
|
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
|
||||||
|
def resting(self):
|
||||||
|
"""Fire Flower staying still on opened box"""
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
|
||||||
|
def animation(self):
|
||||||
|
"""Method to make the Fire Flower blink"""
|
||||||
|
if (self.current_time - self.animate_timer) > 30:
|
||||||
|
if self.frame_index < 3:
|
||||||
|
self.frame_index += 1
|
||||||
|
else:
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.animate_timer = self.current_time
|
||||||
|
|
||||||
|
|
||||||
|
class Star(Powerup):
|
||||||
|
"""A powerup that gives mario invincibility"""
|
||||||
|
def __init__(self, x, y, name='star'):
|
||||||
|
super(Star, self).__init__(x, y)
|
||||||
|
self.setup_powerup(x, y, name, self.setup_frames)
|
||||||
|
self.animate_timer = 0
|
||||||
|
self.rect.y += 1 #looks more centered offset one pixel
|
||||||
|
self.gravity = .4
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Creating the self.frames list where the images for the animation
|
||||||
|
are stored"""
|
||||||
|
self.frames.append(self.get_image(1, 48, 15, 16))
|
||||||
|
self.frames.append(self.get_image(17, 48, 15, 16))
|
||||||
|
self.frames.append(self.get_image(33, 48, 15, 16))
|
||||||
|
self.frames.append(self.get_image(49, 48, 15, 16))
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Handles behavior based on state"""
|
||||||
|
if self.state == c.REVEAL:
|
||||||
|
self.revealing()
|
||||||
|
elif self.state == c.BOUNCE:
|
||||||
|
self.bouncing()
|
||||||
|
|
||||||
|
|
||||||
|
def revealing(self):
|
||||||
|
"""When the star comes out of the box"""
|
||||||
|
self.rect.y += self.y_vel
|
||||||
|
|
||||||
|
if self.rect.bottom <= self.box_height:
|
||||||
|
self.rect.bottom = self.box_height
|
||||||
|
self.start_bounce(-2)
|
||||||
|
self.state = c.BOUNCE
|
||||||
|
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
|
||||||
|
def animation(self):
|
||||||
|
"""sets image for animation"""
|
||||||
|
if (self.current_time - self.animate_timer) > 30:
|
||||||
|
if self.frame_index < 3:
|
||||||
|
self.frame_index += 1
|
||||||
|
else:
|
||||||
|
self.frame_index = 0
|
||||||
|
self.animate_timer = self.current_time
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
|
||||||
|
def start_bounce(self, vel):
|
||||||
|
"""Transitions into bouncing state"""
|
||||||
|
self.y_vel = vel
|
||||||
|
|
||||||
|
|
||||||
|
def bouncing(self):
|
||||||
|
"""Action when the star is bouncing around"""
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
if self.direction == c.LEFT:
|
||||||
|
self.x_vel = -5
|
||||||
|
else:
|
||||||
|
self.x_vel = 5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FireBall(pg.sprite.Sprite):
|
||||||
|
"""Shot from Fire Mario"""
|
||||||
|
def __init__(self, x, y, facing_right, name=c.FIREBALL):
|
||||||
|
super(FireBall, self).__init__()
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.setup_frames()
|
||||||
|
if facing_right:
|
||||||
|
self.direction = c.RIGHT
|
||||||
|
self.x_vel = 12
|
||||||
|
else:
|
||||||
|
self.direction = c.LEFT
|
||||||
|
self.x_vel = -12
|
||||||
|
self.y_vel = 10
|
||||||
|
self.gravity = .9
|
||||||
|
self.frame_index = 0
|
||||||
|
self.animation_timer = 0
|
||||||
|
self.state = c.FLYING
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.right = x
|
||||||
|
self.rect.y = y
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
def setup_frames(self):
|
||||||
|
"""Sets up animation frames"""
|
||||||
|
self.frames = []
|
||||||
|
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(96, 144, 8, 8)) #Frame 1 of flying
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(104, 144, 8, 8)) #Frame 2 of Flying
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(96, 152, 8, 8)) #Frame 3 of Flying
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(104, 152, 8, 8)) #Frame 4 of flying
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(112, 144, 16, 16)) #frame 1 of exploding
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(112, 160, 16, 16)) #frame 2 of exploding
|
||||||
|
self.frames.append(
|
||||||
|
self.get_image(112, 176, 16, 16)) #frame 3 of exploding
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Get the image frames from the sprite sheet"""
|
||||||
|
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info, viewport):
|
||||||
|
"""Updates fireball behavior"""
|
||||||
|
self.current_time = game_info[c.CURRENT_TIME]
|
||||||
|
self.handle_state()
|
||||||
|
self.check_if_off_screen(viewport)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Handles behavior based on state"""
|
||||||
|
if self.state == c.FLYING:
|
||||||
|
self.animation()
|
||||||
|
elif self.state == c.BOUNCING:
|
||||||
|
self.animation()
|
||||||
|
elif self.state == c.EXPLODING:
|
||||||
|
self.animation()
|
||||||
|
|
||||||
|
|
||||||
|
def animation(self):
|
||||||
|
"""adjusts frame for animation"""
|
||||||
|
if self.state == c.FLYING or self.state == c.BOUNCING:
|
||||||
|
if (self.current_time - self.animation_timer) > 200:
|
||||||
|
if self.frame_index < 3:
|
||||||
|
self.frame_index += 1
|
||||||
|
else:
|
||||||
|
self.frame_index = 0
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
|
||||||
|
|
||||||
|
elif self.state == c.EXPLODING:
|
||||||
|
if (self.current_time - self.animation_timer) > 50:
|
||||||
|
if self.frame_index < 6:
|
||||||
|
self.frame_index += 1
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.animation_timer = self.current_time
|
||||||
|
else:
|
||||||
|
self.kill()
|
||||||
|
|
||||||
|
|
||||||
|
def explode_transition(self):
|
||||||
|
"""Transitions fireball to EXPLODING state"""
|
||||||
|
self.frame_index = 4
|
||||||
|
centerx = self.rect.centerx
|
||||||
|
self.image = self.frames[self.frame_index]
|
||||||
|
self.rect.centerx = centerx
|
||||||
|
self.state = c.EXPLODING
|
||||||
|
|
||||||
|
|
||||||
|
def check_if_off_screen(self, viewport):
|
||||||
|
"""Removes from sprite group if off screen"""
|
||||||
|
if (self.rect.x > viewport.right) or (self.rect.y > viewport.bottom) \
|
||||||
|
or (self.rect.right < viewport.x):
|
||||||
|
self.kill()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup
|
||||||
|
from .. import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
class Digit(pg.sprite.Sprite):
|
||||||
|
"""Individual digit for score"""
|
||||||
|
def __init__(self, image):
|
||||||
|
super(Digit, self).__init__()
|
||||||
|
self.image = image
|
||||||
|
self.rect = image.get_rect()
|
||||||
|
|
||||||
|
|
||||||
|
class Score(object):
|
||||||
|
"""Scores that appear, float up, and disappear"""
|
||||||
|
def __init__(self, x, y, score, flag_pole=False):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
if flag_pole:
|
||||||
|
self.y_vel = -4
|
||||||
|
else:
|
||||||
|
self.y_vel = -3
|
||||||
|
self.sprite_sheet = setup.GFX['item_objects']
|
||||||
|
self.create_image_dict()
|
||||||
|
self.score_string = str(score)
|
||||||
|
self.create_digit_list()
|
||||||
|
self.flag_pole_score = flag_pole
|
||||||
|
|
||||||
|
|
||||||
|
def create_image_dict(self):
|
||||||
|
"""Creates the dictionary for all the number images needed"""
|
||||||
|
self.image_dict = {}
|
||||||
|
|
||||||
|
image0 = self.get_image(1, 168, 3, 8)
|
||||||
|
image1 = self.get_image(5, 168, 3, 8)
|
||||||
|
image2 = self.get_image(8, 168, 4, 8)
|
||||||
|
image4 = self.get_image(12, 168, 4, 8)
|
||||||
|
image5 = self.get_image(16, 168, 5, 8)
|
||||||
|
image8 = self.get_image(20, 168, 4, 8)
|
||||||
|
image9 = self.get_image(32, 168, 5, 8)
|
||||||
|
image10 = self.get_image(37, 168, 6, 8)
|
||||||
|
image11 = self.get_image(43, 168, 5, 8)
|
||||||
|
|
||||||
|
self.image_dict['0'] = image0
|
||||||
|
self.image_dict['1'] = image1
|
||||||
|
self.image_dict['2'] = image2
|
||||||
|
self.image_dict['4'] = image4
|
||||||
|
self.image_dict['5'] = image5
|
||||||
|
self.image_dict['8'] = image8
|
||||||
|
self.image_dict['3'] = image9
|
||||||
|
self.image_dict['7'] = image10
|
||||||
|
self.image_dict['9'] = image11
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height):
|
||||||
|
"""Extracts image from sprite sheet"""
|
||||||
|
image = pg.Surface([width, height]).convert()
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.BRICK_SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.BRICK_SIZE_MULTIPLIER)))
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def create_digit_list(self):
|
||||||
|
"""Creates the group of images based on score received"""
|
||||||
|
self.digit_list = []
|
||||||
|
self.digit_group = pg.sprite.Group()
|
||||||
|
|
||||||
|
for digit in self.score_string:
|
||||||
|
self.digit_list.append(Digit(self.image_dict[digit]))
|
||||||
|
|
||||||
|
self.set_rects_for_images()
|
||||||
|
|
||||||
|
|
||||||
|
def set_rects_for_images(self):
|
||||||
|
"""Set the rect attributes for each image in self.image_list"""
|
||||||
|
for i, digit in enumerate(self.digit_list):
|
||||||
|
digit.rect = digit.image.get_rect()
|
||||||
|
digit.rect.x = self.x + (i * 10)
|
||||||
|
digit.rect.y = self.y
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, score_list, level_info):
|
||||||
|
"""Updates score movement"""
|
||||||
|
for number in self.digit_list:
|
||||||
|
number.rect.y += self.y_vel
|
||||||
|
|
||||||
|
if score_list:
|
||||||
|
self.check_to_delete_floating_scores(score_list, level_info)
|
||||||
|
|
||||||
|
if self.flag_pole_score:
|
||||||
|
if self.digit_list[0].rect.y <= 120:
|
||||||
|
self.y_vel = 0
|
||||||
|
|
||||||
|
|
||||||
|
def draw(self, screen):
|
||||||
|
"""Draws score numbers onto screen"""
|
||||||
|
for digit in self.digit_list:
|
||||||
|
screen.blit(digit.image, digit.rect)
|
||||||
|
|
||||||
|
|
||||||
|
def check_to_delete_floating_scores(self, score_list, level_info):
|
||||||
|
"""Check if scores need to be deleted"""
|
||||||
|
for i, score in enumerate(score_list):
|
||||||
|
if int(score.score_string) == 1000:
|
||||||
|
if (score.y - score.digit_list[0].rect.y) > 130:
|
||||||
|
score_list.pop(i)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if (score.y - score.digit_list[0].rect.y) > 75:
|
||||||
|
score_list.pop(i)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
|||||||
|
|
||||||
|
|
||||||
|
SCREEN_HEIGHT = 600
|
||||||
|
SCREEN_WIDTH = 800
|
||||||
|
|
||||||
|
SCREEN_SIZE = (SCREEN_WIDTH,SCREEN_HEIGHT)
|
||||||
|
|
||||||
|
ORIGINAL_CAPTION = "Super Mario Bros 1-1"
|
||||||
|
|
||||||
|
## COLORS ##
|
||||||
|
|
||||||
|
# R G B
|
||||||
|
GRAY = (100, 100, 100)
|
||||||
|
NAVYBLUE = ( 60, 60, 100)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
RED = (255, 0, 0)
|
||||||
|
GREEN = ( 0, 255, 0)
|
||||||
|
FOREST_GREEN = ( 31, 162, 35)
|
||||||
|
BLUE = ( 0, 0, 255)
|
||||||
|
SKY_BLUE = ( 39, 145, 251)
|
||||||
|
YELLOW = (255, 255, 0)
|
||||||
|
ORANGE = (255, 128, 0)
|
||||||
|
PURPLE = (255, 0, 255)
|
||||||
|
CYAN = ( 0, 255, 255)
|
||||||
|
BLACK = ( 0, 0, 0)
|
||||||
|
NEAR_BLACK = ( 19, 15, 48)
|
||||||
|
COMBLUE = (233, 232, 255)
|
||||||
|
GOLD = (255, 215, 0)
|
||||||
|
|
||||||
|
BGCOLOR = WHITE
|
||||||
|
|
||||||
|
SIZE_MULTIPLIER = 2.5
|
||||||
|
BRICK_SIZE_MULTIPLIER = 2.69
|
||||||
|
BACKGROUND_MULTIPLER = 2.679
|
||||||
|
GROUND_HEIGHT = SCREEN_HEIGHT - 62
|
||||||
|
|
||||||
|
#MARIO FORCES
|
||||||
|
WALK_ACCEL = .15
|
||||||
|
RUN_ACCEL = 20
|
||||||
|
SMALL_TURNAROUND = .35
|
||||||
|
|
||||||
|
GRAVITY = 1.01
|
||||||
|
JUMP_GRAVITY = .31
|
||||||
|
JUMP_VEL = -10
|
||||||
|
FAST_JUMP_VEL = -12.5
|
||||||
|
MAX_Y_VEL = 11
|
||||||
|
|
||||||
|
MAX_RUN_SPEED = 800
|
||||||
|
MAX_WALK_SPEED = 6
|
||||||
|
|
||||||
|
|
||||||
|
#Mario States
|
||||||
|
|
||||||
|
STAND = 'standing'
|
||||||
|
WALK = 'walk'
|
||||||
|
JUMP = 'jump'
|
||||||
|
FALL = 'fall'
|
||||||
|
SMALL_TO_BIG = 'small to big'
|
||||||
|
BIG_TO_FIRE = 'big to fire'
|
||||||
|
BIG_TO_SMALL = 'big to small'
|
||||||
|
FLAGPOLE = 'flag pole'
|
||||||
|
WALKING_TO_CASTLE = 'walking to castle'
|
||||||
|
END_OF_LEVEL_FALL = 'end of level fall'
|
||||||
|
|
||||||
|
|
||||||
|
#GOOMBA Stuff
|
||||||
|
|
||||||
|
LEFT = 'left'
|
||||||
|
RIGHT = 'right'
|
||||||
|
JUMPED_ON = 'jumped on'
|
||||||
|
DEATH_JUMP = 'death jump'
|
||||||
|
|
||||||
|
#KOOPA STUFF
|
||||||
|
|
||||||
|
SHELL_SLIDE = 'shell slide'
|
||||||
|
|
||||||
|
#BRICK STATES
|
||||||
|
|
||||||
|
RESTING = 'resting'
|
||||||
|
BUMPED = 'bumped'
|
||||||
|
|
||||||
|
#COIN STATES
|
||||||
|
OPENED = 'opened'
|
||||||
|
|
||||||
|
#MUSHROOM STATES
|
||||||
|
|
||||||
|
REVEAL = 'reveal'
|
||||||
|
SLIDE = 'slide'
|
||||||
|
|
||||||
|
#COIN STATES
|
||||||
|
|
||||||
|
SPIN = 'spin'
|
||||||
|
|
||||||
|
#STAR STATES
|
||||||
|
|
||||||
|
BOUNCE = 'bounce'
|
||||||
|
|
||||||
|
#FIRE STATES
|
||||||
|
|
||||||
|
FLYING = 'flying'
|
||||||
|
BOUNCING = 'bouncing'
|
||||||
|
EXPLODING = 'exploding'
|
||||||
|
|
||||||
|
#Brick and coin box contents
|
||||||
|
|
||||||
|
MUSHROOM = 'mushroom'
|
||||||
|
STAR = 'star'
|
||||||
|
FIREFLOWER = 'fireflower'
|
||||||
|
SIXCOINS = '6coins'
|
||||||
|
COIN = 'coin'
|
||||||
|
LIFE_MUSHROOM = '1up_mushroom'
|
||||||
|
|
||||||
|
FIREBALL = 'fireball'
|
||||||
|
|
||||||
|
#LIST of ENEMIES
|
||||||
|
|
||||||
|
GOOMBA = 'goomba'
|
||||||
|
KOOPA = 'koopa'
|
||||||
|
|
||||||
|
#LEVEL STATES
|
||||||
|
|
||||||
|
FROZEN = 'frozen'
|
||||||
|
NOT_FROZEN = 'not frozen'
|
||||||
|
IN_CASTLE = 'in castle'
|
||||||
|
FLAG_AND_FIREWORKS = 'flag and fireworks'
|
||||||
|
|
||||||
|
#FLAG STATE
|
||||||
|
TOP_OF_POLE = 'top of pole'
|
||||||
|
SLIDE_DOWN = 'slide down'
|
||||||
|
BOTTOM_OF_POLE = 'bottom of pole'
|
||||||
|
|
||||||
|
#1UP score
|
||||||
|
ONEUP = '379'
|
||||||
|
|
||||||
|
#MAIN MENU CURSOR STATES
|
||||||
|
PLAYER1 = '1 player'
|
||||||
|
PLAYER2 = '2 player'
|
||||||
|
|
||||||
|
#OVERHEAD INFO STATES
|
||||||
|
MAIN_MENU = 'main menu'
|
||||||
|
LOAD_SCREEN = 'loading screen'
|
||||||
|
LEVEL = 'level'
|
||||||
|
GAME_OVER = 'game over'
|
||||||
|
FAST_COUNT_DOWN = 'fast count down'
|
||||||
|
END_OF_LEVEL = 'end of level'
|
||||||
|
|
||||||
|
|
||||||
|
#GAME INFO DICTIONARY KEYS
|
||||||
|
COIN_TOTAL = 'coin total'
|
||||||
|
SCORE = 'score'
|
||||||
|
TOP_SCORE = 'top score'
|
||||||
|
LIVES = 'lives'
|
||||||
|
CURRENT_TIME = 'current time'
|
||||||
|
LEVEL_STATE = 'level state'
|
||||||
|
CAMERA_START_X = 'camera start x'
|
||||||
|
MARIO_DEAD = 'mario dead'
|
||||||
|
|
||||||
|
#STATES FOR ENTIRE GAME
|
||||||
|
MAIN_MENU = 'main menu'
|
||||||
|
LOAD_SCREEN = 'load screen'
|
||||||
|
TIME_OUT = 'time out'
|
||||||
|
GAME_OVER = 'game over'
|
||||||
|
LEVEL1 = 'level1'
|
||||||
|
|
||||||
|
#SOUND STATEZ
|
||||||
|
NORMAL = 'normal'
|
||||||
|
STAGE_CLEAR = 'stage clear'
|
||||||
|
WORLD_CLEAR = 'world clear'
|
||||||
|
TIME_WARNING = 'time warning'
|
||||||
|
SPED_UP_NORMAL = 'sped up normal'
|
||||||
|
MARIO_INVINCIBLE = 'mario invincible'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from . import setup
|
||||||
|
from . import constants as c
|
||||||
|
|
||||||
|
class Sound(object):
|
||||||
|
"""Handles all sound for the game"""
|
||||||
|
def __init__(self, overhead_info):
|
||||||
|
"""Initialize the class"""
|
||||||
|
self.sfx_dict = setup.SFX
|
||||||
|
self.music_dict = setup.MUSIC
|
||||||
|
self.overhead_info = overhead_info
|
||||||
|
self.game_info = overhead_info.game_info
|
||||||
|
self.set_music_mixer()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def set_music_mixer(self):
|
||||||
|
"""Sets music for level"""
|
||||||
|
if self.overhead_info.state == c.LEVEL:
|
||||||
|
pg.mixer.music.load(self.music_dict['main_theme'])
|
||||||
|
pg.mixer.music.play()
|
||||||
|
self.state = c.NORMAL
|
||||||
|
elif self.overhead_info.state == c.GAME_OVER:
|
||||||
|
pg.mixer.music.load(self.music_dict['game_over'])
|
||||||
|
pg.mixer.music.play()
|
||||||
|
self.state = c.GAME_OVER
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, game_info, mario):
|
||||||
|
"""Updates sound object with game info"""
|
||||||
|
self.game_info = game_info
|
||||||
|
self.mario = mario
|
||||||
|
self.handle_state()
|
||||||
|
|
||||||
|
def handle_state(self):
|
||||||
|
"""Handles the state of the soundn object"""
|
||||||
|
if self.state == c.NORMAL:
|
||||||
|
if self.mario.dead:
|
||||||
|
self.play_music('death', c.MARIO_DEAD)
|
||||||
|
elif self.mario.invincible \
|
||||||
|
and self.mario.losing_invincibility == False:
|
||||||
|
self.play_music('invincible', c.MARIO_INVINCIBLE)
|
||||||
|
elif self.mario.state == c.FLAGPOLE:
|
||||||
|
self.play_music('flagpole', c.FLAGPOLE)
|
||||||
|
elif self.overhead_info.time == 100:
|
||||||
|
self.play_music('out_of_time', c.TIME_WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
elif self.state == c.FLAGPOLE:
|
||||||
|
if self.mario.state == c.WALKING_TO_CASTLE:
|
||||||
|
self.play_music('stage_clear', c.STAGE_CLEAR)
|
||||||
|
|
||||||
|
elif self.state == c.STAGE_CLEAR:
|
||||||
|
if self.mario.in_castle:
|
||||||
|
self.sfx_dict['count_down'].play()
|
||||||
|
self.state = c.FAST_COUNT_DOWN
|
||||||
|
|
||||||
|
elif self.state == c.FAST_COUNT_DOWN:
|
||||||
|
if self.overhead_info.time == 0:
|
||||||
|
self.sfx_dict['count_down'].stop()
|
||||||
|
self.state = c.WORLD_CLEAR
|
||||||
|
|
||||||
|
elif self.state == c. TIME_WARNING:
|
||||||
|
if pg.mixer.music.get_busy() == 0:
|
||||||
|
self.play_music('main_theme_sped_up', c.SPED_UP_NORMAL)
|
||||||
|
elif self.mario.dead:
|
||||||
|
self.play_music('death', c.MARIO_DEAD)
|
||||||
|
|
||||||
|
elif self.state == c.SPED_UP_NORMAL:
|
||||||
|
if self.mario.dead:
|
||||||
|
self.play_music('death', c.MARIO_DEAD)
|
||||||
|
elif self.mario.state == c.FLAGPOLE:
|
||||||
|
self.play_music('flagpole', c.FLAGPOLE)
|
||||||
|
|
||||||
|
elif self.state == c.MARIO_INVINCIBLE:
|
||||||
|
if (self.mario.current_time - self.mario.invincible_start_timer) > 11000:
|
||||||
|
self.play_music('main_theme', c.NORMAL)
|
||||||
|
elif self.mario.dead:
|
||||||
|
self.play_music('death', c.MARIO_DEAD)
|
||||||
|
|
||||||
|
|
||||||
|
elif self.state == c.WORLD_CLEAR:
|
||||||
|
pass
|
||||||
|
elif self.state == c.MARIO_DEAD:
|
||||||
|
pass
|
||||||
|
elif self.state == c.GAME_OVER:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def play_music(self, key, state):
|
||||||
|
"""Plays new music"""
|
||||||
|
pg.mixer.music.load(self.music_dict[key])
|
||||||
|
pg.mixer.music.play()
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
def stop_music(self):
|
||||||
|
"""Stops playback"""
|
||||||
|
pg.mixer.music.stop()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
from . import setup,tools
|
||||||
|
from .states import main_menu,load_screen,level1
|
||||||
|
from . import constants as c
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Add states to control here."""
|
||||||
|
run_it = tools.Control(setup.ORIGINAL_CAPTION)
|
||||||
|
state_dict = {c.MAIN_MENU: main_menu.Menu(),
|
||||||
|
c.LOAD_SCREEN: load_screen.LoadScreen(),
|
||||||
|
c.TIME_OUT: load_screen.TimeOut(),
|
||||||
|
c.GAME_OVER: load_screen.GameOver(),
|
||||||
|
c.LEVEL1: level1.Level1()}
|
||||||
|
|
||||||
|
run_it.setup_states(state_dict, c.MAIN_MENU)
|
||||||
|
run_it.main()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
"""
|
||||||
|
This module initializes the display and creates dictionaries of resources.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pygame as pg
|
||||||
|
from . import tools
|
||||||
|
from .import constants as c
|
||||||
|
|
||||||
|
ORIGINAL_CAPTION = c.ORIGINAL_CAPTION
|
||||||
|
|
||||||
|
|
||||||
|
os.environ['SDL_VIDEO_CENTERED'] = '1'
|
||||||
|
pg.init()
|
||||||
|
pg.event.set_allowed([pg.KEYDOWN, pg.KEYUP, pg.QUIT])
|
||||||
|
pg.display.set_caption(c.ORIGINAL_CAPTION)
|
||||||
|
SCREEN = pg.display.set_mode(c.SCREEN_SIZE)
|
||||||
|
SCREEN_RECT = SCREEN.get_rect()
|
||||||
|
|
||||||
|
|
||||||
|
FONTS = tools.load_all_fonts(os.path.join("resources","fonts"))
|
||||||
|
MUSIC = tools.load_all_music(os.path.join("resources","music"))
|
||||||
|
GFX = tools.load_all_gfx(os.path.join("resources","graphics"))
|
||||||
|
SFX = tools.load_all_sfx(os.path.join("resources","sound"))
|
||||||
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
from .. import setup, tools
|
||||||
|
from .. import constants as c
|
||||||
|
from .. import game_sound
|
||||||
|
from ..components import info
|
||||||
|
|
||||||
|
class LoadScreen(tools._State):
|
||||||
|
def __init__(self):
|
||||||
|
tools._State.__init__(self)
|
||||||
|
|
||||||
|
def startup(self, current_time, persist):
|
||||||
|
self.start_time = current_time
|
||||||
|
self.persist = persist
|
||||||
|
self.game_info = self.persist
|
||||||
|
self.next = self.set_next_state()
|
||||||
|
|
||||||
|
info_state = self.set_overhead_info_state()
|
||||||
|
|
||||||
|
self.overhead_info = info.OverheadInfo(self.game_info, info_state)
|
||||||
|
self.sound_manager = game_sound.Sound(self.overhead_info)
|
||||||
|
|
||||||
|
|
||||||
|
def set_next_state(self):
|
||||||
|
"""Sets the next state"""
|
||||||
|
return c.LEVEL1
|
||||||
|
|
||||||
|
def set_overhead_info_state(self):
|
||||||
|
"""sets the state to send to the overhead info object"""
|
||||||
|
return c.LOAD_SCREEN
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, surface, keys, current_time):
|
||||||
|
"""Updates the loading screen"""
|
||||||
|
if (current_time - self.start_time) < 2400:
|
||||||
|
surface.fill(c.BLACK)
|
||||||
|
self.overhead_info.update(self.game_info)
|
||||||
|
self.overhead_info.draw(surface)
|
||||||
|
|
||||||
|
elif (current_time - self.start_time) < 2600:
|
||||||
|
surface.fill(c.BLACK)
|
||||||
|
|
||||||
|
elif (current_time - self.start_time) < 2635:
|
||||||
|
surface.fill((106, 150, 252))
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.done = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GameOver(LoadScreen):
|
||||||
|
"""A loading screen with Game Over"""
|
||||||
|
def __init__(self):
|
||||||
|
super(GameOver, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def set_next_state(self):
|
||||||
|
"""Sets next state"""
|
||||||
|
return c.MAIN_MENU
|
||||||
|
|
||||||
|
def set_overhead_info_state(self):
|
||||||
|
"""sets the state to send to the overhead info object"""
|
||||||
|
return c.GAME_OVER
|
||||||
|
|
||||||
|
def update(self, surface, keys, current_time):
|
||||||
|
self.current_time = current_time
|
||||||
|
self.sound_manager.update(self.persist, None)
|
||||||
|
|
||||||
|
if (self.current_time - self.start_time) < 7000:
|
||||||
|
surface.fill(c.BLACK)
|
||||||
|
self.overhead_info.update(self.game_info)
|
||||||
|
self.overhead_info.draw(surface)
|
||||||
|
elif (self.current_time - self.start_time) < 7200:
|
||||||
|
surface.fill(c.BLACK)
|
||||||
|
elif (self.current_time - self.start_time) < 7235:
|
||||||
|
surface.fill((106, 150, 252))
|
||||||
|
else:
|
||||||
|
self.done = True
|
||||||
|
|
||||||
|
|
||||||
|
class TimeOut(LoadScreen):
|
||||||
|
"""Loading Screen with Time Out"""
|
||||||
|
def __init__(self):
|
||||||
|
super(TimeOut, self).__init__()
|
||||||
|
|
||||||
|
def set_next_state(self):
|
||||||
|
"""Sets next state"""
|
||||||
|
if self.persist[c.LIVES] == 0:
|
||||||
|
return c.GAME_OVER
|
||||||
|
else:
|
||||||
|
return c.LOAD_SCREEN
|
||||||
|
|
||||||
|
def set_overhead_info_state(self):
|
||||||
|
"""Sets the state to send to the overhead info object"""
|
||||||
|
return c.TIME_OUT
|
||||||
|
|
||||||
|
def update(self, surface, keys, current_time):
|
||||||
|
self.current_time = current_time
|
||||||
|
|
||||||
|
if (self.current_time - self.start_time) < 2400:
|
||||||
|
surface.fill(c.BLACK)
|
||||||
|
self.overhead_info.update(self.game_info)
|
||||||
|
self.overhead_info.draw(surface)
|
||||||
|
else:
|
||||||
|
self.done = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
import pygame as pg
|
||||||
|
from .. import setup, tools
|
||||||
|
from .. import constants as c
|
||||||
|
from .. components import info, mario
|
||||||
|
class Menu(tools._State):
|
||||||
|
def __init__(self):
|
||||||
|
"""Initializes the state"""
|
||||||
|
tools._State.__init__(self)
|
||||||
|
persist = {c.COIN_TOTAL: 0,
|
||||||
|
c.SCORE: 0,
|
||||||
|
c.LIVES: 3,
|
||||||
|
c.TOP_SCORE: 0,
|
||||||
|
c.CURRENT_TIME: 0.0,
|
||||||
|
c.LEVEL_STATE: None,
|
||||||
|
c.CAMERA_START_X: 0,
|
||||||
|
c.MARIO_DEAD: False}
|
||||||
|
self.startup(0.0, persist)
|
||||||
|
|
||||||
|
def startup(self, current_time, persist):
|
||||||
|
"""Called every time the game's state becomes this one. Initializes
|
||||||
|
certain values"""
|
||||||
|
self.next = c.LOAD_SCREEN
|
||||||
|
self.persist = persist
|
||||||
|
self.game_info = persist
|
||||||
|
self.overhead_info = info.OverheadInfo(self.game_info, c.MAIN_MENU)
|
||||||
|
|
||||||
|
self.sprite_sheet = setup.GFX['title_screen']
|
||||||
|
self.setup_background()
|
||||||
|
self.setup_mario()
|
||||||
|
self.setup_cursor()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_cursor(self):
|
||||||
|
"""Creates the mushroom cursor to select 1 or 2 player game"""
|
||||||
|
self.cursor = pg.sprite.Sprite()
|
||||||
|
dest = (220, 358)
|
||||||
|
self.cursor.image, self.cursor.rect = self.get_image(
|
||||||
|
24, 160, 8, 8, dest, setup.GFX['item_objects'])
|
||||||
|
self.cursor.state = c.PLAYER1
|
||||||
|
|
||||||
|
|
||||||
|
def setup_mario(self):
|
||||||
|
"""Places Mario at the beginning of the level"""
|
||||||
|
self.mario = mario.Mario()
|
||||||
|
self.mario.rect.x = 110
|
||||||
|
self.mario.rect.bottom = c.GROUND_HEIGHT
|
||||||
|
|
||||||
|
|
||||||
|
def setup_background(self):
|
||||||
|
"""Setup the background image to blit"""
|
||||||
|
self.background = setup.GFX['level_1']
|
||||||
|
self.background_rect = self.background.get_rect()
|
||||||
|
self.background = pg.transform.scale(self.background,
|
||||||
|
(int(self.background_rect.width*c.BACKGROUND_MULTIPLER),
|
||||||
|
int(self.background_rect.height*c.BACKGROUND_MULTIPLER)))
|
||||||
|
self.viewport = setup.SCREEN.get_rect(bottom=setup.SCREEN_RECT.bottom)
|
||||||
|
|
||||||
|
self.image_dict = {}
|
||||||
|
self.image_dict['GAME_NAME_BOX'] = self.get_image(
|
||||||
|
1, 60, 176, 88, (170, 100), setup.GFX['title_screen'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(self, x, y, width, height, dest, sprite_sheet):
|
||||||
|
"""Returns images and rects to blit onto the screen"""
|
||||||
|
image = pg.Surface([width, height])
|
||||||
|
rect = image.get_rect()
|
||||||
|
|
||||||
|
image.blit(sprite_sheet, (0, 0), (x, y, width, height))
|
||||||
|
if sprite_sheet == setup.GFX['title_screen']:
|
||||||
|
image.set_colorkey((255, 0, 220))
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*c.SIZE_MULTIPLIER),
|
||||||
|
int(rect.height*c.SIZE_MULTIPLIER)))
|
||||||
|
else:
|
||||||
|
image.set_colorkey(c.BLACK)
|
||||||
|
image = pg.transform.scale(image,
|
||||||
|
(int(rect.width*3),
|
||||||
|
int(rect.height*3)))
|
||||||
|
|
||||||
|
rect = image.get_rect()
|
||||||
|
rect.x = dest[0]
|
||||||
|
rect.y = dest[1]
|
||||||
|
return (image, rect)
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, surface, keys, current_time):
|
||||||
|
"""Updates the state every refresh"""
|
||||||
|
self.current_time = current_time
|
||||||
|
self.game_info[c.CURRENT_TIME] = self.current_time
|
||||||
|
self.update_cursor(keys)
|
||||||
|
self.overhead_info.update(self.game_info)
|
||||||
|
|
||||||
|
surface.blit(self.background, self.viewport, self.viewport)
|
||||||
|
surface.blit(self.image_dict['GAME_NAME_BOX'][0],
|
||||||
|
self.image_dict['GAME_NAME_BOX'][1])
|
||||||
|
surface.blit(self.mario.image, self.mario.rect)
|
||||||
|
surface.blit(self.cursor.image, self.cursor.rect)
|
||||||
|
self.overhead_info.draw(surface)
|
||||||
|
|
||||||
|
|
||||||
|
def update_cursor(self, keys):
|
||||||
|
"""Update the position of the cursor"""
|
||||||
|
input_list = [pg.K_RETURN, pg.K_a, pg.K_s]
|
||||||
|
|
||||||
|
if self.cursor.state == c.PLAYER1:
|
||||||
|
self.cursor.rect.y = 358
|
||||||
|
if keys[pg.K_DOWN]:
|
||||||
|
self.cursor.state = c.PLAYER2
|
||||||
|
for input in input_list:
|
||||||
|
if keys[input]:
|
||||||
|
self.reset_game_info()
|
||||||
|
self.done = True
|
||||||
|
elif self.cursor.state == c.PLAYER2:
|
||||||
|
self.cursor.rect.y = 403
|
||||||
|
if keys[pg.K_UP]:
|
||||||
|
self.cursor.state = c.PLAYER1
|
||||||
|
|
||||||
|
|
||||||
|
def reset_game_info(self):
|
||||||
|
"""Resets the game info in case of a Game Over and restart"""
|
||||||
|
self.game_info[c.COIN_TOTAL] = 0
|
||||||
|
self.game_info[c.SCORE] = 0
|
||||||
|
self.game_info[c.LIVES] = 3
|
||||||
|
self.game_info[c.CURRENT_TIME] = 0.0
|
||||||
|
self.game_info[c.LEVEL_STATE] = None
|
||||||
|
|
||||||
|
self.persist = self.game_info
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pygame as pg
|
||||||
|
|
||||||
|
keybinding = {
|
||||||
|
'action':pg.K_s,
|
||||||
|
'jump':pg.K_a,
|
||||||
|
'left':pg.K_LEFT,
|
||||||
|
'right':pg.K_RIGHT,
|
||||||
|
'down':pg.K_DOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
class Control(object):
|
||||||
|
"""Control class for entire project. Contains the game loop, and contains
|
||||||
|
the event_loop which passes events to States as needed. Logic for flipping
|
||||||
|
states is also found here."""
|
||||||
|
def __init__(self, caption):
|
||||||
|
self.screen = pg.display.get_surface()
|
||||||
|
self.done = False
|
||||||
|
self.clock = pg.time.Clock()
|
||||||
|
self.caption = caption
|
||||||
|
self.fps = 60
|
||||||
|
self.show_fps = False
|
||||||
|
self.current_time = 0.0
|
||||||
|
self.keys = pg.key.get_pressed()
|
||||||
|
self.state_dict = {}
|
||||||
|
self.state_name = None
|
||||||
|
self.state = None
|
||||||
|
|
||||||
|
def setup_states(self, state_dict, start_state):
|
||||||
|
self.state_dict = state_dict
|
||||||
|
self.state_name = start_state
|
||||||
|
self.state = self.state_dict[self.state_name]
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.current_time = pg.time.get_ticks()
|
||||||
|
if self.state.quit:
|
||||||
|
self.done = True
|
||||||
|
elif self.state.done:
|
||||||
|
self.flip_state()
|
||||||
|
self.state.update(self.screen, self.keys, self.current_time)
|
||||||
|
|
||||||
|
def flip_state(self):
|
||||||
|
previous, self.state_name = self.state_name, self.state.next
|
||||||
|
persist = self.state.cleanup()
|
||||||
|
self.state = self.state_dict[self.state_name]
|
||||||
|
self.state.startup(self.current_time, persist)
|
||||||
|
self.state.previous = previous
|
||||||
|
|
||||||
|
|
||||||
|
def event_loop(self):
|
||||||
|
for event in pg.event.get():
|
||||||
|
if event.type == pg.QUIT:
|
||||||
|
self.done = True
|
||||||
|
elif event.type == pg.KEYDOWN:
|
||||||
|
self.keys = pg.key.get_pressed()
|
||||||
|
self.toggle_show_fps(event.key)
|
||||||
|
elif event.type == pg.KEYUP:
|
||||||
|
self.keys = pg.key.get_pressed()
|
||||||
|
self.state.get_event(event)
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_show_fps(self, key):
|
||||||
|
if key == pg.K_F5:
|
||||||
|
self.show_fps = not self.show_fps
|
||||||
|
if not self.show_fps:
|
||||||
|
pg.display.set_caption(self.caption)
|
||||||
|
|
||||||
|
|
||||||
|
def main(self):
|
||||||
|
"""Main loop for entire program"""
|
||||||
|
while not self.done:
|
||||||
|
self.event_loop()
|
||||||
|
self.update()
|
||||||
|
pg.display.update()
|
||||||
|
self.clock.tick(self.fps)
|
||||||
|
if self.show_fps:
|
||||||
|
fps = self.clock.get_fps()
|
||||||
|
with_fps = "{} - {:.2f} FPS".format(self.caption, fps)
|
||||||
|
pg.display.set_caption(with_fps)
|
||||||
|
|
||||||
|
|
||||||
|
class _State(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.start_time = 0.0
|
||||||
|
self.current_time = 0.0
|
||||||
|
self.done = False
|
||||||
|
self.quit = False
|
||||||
|
self.next = None
|
||||||
|
self.previous = None
|
||||||
|
self.persist = {}
|
||||||
|
|
||||||
|
def get_event(self, event):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def startup(self, current_time, persistant):
|
||||||
|
self.persist = persistant
|
||||||
|
self.start_time = current_time
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.done = False
|
||||||
|
return self.persist
|
||||||
|
|
||||||
|
def update(self, surface, keys, current_time):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_all_gfx(directory, colorkey=(255,0,255), accept=('.png', 'jpg', 'bmp')):
|
||||||
|
graphics = {}
|
||||||
|
for pic in os.listdir(directory):
|
||||||
|
name, ext = os.path.splitext(pic)
|
||||||
|
if ext.lower() in accept:
|
||||||
|
img = pg.image.load(os.path.join(directory, pic))
|
||||||
|
if img.get_alpha():
|
||||||
|
img = img.convert_alpha()
|
||||||
|
else:
|
||||||
|
img = img.convert()
|
||||||
|
img.set_colorkey(colorkey)
|
||||||
|
graphics[name]=img
|
||||||
|
return graphics
|
||||||
|
|
||||||
|
|
||||||
|
def load_all_music(directory, accept=('.wav', '.mp3', '.ogg', '.mdi')):
|
||||||
|
songs = {}
|
||||||
|
for song in os.listdir(directory):
|
||||||
|
name,ext = os.path.splitext(song)
|
||||||
|
if ext.lower() in accept:
|
||||||
|
songs[name] = os.path.join(directory, song)
|
||||||
|
return songs
|
||||||
|
|
||||||
|
|
||||||
|
def load_all_fonts(directory, accept=('.ttf')):
|
||||||
|
return load_all_music(directory, accept)
|
||||||
|
|
||||||
|
|
||||||
|
def load_all_sfx(directory, accept=('.wav','.mpe','.ogg','.mdi')):
|
||||||
|
effects = {}
|
||||||
|
for fx in os.listdir(directory):
|
||||||
|
name, ext = os.path.splitext(fx)
|
||||||
|
if ext.lower() in accept:
|
||||||
|
effects[name] = pg.mixer.Sound(os.path.join(directory, fx))
|
||||||
|
return effects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
import sys
|
||||||
|
import pygame as pg
|
||||||
|
from data.main import main
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
|
pg.quit()
|
||||||
|
sys.exit()
|
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'justinarmstrong'
|
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'justinarmstrong'
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 8.9 KiB |
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'justinarmstrong'
|
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'justinarmstrong'
|
After Width: | Height: | Size: 9.2 KiB |