0% found this document useful (0 votes)
14 views48 pages

CS Pro P-1

The document outlines a project on creating a Super Mario Bros. game using Python and the PyGame library. It includes acknowledgments, project requirements, environment setup, level design, and source code for various game components. The project aims to implement game logic, interactive elements, and user interface features, culminating in a playable game experience.

Uploaded by

gnanadurga6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views48 pages

CS Pro P-1

The document outlines a project on creating a Super Mario Bros. game using Python and the PyGame library. It includes acknowledgments, project requirements, environment setup, level design, and source code for various game components. The project aims to implement game logic, interactive elements, and user interface features, culminating in a playable game experience.

Uploaded by

gnanadurga6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

SRI GURUKULAM SECONDARY SCHOOL

C O M P UT E R S C IE N C E
I N V E S T IG A T O R Y P R O J EC T

SUPER MARIO BROS. GAME PROJECT

SUBMITTED TO: SUBMITTED BY:


Mrs. PRIYADHARSHINI.L PAVITHRAN P.
HARISH M.B
KAVISH S.
ACKNOWLEDGEMENT
This project report would be inconclusive without
acknowledging the services of those helping hands in the
entire process of project presentation.
With grateful heart I acknowledge the presence of those who
were behind the endeavours concerning this project.
At the outset, I express my deep sense of obligation to Mrs.
Sarojamani R., Principal of Sri Gurukulam Secondary
School, Hosur, for her continuous motivation, guidance and
support.
Mrs. Priyadharshini L. our dear teacher of Computer
Science deserves whole-hearted appreciation for the great
inspiration and continuous guidance in completing this
project.
A special mention to my friends for all the support and help
rendered towards the fulfilment of the project.
Special thanks to my parents for the cooperation and
support which helped me in materializing this project.

PAGE 1
INTRODUCTION
The Mario Game In Python, This Mario Game Code In Python is
design in Graphical User Interface(GUI ) that uses PyGame library.
Talking about the gameplay, the story is, The princess toadstool of
the mushroom kingdom has been kidnapped by the notorious King
Koopa and the toads of the mushroom kingdom have been held
captive in the many castles of King Koopa. It's up to Mario to save
the princess and defeat King Koopa and his minions.

PAGE 2
SETTING UP THE ENVIRONMENT
We want to set up our game environment so that we can start
designing our game. At the highest level, we’ll have three modules in
your code: the game module, the level module, and the sprite
module. The game module will contain game logic (i.e., what
happens when a player dies), and the level module will include game
design (i.e., what the level looks like).

The sprite module will contain our sprites (i.e., your characters,
coins, blocks, etc.). It’s important to separate our game design and
game logic because we want to minimize the dependencies between
our modules so that they are easier to understand and modify.

We’ll also need to install the Pygame library( pip install


pygame==2.1.3.dev8 ), allowing us to create the game from scratch.

PAGE 3
REQUIREMENTS

REQUIRED MODULES:
1. Pygame
2. Scipy

MINIMUM REQUIREMENT:
S.NO NAME SOFTWARE
1 Operating Windows 10
System
2 Processor 2.4 GHz Dual
Core
3 Memory 4 GB RAM
4 Graphics Intel HD
Graphics 4000
5 Storage 2GB available
space

RECOMMENDED REQUIREMENTS:
S.NO NAME SOFTWARE
1 Operating Windows 10
System
2 Processor 3.0 GHz Quad
Core
3 Memory 8 GB RAM
4 Graphics NVIDIA GeForce
GTX 660
5 Storage 2GB available
space

PAGE 4
DESIGNING THE LEVELS AND SPRITES
Now that we have our environment set up for the Mario game in
Python, it’s time to create the level for the game. A level represents
the game space that includes the general environment and obstacles
that the player needs to overcome (e.g., ground, grass, rocks, trees,
mountains, vines, clouds, and rivers). We can create the level using
a graphical editor like Tiled. There are also many visual-level design
tools available online.
Once after the level is designed, we will need to save it as an image
file (.png) and then load it into your Python IDE.

PAGE 5
MAKING THE LEVEL MORE INTERACTIVE
To make the level more interactive add sounds whenever a power-up
is collected, or the player picks up a coin. Also, make vines come
down from the top of the level when a player goes down a level. We
can make ground disappear when a player goes down a level and
make rocks fall down from the top of the level.
We can also make vines come down from the bottom of the level
when the player goes up a level. We can make the ground appear
when a player goes up a level, and rocks appear at the bottom when
a player goes down a level. We can also make water flow from the
top to the bottom when a player goes down a level .

LEVEL-1

LEVEL-2

PAGE 6
ADDING THE TITLE SCREEN AND GAME
OVER SCREEN

TITLE SCREEN:

ON-GAME SCREEN:

GAME OVER SCREEN:

PAGE 7
SOURCE CODE
MAIN PY FILE:

import pygame

from classes.Dashboard import Dashboard

from classes.Level import Level

from classes.Menu import Menu

from classes.Sound import Sound

from entities.Mario import Mario

windowSize = 640, 480

def main():

pygame.mixer.pre_init(44100, -16, 2, 4096)

pygame.init()

screen = pygame.display.set_mode(windowSize)

max_frame_rate = 60

dashboard = Dashboard("./img/font.png", 8, screen)

sound = Sound()

level = Level(screen, sound, dashboard)

menu = Menu(screen, dashboard, level, sound)

while not menu.start:

menu.update()

mario = Mario(0, 0, level, screen, dashboard, sound)

clock = pygame.time.Clock()

while not mario.restart:

pygame.display.set_caption("Super Mario running with {:d} FPS".format(int(clock.get_fps())))

if mario.pause:

mario.pauseObj.update()

else:

level.drawLevel(mario.camera)

dashboard.update()

mario.update()

pygame.display.update()

clock.tick(max_frame_rate)

PAGE 8
return 'restart'

COMPILE FILE:

from distutils.core import setup

import py2exe

import glob

setup(

# this is the file that is run when you start the game from the command line.

console=["main.py"],

# data files - these are the non-python files, like images and sounds

data_files=[

("sprites", glob.glob("sprites\\*.json")),

("sfx", glob.glob("sfx\\*.ogg") + glob.glob("sfx\\*.wav")),

("levels", glob.glob("levels\\*.json")),

("img", glob.glob("img\\*.gif") + glob.glob("img\\*.png")),

("", ["settings.json"]),

],

ANIMATION:

class Animation:

def __init__(self, images, idleSprite=None, airSprite=None, deltaTime=7):

self.images = images

self.timer = 0

self.index = 0

self.image = self.images[self.index]

self.idleSprite = idleSprite

self.airSprite = airSprite

self.deltaTime = deltaTime

def update(self):

self.timer += 1

if self.timer % self.deltaTime == 0:

if self.index < len(self.images) - 1:

self.index += 1

else:

PAGE 9
self.index = 0

self.image = self.images[self.index]

def idle(self):

self.image = self.idleSprite

def inAir(self):

self.image = self.airSprite

CAMERA:

from classes.Maths import Vec2D

class Camera:

def __init__(self, pos, entity):

self.pos = Vec2D(pos.x, pos.y)

self.entity = entity

self.x = self.pos.x * 32

self.y = self.pos.y * 32

def move(self):

xPosFloat = self.entity.getPosIndexAsFloat().x

if 10 < xPosFloat < 50:

self.pos.x = -xPosFloat + 10

self.x = self.pos.x * 32

self.y = self.pos.y * 32

COLLIDER:

class Collider:

def __init__(self, entity, level):

self.entity = entity

self.level = level.level

self.levelObj = level

self.result = []

def checkX(self):

if self.leftLevelBorderReached() or self.rightLevelBorderReached():

return

try:

rows = [

self.level[self.entity.getPosIndex().y],

PAGE 10
self.level[self.entity.getPosIndex().y + 1],

self.level[self.entity.getPosIndex().y + 2],

except Exception:

return

for row in rows:

tiles = row[self.entity.getPosIndex().x : self.entity.getPosIndex().x + 2]

for tile in tiles:

if tile.rect is not None:

if self.entity.rect.colliderect(tile.rect):

if self.entity.vel.x > 0:

self.entity.rect.right = tile.rect.left

self.entity.vel.x = 0

if self.entity.vel.x < 0:

self.entity.rect.left = tile.rect.right

self.entity.vel.x = 0

def checkY(self):

self.entity.onGround = False

try:

rows = [

self.level[self.entity.getPosIndex().y],

self.level[self.entity.getPosIndex().y + 1],

self.level[self.entity.getPosIndex().y + 2],

except Exception:

try:

self.entity.gameOver()

except Exception:

self.entity.alive = None

return

for row in rows:

tiles = row[self.entity.getPosIndex().x : self.entity.getPosIndex().x + 2]

for tile in tiles:

PAGE 11
if tile.rect is not None:

if self.entity.rect.colliderect(tile.rect):

if self.entity.vel.y > 0:

self.entity.onGround = True

self.entity.rect.bottom = tile.rect.top

self.entity.vel.y = 0

# reset jump on bottom

if self.entity.traits is not None:

if "JumpTrait" in self.entity.traits:

self.entity.traits["JumpTrait"].reset()

if "bounceTrait" in self.entity.traits:

self.entity.traits["bounceTrait"].reset()

if self.entity.vel.y < 0:

self.entity.rect.top = tile.rect.bottom

self.entity.vel.y = 0

def rightLevelBorderReached(self):

if self.entity.getPosIndexAsFloat().x > self.levelObj.levelLength - 1:

self.entity.rect.x = (self.levelObj.levelLength - 1) * 32

self.entity.vel.x = 0

return True

def leftLevelBorderReached(self):

if self.entity.rect.x < 0:

self.entity.rect.x = 0

self.entity.vel.x = 0

return True

DASHBOARD :

import pygame

from classes.Font import Font

class Dashboard(Font):

def __init__(self, filePath, size, screen):

Font.__init__(self, filePath, size)

self.state = "menu"

self.screen = screen

PAGE 12
self.levelName = ""

self.points = 0

self.coins = 0

self.ticks = 0

self.time = 0

def update(self):

self.drawText("MARIO", 50, 20, 15)

self.drawText(self.pointString(), 50, 37, 15)

self.drawText("@x{}".format(self.coinString()), 225, 37, 15)

self.drawText("WORLD", 380, 20, 15)

self.drawText(str(self.levelName), 395, 37, 15)

self.drawText("TIME", 520, 20, 15)

if self.state != "menu":

self.drawText(self.timeString(), 535, 37, 15)

# update Time

self.ticks += 1

if self.ticks == 60:

self.ticks = 0

self.time += 1

def drawText(self, text, x, y, size):

for char in text:

charSprite = pygame.transform.scale(self.charSprites[char], (size, size))

self.screen.blit(charSprite, (x, y))

if char == " ":

x += size//2

else:

x += size

def coinString(self):

return "{:02d}".format(self.coins)

def pointString(self):

return "{:06d}".format(self.points)

def timeString(self):

return "{:03d}".format(self.time)

PAGE 13
ENTITY COLLIDER:

class EntityCollider:

def __init__(self, entity):

self.entity = entity

def check(self, target):

if self.entity.rect.colliderect(target.rect):

return self.determineSide(target.rect, self.entity.rect)

return CollisionState(False, False)

def determineSide(self, rect1, rect2):

if (

rect1.collidepoint(rect2.bottomleft)

or rect1.collidepoint(rect2.bottomright)

or rect1.collidepoint(rect2.midbottom)

):

if rect2.collidepoint(

(rect1.midleft[0] / 2, rect1.midleft[1] / 2)

) or rect2.collidepoint((rect1.midright[0] / 2, rect1.midright[1] / 2)):

return CollisionState(True, False)

else:

if self.entity.vel.y > 0:

return CollisionState(True, True)

return CollisionState(True, False)

class CollisionState:

def __init__(self, _isColliding, _isTop):

self.isColliding = _isColliding

self.isTop = _isTop

FONT:

from classes.Spritesheet import Spritesheet

import pygame

class Font(Spritesheet):

def __init__(self, filePath, size):

Spritesheet.__init__(self, filename=filePath)

self.chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

PAGE 14
self.charSprites = self.loadFont()

def loadFont(self):

font = {}

row = 0

charAt = 0

for char in self.chars:

if charAt == 16:

charAt = 0

row += 1

font.update(

char: self.image_at(

charAt,

row,

2,

colorkey=pygame.color.Color(0, 0, 0),

xTileSize=8,

yTileSize=8

charAt += 1

return font

GAUSSIANBLUR:

import pygame

from scipy.ndimage.filters import *

class GaussianBlur:

def __init__(self, kernelsize=7):

self.kernel_size = kernelsize

def filter(self, srfc, xpos, ypos, width, height):

nSrfc = pygame.Surface((width, height))

pxa = pygame.surfarray.array3d(srfc)

blurred = gaussian_filter(pxa, sigma=(self.kernel_size, self.kernel_size, 0))

PAGE 15
pygame.surfarray.blit_array(nSrfc, blurred)

del pxa

return nSrfc

INPUT:

import pygame

from pygame.locals import *

import sys

class Input:

def __init__(self, entity):

self.mouseX = 0

self.mouseY = 0

self.entity = entity

def checkForInput(self):

events = pygame.event.get()

self.checkForKeyboardInput()

self.checkForMouseInput(events)

self.checkForQuitAndRestartInputEvents(events)

def checkForKeyboardInput(self):

pressedKeys = pygame.key.get_pressed()

if pressedKeys[K_LEFT] or pressedKeys[K_h] and not pressedKeys[K_RIGHT]:

self.entity.traits["goTrait"].direction = -1

elif pressedKeys[K_RIGHT] or pressedKeys[K_l] and not pressedKeys[K_LEFT]:

self.entity.traits["goTrait"].direction = 1

else:

self.entity.traits['goTrait'].direction = 0

isJumping = pressedKeys[K_SPACE] or pressedKeys[K_UP] or pressedKeys[K_k]

self.entity.traits['jumpTrait'].jump(isJumping)

self.entity.traits['goTrait'].boost = pressedKeys[K_LSHIFT]

def checkForMouseInput(self, events):

mouseX, mouseY = pygame.mouse.get_pos()

if self.isRightMouseButtonPressed(events):

self.entity.levelObj.addKoopa(

mouseY / 32, mouseX / 32 - self.entity.camera.pos.x

PAGE 16
)

self.entity.levelObj.addGoomba(

mouseY / 32, mouseX / 32 - self.entity.camera.pos.x

self.entity.levelObj.addRedMushroom(

mouseY / 32, mouseX / 32 - self.entity.camera.pos.x

if self.isLeftMouseButtonPressed(events):

self.entity.levelObj.addCoin(

mouseX / 32 - self.entity.camera.pos.x, mouseY / 32

def checkForQuitAndRestartInputEvents(self, events):

for event in events:

if event.type == pygame.QUIT:

pygame.quit()

sys.exit()

if event.type == pygame.KEYDOWN and \

(event.key == pygame.K_ESCAPE or event.key == pygame.K_F5):

self.entity.pause = True

self.entity.pauseObj.createBackgroundBlur()

def isLeftMouseButtonPressed(self, events):

return self.checkMouse(events, 1)

def isRightMouseButtonPressed(self, events):

return self.checkMouse(events, 3)

def checkMouse(self, events, button):

for e in events:

if e.type == pygame.MOUSEBUTTONUP and e.button == button:

return True

return False

LEVELS:

import json

import pygame

from classes.Sprites import Sprites

PAGE 17
from classes.Tile import Tile

from entities.Coin import Coin

from entities.CoinBrick import CoinBrick

from entities.Goomba import Goomba

from entities.Mushroom import RedMushroom

from entities.Koopa import Koopa

from entities.CoinBox import CoinBox

from entities.RandomBox import RandomBox

class Level:

def __init__(self, screen, sound, dashboard):

self.sprites = Sprites()

self.dashboard = dashboard

self.sound = sound

self.screen = screen

self.level = None

self.levelLength = 0

self.entityList = []

def loadLevel(self, levelname):

with open("./levels/{}.json".format(levelname)) as jsonData:

data = json.load(jsonData)

self.loadLayers(data)

self.loadObjects(data)

self.loadEntities(data)

self.levelLength = data["length"]

def loadEntities(self, data):

try:

[self.addCoinBox(x, y) for x, y in data["level"]["entities"]["CoinBox"]]

[self.addGoomba(x, y) for x, y in data["level"]["entities"]["Goomba"]]

[self.addKoopa(x, y) for x, y in data["level"]["entities"]["Koopa"]]

[self.addCoin(x, y) for x, y in data["level"]["entities"]["coin"]]

[self.addCoinBrick(x, y) for x, y in data["level"]["entities"]["coinBrick"]]

[self.addRandomBox(x, y, item) for x, y, item in data["level"]["entities"]["RandomBox"]]

except:

PAGE 18
# if no entities in Level

pass

def loadLayers(self, data):

layers = []

for x in range(*data["level"]["layers"]["sky"]["x"]):

layers.append(

Tile(self.sprites.spriteCollection.get("sky"), None)

for y in range(*data["level"]["layers"]["sky"]["y"])

+[

Tile(

self.sprites.spriteCollection.get("ground"),

pygame.Rect(x * 32, (y - 1) * 32, 32, 32),

for y in range(*data["level"]["layers"]["ground"]["y"])

self.level = list(map(list, zip(*layers)))

def loadObjects(self, data):

for x, y in data["level"]["objects"]["bush"]:

self.addBushSprite(x, y)

for x, y in data["level"]["objects"]["cloud"]:

self.addCloudSprite(x, y)

for x, y, z in data["level"]["objects"]["pipe"]:

self.addPipeSprite(x, y, z)

for x, y in data["level"]["objects"]["sky"]:

self.level[y][x] = Tile(self.sprites.spriteCollection.get("sky"), None)

for x, y in data["level"]["objects"]["ground"]:

self.level[y][x] = Tile(

self.sprites.spriteCollection.get("ground"),

PAGE 19
pygame.Rect(x * 32, y * 32, 32, 32),

def updateEntities(self, cam):

for entity in self.entityList:

entity.update(cam)

if entity.alive is None:

self.entityList.remove(entity)

def drawLevel(self, camera):

try:

for y in range(0, 15):

for x in range(0 - int(camera.pos.x + 1), 20 - int(camera.pos.x - 1)):

if self.level[y][x].sprite is not None:

if self.level[y][x].sprite.redrawBackground:

self.screen.blit(

self.sprites.spriteCollection.get("sky").image,

((x + camera.pos.x) * 32, y * 32),

self.level[y][x].sprite.drawSprite(

x + camera.pos.x, y, self.screen

self.updateEntities(camera)

except IndexError:

return

def addCloudSprite(self, x, y):

try:

for yOff in range(0, 2):

for xOff in range(0, 3):

self.level[y + yOff][x + xOff] = Tile(

self.sprites.spriteCollection.get("cloud{}_{}".format(yOff + 1, xOff + 1)), None, )

except IndexError:

return

def addPipeSprite(self, x, y, length=2):

try:

PAGE 20
# add pipe head

self.level[y][x] = Tile(

self.sprites.spriteCollection.get("pipeL"),

pygame.Rect(x * 32, y * 32, 32, 32),

self.level[y][x + 1] = Tile(

self.sprites.spriteCollection.get("pipeR"),

pygame.Rect((x + 1) * 32, y * 32, 32, 32),

# add pipe body

for i in range(1, length + 20):

self.level[y + i][x] = Tile(

self.sprites.spriteCollection.get("pipe2L"),

pygame.Rect(x * 32, (y + i) * 32, 32, 32),

self.level[y + i][x + 1] = Tile(

self.sprites.spriteCollection.get("pipe2R"),

pygame.Rect((x + 1) * 32, (y + i) * 32, 32, 32),

except IndexError:

return

def addBushSprite(self, x, y):

try:

self.level[y][x] = Tile(self.sprites.spriteCollection.get("bush_1"), None)

self.level[y][x + 1] = Tile(

self.sprites.spriteCollection.get("bush_2"), None

self.level[y][x + 2] = Tile(

self.sprites.spriteCollection.get("bush_3"), None

except IndexError:

return

PAGE 21
def addCoinBox(self, x, y):

self.level[y][x] = Tile(None, pygame.Rect(x * 32, y * 32 - 1, 32, 32))

self.entityList.append(

CoinBox(

self.screen,

self.sprites.spriteCollection,

x,

y,

self.sound,

self.dashboard,

def addRandomBox(self, x, y, item):

self.level[y][x] = Tile(None, pygame.Rect(x * 32, y * 32 - 1, 32, 32))

self.entityList.append(

RandomBox(

self.screen,

self.sprites.spriteCollection,

x,

y,

item,

self.sound,

self.dashboard,

self

def addCoin(self, x, y):

self.entityList.append(Coin(self.screen, self.sprites.spriteCollection, x, y))

def addCoinBrick(self, x, y):

self.level[y][x] = Tile(None, pygame.Rect(x * 32, y * 32 - 1, 32, 32))

self.entityList.append(

CoinBrick(

self.screen,

PAGE 22
self.sprites.spriteCollection,

x,

y,

self.sound,

self.dashboard

def addGoomba(self, x, y):

self.entityList.append(

Goomba(self.screen, self.sprites.spriteCollection, x, y, self, self.sound)

def addKoopa(self, x, y):

self.entityList.append(

Koopa(self.screen, self.sprites.spriteCollection, x, y, self, self.sound)

def addRedMushroom(self, x, y):

self.entityList.append(

RedMushroom(self.screen, self.sprites.spriteCollection, x, y, self, self.sound)

MATHS:

class Vec2D:

def __init__(self, x=0, y=0):

self.x = x

self.y = y

MENU:

import json

import sys

import os

import pygame

from classes.Spritesheet import Spritesheet

class Menu:

def __init__(self, screen, dashboard, level, sound):

self.screen = screen

PAGE 23
self.sound = sound

self.start = False

self.inSettings = False

self.state = 0

self.level = level

self.music = True

self.sfx = True

self.currSelectedLevel = 1

self.levelNames = []

self.inChoosingLevel = False

self.dashboard = dashboard

self.levelCount = 0

self.spritesheet = Spritesheet("./img/title_screen.png")

self.menu_banner = self.spritesheet.image_at(

0,

60,

2,

colorkey=[255, 0, 220],

ignoreTileSize=True,

xTileSize=180,

yTileSize=88,

self.menu_dot = self.spritesheet.image_at(

0, 150, 2, colorkey=[255, 0, 220], ignoreTileSize=True

self.menu_dot2 = self.spritesheet.image_at(

20, 150, 2, colorkey=[255, 0, 220], ignoreTileSize=True

self.loadSettings("./settings.json")

def update(self):

self.checkInput()

if self.inChoosingLevel:

return

PAGE 24
self.drawMenuBackground()

self.dashboard.update()

if not self.inSettings:

self.drawMenu()

else:

self.drawSettings()

def drawDot(self):

if self.state == 0:

self.screen.blit(self.menu_dot, (145, 273))

self.screen.blit(self.menu_dot2, (145, 313))

self.screen.blit(self.menu_dot2, (145, 353))

elif self.state == 1:

self.screen.blit(self.menu_dot, (145, 313))

self.screen.blit(self.menu_dot2, (145, 273))

self.screen.blit(self.menu_dot2, (145, 353))

elif self.state == 2:

self.screen.blit(self.menu_dot, (145, 353))

self.screen.blit(self.menu_dot2, (145, 273))

self.screen.blit(self.menu_dot2, (145, 313))

def loadSettings(self, url):

try:

with open(url) as jsonData:

data = json.load(jsonData)

if data["sound"]:

self.music = True

self.sound.music_channel.play(self.sound.soundtrack, loops=-1)

else:

self.music = False

if data["sfx"]:

self.sfx = True

self.sound.allowSFX = True

else:

self.sound.allowSFX = False

PAGE 25
self.sfx = False

except (IOError, OSError):

self.music = False

self.sound.allowSFX = False

self.sfx = False

self.saveSettings("./settings.json")

def saveSettings(self, url):

data = {"sound": self.music, "sfx": self.sfx}

with open(url, "w") as outfile:

json.dump(data, outfile)

def drawMenu(self):

self.drawDot()

self.dashboard.drawText("CHOOSE LEVEL", 180, 280, 24)

self.dashboard.drawText("SETTINGS", 180, 320, 24)

self.dashboard.drawText("EXIT", 180, 360, 24)

def drawMenuBackground(self, withBanner=True):

for y in range(0, 13):

for x in range(0, 20):

self.screen.blit(

self.level.sprites.spriteCollection.get("sky").image,

(x * 32, y * 32),

for y in range(13, 15):

for x in range(0, 20):

self.screen.blit(

self.level.sprites.spriteCollection.get("ground").image,

(x * 32, y * 32),

if withBanner:

self.screen.blit(self.menu_banner, (150, 80))

self.screen.blit(

self.level.sprites.spriteCollection.get("mario_idle").image,

PAGE 26
(2 * 32, 12 * 32),

self.screen.blit(

self.level.sprites.spriteCollection.get("bush_1").image, (14 * 32, 12 * 32)

self.screen.blit(

self.level.sprites.spriteCollection.get("bush_2").image, (15 * 32, 12 * 32)

self.screen.blit(

self.level.sprites.spriteCollection.get("bush_2").image, (16 * 32, 12 * 32)

self.screen.blit(

self.level.sprites.spriteCollection.get("bush_2").image, (17 * 32, 12 * 32)

self.screen.blit(

self.level.sprites.spriteCollection.get("bush_3").image, (18 * 32, 12 * 32)

self.screen.blit(self.level.sprites.spriteCollection.get("goomba-1").image, (18.5*32, 12*32))

def drawSettings(self):

self.drawDot()

self.dashboard.drawText("MUSIC", 180, 280, 24)

if self.music:

self.dashboard.drawText("ON", 340, 280, 24)

else:

self.dashboard.drawText("OFF", 340, 280, 24)

self.dashboard.drawText("SFX", 180, 320, 24)

if self.sfx:

self.dashboard.drawText("ON", 340, 320, 24)

else:

self.dashboard.drawText("OFF", 340, 320, 24)

self.dashboard.drawText("BACK", 180, 360, 24)

def chooseLevel(self):

self.drawMenuBackground(False)

PAGE 27
self.inChoosingLevel = True

self.levelNames = self.loadLevelNames()

self.drawLevelChooser()

def drawBorder(self, x, y, width, height, color, thickness):

pygame.draw.rect(self.screen, color, (x, y, width, thickness))

pygame.draw.rect(self.screen, color, (x, y+width, width, thickness))

pygame.draw.rect(self.screen, color, (x, y, thickness, width))

pygame.draw.rect(self.screen, color, (x+width, y, thickness, width+thickness))

def drawLevelChooser(self):

j=0

offset = 75

textOffset = 90

for i, levelName in enumerate(self.loadLevelNames()):

if self.currSelectedLevel == i+1:

color = (255, 255, 255)

else:

color = (150, 150, 150)

if i < 3:

self.dashboard.drawText(levelName, 175*i+textOffset, 100, 12)

self.drawBorder(175*i+offset, 55, 125, 75, color, 5)

else:

self.dashboard.drawText(levelName, 175*j+textOffset, 250, 12)

self.drawBorder(175*j+offset, 210, 125, 75, color, 5)

j += 1

def loadLevelNames(self):

files = []

res = []

for r, d, f in os.walk("./levels"):

for file in f:

files.append(os.path.join(r, file))

for f in files:

res.append(os.path.split(f)[1].split(".")[0])

PAGE 28
self.levelCount = len(res)

return res

def checkInput(self):

events = pygame.event.get()

for event in events:

if event.type == pygame.QUIT:

pygame.quit()

sys.exit()

if event.type == pygame.KEYDOWN:

if event.key == pygame.K_ESCAPE:

if self.inChoosingLevel or self.inSettings:

self.inChoosingLevel = False

self.inSettings = False

self.__init__(self.screen, self.dashboard, self.level, self.sound)

else:

pygame.quit()

sys.exit()

elif event.key == pygame.K_UP or event.key == pygame.K_k:

if self.inChoosingLevel:

if self.currSelectedLevel > 3:

self.currSelectedLevel -= 3

self.drawLevelChooser()

if self.state > 0:

self.state -= 1

elif event.key == pygame.K_DOWN or event.key == pygame.K_j:

if self.inChoosingLevel:

if self.currSelectedLevel+3 <= self.levelCount:

self.currSelectedLevel += 3

self.drawLevelChooser()

if self.state < 2:

self.state += 1

elif event.key == pygame.K_LEFT or event.key == pygame.K_h:

if self.currSelectedLevel > 1:

PAGE 29
self.currSelectedLevel -= 1

self.drawLevelChooser()

elif event.key == pygame.K_RIGHT or event.key == pygame.K_l:

if self.currSelectedLevel < self.levelCount:

self.currSelectedLevel += 1

self.drawLevelChooser()

elif event.key == pygame.K_RETURN:

if self.inChoosingLevel:

self.inChoosingLevel = False

self.dashboard.state = "start"

self.dashboard.time = 0

self.level.loadLevel(self.levelNames[self.currSelectedLevel-1])

self.dashboard.levelName = self.levelNames[self.currSelectedLevel-1].split("Level")[1]

self.start = True

return

if not self.inSettings:

if self.state == 0:

self.chooseLevel()

elif self.state == 1:

self.inSettings = True

self.state = 0

elif self.state == 2:

pygame.quit()

sys.exit()

else:

if self.state == 0:

if self.music:

self.sound.music_channel.stop()

self.music = False

else:

self.sound.music_channel.play(self.sound.soundtrack, loops=-1)

self.music = True

self.saveSettings("./settings.json")

PAGE 30
elif self.state == 1:

if self.sfx:

self.sound.allowSFX = False

self.sfx = False

else:

self.sound.allowSFX = True

self.sfx = True

self.saveSettings("./settings.json")

elif self.state == 2:

self.inSettings = False

pygame.display.update()

PAUSE:

import pygame

import sys

from classes.Spritesheet import Spritesheet

from classes.GaussianBlur import GaussianBlur

class Pause:

def __init__(self, screen, entity, dashboard):

self.screen = screen

self.entity = entity

self.dashboard = dashboard

self.state = 0

self.spritesheet = Spritesheet("./img/title_screen.png")

self.pause_srfc = GaussianBlur().filter(self.screen, 0, 0, 640, 480)

self.dot = self.spritesheet.image_at(

0, 150, 2, colorkey=[255, 0, 220], ignoreTileSize=True

self.gray_dot = self.spritesheet.image_at(

20, 150, 2, colorkey=[255, 0, 220], ignoreTileSize=True

def update(self):

self.screen.blit(self.pause_srfc, (0, 0))

self.dashboard.drawText("PAUSED", 120, 160, 68)

PAGE 31
self.dashboard.drawText("CONTINUE", 150, 280, 32)

self.dashboard.drawText("BACK TO MENU", 150, 320, 32)

self.drawDot()

pygame.display.update()

self.checkInput()

def drawDot(self):

if self.state == 0:

self.screen.blit(self.dot, (100, 275))

self.screen.blit(self.gray_dot, (100, 315))

elif self.state == 1:

self.screen.blit(self.dot, (100, 315))

self.screen.blit(self.gray_dot, (100, 275))

def checkInput(self):

events = pygame.event.get()

for event in events:

if event.type == pygame.QUIT:

pygame.quit()

sys.exit()

if event.type == pygame.KEYDOWN:

if event.key == pygame.K_RETURN:

if self.state == 0:

self.entity.pause = False

elif self.state == 1:

self.entity.restart = True

elif event.key == pygame.K_UP:

if self.state > 0:

self.state -= 1

elif event.key == pygame.K_DOWN:

if self.state < 1:

self.state += 1

def createBackgroundBlur(self):

self.pause_srfc = GaussianBlur().filter(self.screen, 0, 0, 640, 480)

SOUND:

PAGE 32
from pygame import mixer

class Sound:

def __init__(self):

self.music_channel = mixer.Channel(0)

self.music_channel.set_volume(0.2)

self.sfx_channel = mixer.Channel(1)

self.sfx_channel.set_volume(0.2)

self.allowSFX = True

self.soundtrack = mixer.Sound("./sfx/main_theme.ogg")

self.coin = mixer.Sound("./sfx/coin.ogg")

self.bump = mixer.Sound("./sfx/bump.ogg")

self.stomp = mixer.Sound("./sfx/stomp.ogg")

self.jump = mixer.Sound("./sfx/small_jump.ogg")

self.death = mixer.Sound("./sfx/death.wav")

self.kick = mixer.Sound("./sfx/kick.ogg")

self.brick_bump = mixer.Sound("./sfx/brick-bump.ogg")

self.powerup = mixer.Sound('./sfx/powerup.ogg')

self.powerup_appear = mixer.Sound('./sfx/powerup_appears.ogg')

self.pipe = mixer.Sound('./sfx/pipe.ogg')

def play_sfx(self, sfx):

if self.allowSFX:

self.sfx_channel.play(sfx)

def play_music(self, music):

self.music_channel.play(music)

SPRITE:

class Sprite:

def __init__(self, image, colliding, animation=None, redrawBackground=False):

self.image = image

self.colliding = colliding

self.animation = animation

self.redrawBackground = redrawBackground

def drawSprite(self, x, y, screen):

dimensions = (x * 32, y * 32)

PAGE 33
if self.animation is None:

screen.blit(self.image, dimensions)

else:

self.animation.update()

screen.blit(self.animation.image, dimensions)

SPRITESHEET:

import pygame

class Spritesheet(object):

def __init__(self, filename):

try:

self.sheet = pygame.image.load(filename)

self.sheet = pygame.image.load(filename)

if not self.sheet.get_alpha():

self.sheet.set_colorkey((0, 0, 0))

except pygame.error:

print("Unable to load spritesheet image:", filename)

raise SystemExit

def image_at(self, x, y, scalingfactor, colorkey=None, ignoreTileSize=False,

xTileSize=16, yTileSize=16):

if ignoreTileSize:

rect = pygame.Rect((x, y, xTileSize, yTileSize))

else:

rect = pygame.Rect((x * xTileSize, y * yTileSize, xTileSize, yTileSize))

image = pygame.Surface(rect.size)

image.blit(self.sheet, (0, 0), rect)

if colorkey is not None:

if colorkey == -1:

colorkey = image.get_at((0, 0))

image.set_colorkey(colorkey, pygame.RLEACCEL)

return pygame.transform.scale(

image, (xTileSize * scalingfactor, yTileSize * scalingfactor)

TILE:

PAGE 34
import pygame

class Tile:

def __init__(self, sprite, rect):

self.sprite = sprite

self.rect = rect

def drawRect(self, screen):

try:

pygame.draw.rect(screen, pygame.Color(255, 0, 0), self.rect, 1)

except Exception:

pass

COINS:

from copy import copy

from entities.EntityBase import EntityBase

class Coin(EntityBase):

def __init__(self, screen, spriteCollection, x, y, gravity=0):

super(Coin, self).__init__(x, y, gravity)

self.screen = screen

self.spriteCollection = spriteCollection

self.animation = copy(self.spriteCollection.get("coin").animation)

self.type = "Item"

def update(self, cam):

if self.alive:

self.animation.update()

self.screen.blit(self.animation.image, (self.rect.x + cam.x, self.rect.y))

COINBOX:

from copy import copy

from entities.EntityBase import EntityBase

from entities.Item import Item

class CoinBox(EntityBase):

def __init__(self, screen, spriteCollection, x, y, sound, dashboard, gravity=0):

super(CoinBox, self).__init__(x, y, gravity)

self.screen = screen

PAGE 35
self.spriteCollection = spriteCollection

self.animation = copy(self.spriteCollection.get("CoinBox").animation)

self.type = "Block"

self.triggered = False

self.time = 0

self.maxTime = 10

self.sound = sound

self.dashboard = dashboard

self.vel = 1

self.item = Item(spriteCollection, screen, self.rect.x, self.rect.y)

def update(self, cam):

if self.alive and not self.triggered:

self.animation.update()

else:

self.animation.image = self.spriteCollection.get("empty").image

self.item.spawnCoin(cam, self.sound, self.dashboard)

if self.time < self.maxTime:

self.time += 1

self.rect.y -= self.vel

else:

if self.time < self.maxTime * 2:

self.time += 1

self.rect.y += self.vel

self.screen.blit(

self.spriteCollection.get("sky").image,

(self.rect.x + cam.x, self.rect.y + 2),

self.screen.blit(self.animation.image, (self.rect.x + cam.x, self.rect.y - 1))

COINBRICK:

from copy import copy

from entities.EntityBase import EntityBase

from entities.Item import Item

class CoinBrick(EntityBase):

PAGE 36
def __init__(self, screen, spriteCollection, x, y, sound, dashboard, gravity=0):

super(CoinBrick, self).__init__(x, y, gravity)

self.screen = screen

self.spriteCollection = spriteCollection

self.image = self.spriteCollection.get("bricks").image

self.type = "Block"

self.triggered = False

self.sound = sound

self.dashboard = dashboard

self.item = Item(spriteCollection, screen, self.rect.x, self.rect.y)

def update(self, cam):

if not self.alive or self.triggered:

self.image = self.spriteCollection.get("empty").image

self.item.spawnCoin(cam, self.sound, self.dashboard)

self.screen.blit(

self.spriteCollection.get("sky").image,

(self.rect.x + cam.x, self.rect.y + 2),

self.screen.blit(self.image, (self.rect.x + cam.x, self.rect.y - 1))

ENTITY BASE:

import pygame

from classes.Maths import Vec2D

class EntityBase(object):

def __init__(self, x, y, gravity):

self.vel = Vec2D()

self.rect = pygame.Rect(x * 32, y * 32, 32, 32)

self.gravity = gravity

self.traits = None

self.alive = True

self.active = True

self.bouncing = False

self.timeAfterDeath = 5

self.timer = 0

PAGE 37
self.type = ""

self.onGround = False

self.obeyGravity = True

def applyGravity(self):

if self.obeyGravity:

self.vel.y += self.gravity

def updateTraits(self):

for trait in self.traits.values():

try:

trait.update()

except AttributeError:

pass

def getPosIndex(self):

return Vec2D(self.rect.x // 32, self.rect.y // 32)

def getPosIndexAsFloat(self):

return Vec2D(self.rect.x / 32.0, self.rect.y / 32.0)

GOOMBA:

from classes.Animation import Animation

from classes.Collider import Collider

from classes.EntityCollider import EntityCollider

from classes.Maths import Vec2D

from entities.EntityBase import EntityBase

from traits.leftrightwalk import LeftRightWalkTrait

class Goomba(EntityBase):

def __init__(self, screen, spriteColl, x, y, level, sound):

super(Goomba, self).__init__(y, x - 1, 1.25)

self.spriteCollection = spriteColl

self.animation = Animation(

self.spriteCollection.get("goomba-1").image,

self.spriteCollection.get("goomba-2").image,

PAGE 38
self.screen = screen

self.leftrightTrait = LeftRightWalkTrait(self, level)

self.type = "Mob"

self.dashboard = level.dashboard

self.collision = Collider(self, level)

self.EntityCollider = EntityCollider(self)

self.levelObj = level

self.sound = sound

self.textPos = Vec2D(0, 0)

def update(self, camera):

if self.alive:

self.applyGravity()

self.drawGoomba(camera)

self.leftrightTrait.update()

self.checkEntityCollision()

else:

self.onDead(camera)

def drawGoomba(self, camera):

self.screen.blit(self.animation.image, (self.rect.x + camera.x, self.rect.y))

self.animation.update()

def onDead(self, camera):

if self.timer == 0:

self.setPointsTextStartPosition(self.rect.x + 3, self.rect.y)

if self.timer < self.timeAfterDeath:

self.movePointsTextUpAndDraw(camera)

self.drawFlatGoomba(camera)

else:

self.alive = None

self.timer += 0.1

def drawFlatGoomba(self, camera):

self.screen.blit(

self.spriteCollection.get("goomba-flat").image,

PAGE 39
(self.rect.x + camera.x, self.rect.y),

def setPointsTextStartPosition(self, x, y):

self.textPos = Vec2D(x, y)

def movePointsTextUpAndDraw(self, camera):

self.textPos.y += -0.5

self.dashboard.drawText("100", self.textPos.x + camera.x, self.textPos.y, 8)

def checkEntityCollision(self):

for ent in self.levelObj.entityList:

collisionState = self.EntityCollider.check(ent)

if collisionState.isColliding:

if ent.type == "Mob":

self._onCollisionWithMob(ent, collisionState)

def _onCollisionWithMob(self, mob, collisionState):

if collisionState.isColliding and mob.bouncing:

self.alive = False

self.sound.play_sfx(self.sound.brick_bump)

ITEM:

from copy import copy

from classes.Dashboard import Dashboard

from classes.Maths import Vec2D

class Item(Dashboard):

def __init__(self, collection, screen, x, y):

super(Item, self).__init__("./img/font.png", 8, screen)

self.ItemPos = Vec2D(x, y)

self.itemVel = Vec2D(0, 0)

self.screen = screen

self.coin_animation = copy(collection.get("coin-item").animation)

self.sound_played = False

def spawnCoin(self, cam, sound, dashboard):

if not self.sound_played:

self.sound_played = True

dashboard.points += 100

PAGE 40
sound.play_sfx(sound.coin)

self.coin_animation.update()

if self.coin_animation.timer < 45:

if self.coin_animation.timer < 15:

self.itemVel.y -= 0.5

self.ItemPos.y += self.itemVel.y

elif self.coin_animation.timer < 45:

self.itemVel.y += 0.5

self.ItemPos.y += self.itemVel.y

self.screen.blit(

self.coin_animation.image, (self.ItemPos.x + cam.x, self.ItemPos.y)

elif self.coin_animation.timer < 80:

self.itemVel.y = -0.75

self.ItemPos.y += self.itemVel.y

self.drawText("100", self.ItemPos.x + 3 + cam.x, self.ItemPos.y, 8)

MARIO:

import pygame

from classes.Animation import Animation

from classes.Camera import Camera

from classes.Collider import Collider

from classes.EntityCollider import EntityCollider

from classes.Input import Input

from classes.Sprites import Sprites

from entities.EntityBase import EntityBase

from entities.Mushroom import RedMushroom

from traits.bounce import bounceTrait

from traits.go import GoTrait

from traits.jump import JumpTrait

from classes.Pause import Pause

spriteCollection = Sprites().spriteCollection

PAGE 41
smallAnimation = Animation(

spriteCollection["mario_run1"].image,

spriteCollection["mario_run2"].image,

spriteCollection["mario_run3"].image,

],

spriteCollection["mario_idle"].image,

spriteCollection["mario_jump"].image,

bigAnimation = Animation(

spriteCollection["mario_big_run1"].image,

spriteCollection["mario_big_run2"].image,

spriteCollection["mario_big_run3"].image,

],

spriteCollection["mario_big_idle"].image,

spriteCollection["mario_big_jump"].image,

class Mario(EntityBase):

def __init__(self, x, y, level, screen, dashboard, sound, gravity=0.8):

super(Mario, self).__init__(x, y, gravity)

self.camera = Camera(self.rect, self)

self.sound = sound

self.input = Input(self)

self.inAir = False

self.inJump = False

self.powerUpState = 0

self.invincibilityFrames = 0

self.traits = {

"jumpTrait": JumpTrait(self),

"goTrait": GoTrait(smallAnimation, screen, self.camera, self),

"bounceTrait": bounceTrait(self),

PAGE 42
self.levelObj = level

self.collision = Collider(self, level)

self.screen = screen

self.EntityCollider = EntityCollider(self)

self.dashboard = dashboard

self.restart = False

self.pause = False

self.pauseObj = Pause(screen, self, dashboard)

def update(self):

if self.invincibilityFrames > 0:

self.invincibilityFrames -= 1

self.updateTraits()

self.moveMario()

self.camera.move()

self.applyGravity()

self.checkEntityCollision()

self.input.checkForInput()

def moveMario(self):

self.rect.y += self.vel.y

self.collision.checkY()

self.rect.x += self.vel.x

self.collision.checkX()

def checkEntityCollision(self):

for ent in self.levelObj.entityList:

collisionState = self.EntityCollider.check(ent)

if collisionState.isColliding:

if ent.type == "Item":

self._onCollisionWithItem(ent)

elif ent.type == "Block":

self._onCollisionWithBlock(ent)

elif ent.type == "Mob":

self._onCollisionWithMob(ent, collisionState)

def _onCollisionWithItem(self, item):

PAGE 43
self.levelObj.entityList.remove(item)

self.dashboard.points += 100

self.dashboard.coins += 1

self.sound.play_sfx(self.sound.coin)

def _onCollisionWithBlock(self, block):

if not block.triggered:

self.dashboard.coins += 1

self.sound.play_sfx(self.sound.bump)

block.triggered = True

def _onCollisionWithMob(self, mob, collisionState):

if isinstance(mob, RedMushroom) and mob.alive:

self.powerup(1)

self.killEntity(mob)

self.sound.play_sfx(self.sound.powerup)

elif collisionState.isTop and (mob.alive or mob.bouncing):

self.sound.play_sfx(self.sound.stomp)

self.rect.bottom = mob.rect.top

self.bounce()

self.killEntity(mob)

elif collisionState.isTop and mob.alive and not mob.active:

self.sound.play_sfx(self.sound.stomp)

self.rect.bottom = mob.rect.top

mob.timer = 0

self.bounce()

mob.alive = False

elif collisionState.isColliding and mob.alive and not mob.active and not mob.bouncing:

mob.bouncing = True

if mob.rect.x < self.rect.x:

mob.leftrightTrait.direction = -1

mob.rect.x += -5

self.sound.play_sfx(self.sound.kick)

else:

mob.rect.x += 5

PAGE 44
mob.leftrightTrait.direction = 1

self.sound.play_sfx(self.sound.kick)

elif collisionState.isColliding and mob.alive and not self.invincibilityFrames:

if self.powerUpState == 0:

self.gameOver()

elif self.powerUpState == 1:

self.powerUpState = 0

self.traits['goTrait'].updateAnimation(smallAnimation)

x, y = self.rect.x, self.rect.y

self.rect = pygame.Rect(x, y + 32, 32, 32)

self.invincibilityFrames = 60

self.sound.play_sfx(self.sound.pipe)

def bounce(self):

self.traits["bounceTrait"].jump = True

def killEntity(self, ent):

if ent.__class__.__name__ != "Koopa":

ent.alive = False

else:

ent.timer = 0

ent.leftrightTrait.speed = 1

ent.alive = True

ent.active = False

ent.bouncing = False

self.dashboard.points += 100

def gameOver(self):

srf = pygame.Surface((640, 480))

srf.set_colorkey((255, 255, 255), pygame.RLEACCEL)

srf.set_alpha(128)

self.sound.music_channel.stop()

self.sound.music_channel.play(self.sound.death)

for i in range(500, 20, -2):

srf.fill((0, 0, 0))

pygame.draw.circle(

PAGE 45
srf,

(255, 255, 255),

(int(self.camera.x + self.rect.x) + 16, self.rect.y + 16),

i,

self.screen.blit(srf, (0, 0))

pygame.display.update()

self.input.checkForInput()

while self.sound.music_channel.get_busy():

pygame.display.update()

self.input.checkForInput()

self.restart = True

def getPos(self):

return self.camera.x + self.rect.x, self.rect.y

def setPos(self, x, y):

self.rect.x = x

self.rect.y = y

def powerup(self, powerupID):

if self.powerUpState == 0:

if powerupID == 1:

self.powerUpState = 1

self.traits['goTrait'].updateAnimation(bigAnimation)

self.rect = pygame.Rect(self.rect.x, self.rect.y-32, 32, 64)

self.invincibilityFrames = 20

PAGE 46
BIBILIOGRAPHY

• https://github.com/explore
• https://www.wikipedia.org/
• https://codewithcurious.com/projects/

PAGE 47

You might also like