First commit, engine import

This commit is contained in:
theo@manjaro 2021-09-10 19:22:30 +02:00
parent a05ad5553e
commit c7f5852c34
51 changed files with 885 additions and 0 deletions

BIN
gamedata/assets/empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

BIN
gamedata/assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

BIN
gamedata/assets/gui/title.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
gamedata/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
gamedata/assets/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
gamedata/assets/solid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

70
gamedata/definitions.py Normal file
View File

@ -0,0 +1,70 @@
from random import *
import sys,os,math,shutil,json
def drawcenter(game,surface,posx,posy):
# Draw a surface in its center
game.window.blit(surface,(round(posx-surface.get_width()/2),round(posy-surface.get_height()/2)))
def blit_text(pygame,surface, text, pos, font, color=[255]*4,center=False): # Blitting text with linebreaks
words = [word.split(' ') for word in text.splitlines()] # Liste qui contient tout les mots
space = font.size(' ')[0] # La largeur d'un espace
max_width, max_height = surface.get_size()
x, y = pos
linebreak = False
linesurf = pygame.Surface(surface.get_size(),pygame.SRCALPHA)
for line in words:
if linebreak:
px = 0
if center:
px = (surface.get_width()-x+space)//2
surface.blit(linesurf,(px,0))
linesurf.fill([0]*4)
x=pos[0]
y+=font.size(' ')[1]
linebreak = False
for word in line:
word_surface = font.render(word,False,color)
word_width = word_surface.get_width()
if x+word_width>surface.get_width():
px = 0
if center:
px = (surface.get_width()-x+space)//2
surface.blit(linesurf,(px,0))
linesurf.fill([0]*4)
x=pos[0]
y+=font.size(' ')[1]
linesurf.blit(word_surface,(x,y))
x+=word_width+space
linebreak = True
px = 0
if center:
px = (surface.get_width()-x+space)//2
surface.blit(linesurf,(px,0))
linesurf.fill([0]*4)
x=pos[0]
y+=font.size(' ')[1]
class Timer():
def __init__(self,maxcount):
self.maxcount = maxcount
self.timer = maxcount
self.loops = 0
def tick(self,avancement):
result = self.timer<=0
self.timer-=avancement
if result:
self.timer+=self.maxcount
self.loops+=1
return result
def getloops(self):
return self.loops
def getmax(self):
return self.maxcount
def getratio(self):
return max(min(1,self.timer/self.maxcount),0)
def reset(self):
self.timer = self.maxcount
def add(self,amount):
self.timer+=amount
self.maxcount+=amount

BIN
gamedata/font.ttf Normal file

Binary file not shown.

243
gamedata/game.py Normal file
View File

@ -0,0 +1,243 @@
import pygame, os, math, time
import gamedata.definitions as lib
import gamedata.scenes as scenes
import gamedata.objects.gameloop as gameloop
from gamedata.objects.particles import Particle
class Game():
def __init__(self):
self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT = 1280, 720
self.window = pygame.Surface((self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT))
self.realwindow = pygame.display.set_mode((self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT))
pygame.display.set_caption("VimJam2")
pygame.init()
pygame.mixer.init()
font = "gamedata/font.ttf"
self.fontfile = pygame.font.Font(font,25)
self.fontfilesmall = pygame.font.Font(font,18)
self.fontfilebig = pygame.font.Font(font,60)
self.logs = []
self.running = True
self.init_inputs()
self.gameloop = gameloop.GameLoop() # Je crée une boucle de jeu
def load_image(filename):
return pygame.image.load(filename).convert_alpha()
self.sprite_lib = self.init_assets("gamedata/assets/",load_image) # Dico qui contient chaques images du dossier assets
pygame.display.set_icon(self.sprite_lib["icon.png"])
self.sound_lib = self.init_assets("gamedata/sounds/",pygame.mixer.Sound) # Pareil, mais pour les musiques / sons
self.sound_volumes = {}
for i in self.sound_lib.keys():
self.sound_volumes[i] = 1
self.spriteLists = {} # Tiendra des listes préarrangées
self.scenes = scenes # Je stoque mes modules à l'intérieur de ma classe pour y avoir accès partout
self.scene = None
self.lib = lib
self.pygame = pygame
self.math = math
self.elapsedtime = 0
self.globals = {} # Un dico pour ranger toute les valeurs globales, pour communiquer entre objets par exemples
self.globals["camerax"] = 0
self.globals["cameray"] = 0
self.globals["scamerax"] = 3
self.globals["scameray"] = 0
self.globals["players"] = []
self.globals["hitpose"] = False
self.scaleCamera()
settings = {"sfx":1,"bgm":1}
self.globals["bgmvolume"] = settings["bgm"]
self.globals["sfxvolume"] = settings["sfx"]
self.reinit_volumes()
self.pasttime = time.time()
# Je charge la scene de base
scenes.main(self)
def set_camera(self,posx,posy):
self.globals["camerax"], self.globals["cameray"] = posx,posy
def log(*args):
args[0].logs.append(" ".join(args[1:]))
print(" ".join(args[1:]))
def reinit_volumes(self):
for i in self.sound_lib.keys(): # J'applique de base les volumes
if i.startswith("sfx/"):
self.sound_lib[i].set_volume(self.globals["sfxvolume"]*self.sound_volumes[i])
if i.startswith("bgm/"):
self.sound_lib[i].set_volume(self.globals["bgmvolume"]*self.sound_volumes[i])
def set_volume(self,sound,newvolume):
self.sound_volumes[sound] = newvolume
self.reinit_volumes()
def game_loop(self):
self.dt = time.time()-self.pasttime
self.elapsedtime += self.dt
self.pasttime = time.time()
self.check_events() # Détecte les entrées clavier
self.window.fill((0)*3) # Remplis l'écran de noir
if self.gameloop: # Si j'ai une boucle de jeu, la lancer
self.gameloop.step(self) # La logique de la boucle
self.gameloop.draw(self) # L'affichage de la boucle
if self.scene :
self.scene(self)
self.scene = False
pygame.display.update() # Mettre à jour l'affichage
def init_inputs(self):
self.inputs = {}
self.inputs["unicode"] = ""
self.inputs["mouse"] = {
"pos" : [0,0], # Position
"rel" : [0,0], # Mouvement relatif
"click" : 0 # Timer du click
}
self.inputs["keys"] = {
"escape":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_ESCAPE # Code pygame de la touche en question
},
"backspace":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_BACKSPACE # Code pygame de la touche en question
},
"enter":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_RETURN # Code pygame de la touche en question
},
"left":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_q # Code pygame de la touche en question
},
"right":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_d # Code pygame de la touche en question
},
"up":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_z # Code pygame de la touche en question
},
"down":{
"timer" : 0, # Timer de la touche
"realtime" : 0, # Temps réel préssé
"pressed" : False,
"keycode" : pygame.K_s # Code pygame de la touche en question
}
}
self.no_unicode = [pygame.K_ESCAPE,pygame.K_BACKSPACE,pygame.K_RETURN]
def check_events(self):
self.inputs["unicode"] = ""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN:
for i in self.inputs["keys"].keys():
if event.key == self.inputs["keys"][i]["keycode"]: # Vérifie si une des touches du dico est préssée
self.inputs["keys"][i]["pressed"] = True
else:
if event.key not in self.no_unicode:
self.inputs["unicode"] = event.unicode # Je récupère la "lettre" de la touche préssée
if event.type == pygame.KEYUP:
for i in self.inputs["keys"].keys():
if event.key == self.inputs["keys"][i]["keycode"]: # Vérifie si une des touches du dico est préssée
self.inputs["keys"][i]["pressed"] = False
self.inputs["mouse"]["pos"] = pygame.mouse.get_pos() # Position
self.inputs["mouse"]["rel"] = pygame.mouse.get_rel() # Déplacement par rapport à la frame précédente
# Augmente le timer si la touche est préssée, le reset sinon
for i in self.inputs["keys"].keys():
if self.inputs["keys"][i]["pressed"]:
self.inputs["keys"][i]["timer"]+=1
self.inputs["keys"][i]["realtime"]+=self.dt
else:
self.inputs["keys"][i]["timer"]=0
self.inputs["keys"][i]["realtime"]=0
# Timer du click
boutons = pygame.mouse.get_pressed()
if boutons[0]: # Si click gauche
self.inputs["mouse"]["click"]+=1
else:
self.inputs["mouse"]["click"] = 0
def init_assets(self,path,function,recursive=True):
dico = {}
self.scan_dir(path,path,dico,function,recursive)
return dico
def scan_dir(self,dirpath,origin,dico,function,recursive=True):
scanner = os.scandir(path=dirpath)
for i in scanner: # Je passe à travers toutes les données d'un dossier, fichiers et sous dossiers compris
# i.path est le chemin du fichier, par exemple
# Si c'est une image, je l'importe et l'ajoute à la librairie
finalpath = i.path.replace("\\","/")
if i.is_file() or not recursive:
finalpath = finalpath.replace(origin,'') # J'enleve l'origine (dans ce cas 'assets/' car c'est redontant, tout les sprites sont dedans
dico[finalpath] = function(i.path)
# Si c'est un dossier, je répete l'opération mais à l'intérieur de celui ci
if i.is_dir() and recursive:
self.scan_dir(i.path,origin,dico,function,recursive)
scanner.close()
def getSpriteDir(self,directory,ext=".png",assetdir="sprite_lib"):
keys = (directory,ext,assetdir)
assetdir = getattr(self,assetdir) # Si je ne précise pas quel type de ressource, je cherche dans mes sprites
if keys in self.spriteLists.keys():
return self.spriteLists[keys]
else:
# Organise les sprites
sprite_list = []
index = 0
while directory+str(index)+ext in assetdir.keys():
sprite_list.append(assetdir[directory+str(index)+ext])
index+=1
# Le stoque pour éviter de les réorganiser à chaque fois
self.spriteLists[keys] = sprite_list
return sprite_list
def addParticle(self,sprites,posx,posy,velx=0,vely=0,modvelx=0,modvely=0,flipx=False,flipy=False,fps=15):
p = Particle(self,sprites,posx,posy,velx,vely,modvelx,modvely,flipx,flipy,fps)
self.gameloop.summon(p)
def scaleCamera(self,neww=None,newh=None):
if not neww:
neww=self.DISPLAY_WIDTH
if not newh:
newh=self.DISPLAY_HEIGHT
self.globals["cameraw"] = neww
self.globals["camerah"] = newh
self.globals["tempsubsurface"] = pygame.Surface((neww,newh))

18
gamedata/objects/base.py Normal file
View File

@ -0,0 +1,18 @@
import pygame
class BaseObject():
def __init__(self,x,y,game,w=10,h=10):
self.rect = pygame.Rect([x,y,w,h])
self.baserect = self.rect.copy()
self.game = game
self.sprite = game.sprite_lib["icon.png"]
self.spriteoffset = 0,0
self.depth = 1 # Sa "profondeur", déterminera l'odre d'affichage des objets
def step(self):
pass
def draw(self):
if self.sprite:
self.game.window.blit(self.sprite,self.rect[:2])

View File

@ -0,0 +1,31 @@
from gamedata.objects.base import BaseObject
class BackgroundDrawer(BaseObject):
def __init__(self,x,y,game,w,h,sprite,ratio):
super().__init__(x,y,game,w,h)
self.ratio = ratio
self.depth = -1
self.fill(sprite) # Générer notre sprite de l'objet, le remplissant avec le sprite argument
def fill(self,sprite):
game = self.game
self.tilew = sprite.get_width()
self.tileh = sprite.get_height()
nbw = round(self.rect[2]/self.tilew+1.5)
nbh = round(self.rect[3]/self.tileh+1.5)
sw = nbw*self.tileh
sh = nbh*self.tileh
self.sprite = game.pygame.Surface((sw,sh),game.pygame.SRCALPHA)
for i in range(nbw):
for j in range(nbh):
self.sprite.blit(sprite,(i*self.tilew,j*self.tileh))
def draw(self):
game = self.game
# Affichage du sprite de mannière répétée
px = (self.rect[0]-game.globals["camerax"]*self.ratio)%self.tilew
py = (self.rect[1]-game.globals["cameray"]*self.ratio)%self.tileh
game.window.blit(self.sprite,(self.baserect[0]+px-self.tilew,self.baserect[1]+py-self.tileh))

View File

@ -0,0 +1,23 @@
from gamedata.objects.bg.backgrounddrawer import BackgroundDrawer
class MenuBackground(BackgroundDrawer):
def __init__(self,game):
super().__init__(0,0,game,game.DISPLAY_WIDTH,game.DISPLAY_HEIGHT,game.sprite_lib["grid.png"],0.025)
# Initialise son sprite
shadow = game.sprite_lib["shadow.png"]
self.shadow = game.pygame.transform.scale(shadow,(1500,1500)) # J'augmente la taille de l'ombre
def step(self):
game = self.game
super().step()
destx = (game.inputs["mouse"]["pos"][0]-game.DISPLAY_WIDTH/2)
desty = (game.inputs["mouse"]["pos"][1]-game.DISPLAY_HEIGHT/2)
game.globals["camerax"] += (destx-game.globals["camerax"])/6
game.globals["cameray"] += (desty-game.globals["cameray"])/6
def draw(self):
game = self.game
super().draw()
game.lib.drawcenter(game,self.shadow,game.DISPLAY_WIDTH/2,game.DISPLAY_HEIGHT*3/5)

View File

@ -0,0 +1,12 @@
from gamedata.objects.bg.backgrounddrawer import BackgroundDrawer
class MovingBackground(BackgroundDrawer):
def __init__(self,x,y,game,w,h,sprite,ratio,spdx,spdy):
super().__init__(x,y,game,w,h,sprite,ratio)
self.spdx = spdx
self.spdy = spdy
def step(self):
self.rect[0]+=self.spdx
self.rect[1]+=self.spdy

View File

@ -0,0 +1,89 @@
import gamedata.objects.base as base
class Button(base.BaseObject):
def __init__(self,x,y,game,w=100,h=64,folder="base",folderact="baseAct"):
super().__init__(x,y,game,w,h) # initialise l'objet de base avec les bons arguments
self.text = "Hello"
self.spritenon = self.gensprite(w,h,folder)
self.spriteact = self.gensprite(w,h,folderact)
self.sfx = game.sound_lib["sfx/click.wav"]
self.trigger = False
self.collision = False
def click(self,game):
print("hello world ! ")
self.click = click
self.skip = False # Si je passe l'effet sonore de base
def gensprite(self,w,h,foldername):
game = self.game
# Initialisation des parties de sprites
sprites = {}
for i in ("middle","left","right","up","down","corner_ul","corner_ur","corner_dl","corner_dr"):
sprites[i] = game.sprite_lib["gui/button/"+foldername+"/"+i+".png"] # Je récupère tout les sprites correspondant aux boutons
basewidth = w-sprites["left"].get_width()-sprites["right"].get_width() # Largeur du sprite du milieu
baseheight = h-sprites["up"].get_height()-sprites["down"].get_height() # Hauteur du sprite du milieu
for i in ("left","right"):
sprites[i] = base.pygame.transform.scale(sprites[i],(sprites[i].get_width(),baseheight))
for i in ("up","down"):
sprites[i] = base.pygame.transform.scale(sprites[i],(basewidth,sprites[i].get_height()))
# Initialisation de son sprite
finalsprite = base.pygame.Surface((w,h))
# Bordures haut et bas
finalsprite.blit(sprites["up"],(sprites["left"].get_width(),0))
finalsprite.blit(sprites["down"],(sprites["left"].get_width(),sprites["up"].get_height()+baseheight))
# Bordures gauche et droite
finalsprite.blit(sprites["left"],(0,sprites["up"].get_height()))
finalsprite.blit(sprites["right"],(sprites["left"].get_width()+basewidth,sprites["up"].get_height()))
# Coins du bouton
# Coins du bas
sprites["corner_dr"] = base.pygame.transform.scale(sprites["corner_dr"],(sprites["right"].get_width(),sprites["down"].get_height()))
finalsprite.blit(sprites["corner_dr"],(sprites["left"].get_width()+basewidth,sprites["up"].get_height()+baseheight))
sprites["corner_dl"] = base.pygame.transform.scale(sprites["corner_dl"],(sprites["left"].get_width(),sprites["down"].get_height()))
finalsprite.blit(sprites["corner_dl"],(0,sprites["up"].get_height()+baseheight))
# Coins du haut
sprites["corner_ur"] = base.pygame.transform.scale(sprites["corner_ur"],(sprites["right"].get_width(),sprites["up"].get_height()))
finalsprite.blit(sprites["corner_ur"],(sprites["left"].get_width()+basewidth,0))
sprites["corner_ul"] = base.pygame.transform.scale(sprites["corner_ul"],(sprites["left"].get_width(),sprites["up"].get_height()))
finalsprite.blit(sprites["corner_ul"],(0,0))
# Sprite du milieu
finalsprite.blit(base.pygame.transform.scale(sprites["middle"],(basewidth,baseheight)),(sprites["left"].get_width(),sprites["up"].get_height()))
return finalsprite
def step(self):
game = self.game
# Je vérifie si mon curseur de souris est dans le rectangle de l'objet
self.collision = True
nb = len(self.rect)//2 # Le nombre de dimensions, dans ce cas 2
for i in range(nb):
self.collision = self.collision and self.rect[i]<=game.inputs["mouse"]["pos"][i]<=self.rect[i+nb]+self.rect[i]
if self.collision and game.inputs["mouse"]["click"]==1:
self.trigger = True
if self.trigger:
self.click(self,game)
if self.skip:
self.skip = False
else:
self.sfx.play()
self.trigger = False
def draw(self):
game = self.game
# J'utilise le sprite special selection quand j'ai la souris dessus
self.sprite = self.spritenon
if self.collision:
self.sprite = self.spriteact
super().draw()
# Affichage du texte centré
value = 150
if self.collision: # Eclaircissement du texte
value+=75
img = game.fontfile.render(self.text, False, [value]*4)
posx = self.rect[0]+self.rect[2]/2-img.get_width()/2
posy = self.rect[1]+self.rect[3]/2-img.get_height()/2
self.game.window.blit(img, (posx, posy))

View File

@ -0,0 +1,68 @@
class GameLoop():
def __init__(self):
self.reinit()
def reinit(self):
# Réinitialise la boucle de jeu
self.objects = {}
self.maxid = 0
def summon(self,obj):
# Ajoute un objet à la boucle de jeu
obj.id = self.maxid # Donne un identifiant unique à l'objet
self.objects[self.maxid] = obj # Ajoute l'objet à la boucle
self.maxid+=1 # Change le prochain id disponible
return obj # Retourne l'objet stocké, au cas ou !!!!
def findname(self,name):
# Retournes tout les objets portants ce nom
result = []
for i in self.objects.values():
if type(i).__name__==name: # Si le nom de la classe correspond au nom donné, je retourne la classe
result.append(i)
return result
def delid(self,id):
# Supprime un objet à partir de son id
del(self.objects[id])
def delname(self,name):
# Supprimes les objet à partir d'un nom
for i in self.findname(name):
self.delid(i.id)
def step(self,game):
# Addoucie le secouement de la caméra
for i in ["x","y"]:
game.globals["scamera"+i]-=game.dt*5
game.globals["scamera"+i]= max(0,game.globals["scamera"+i])
objs = list(self.objects.values())
for i in objs:
i.step()
def draw(self,game):
#Je secoue ma caméra
vx = game.globals["scamerax"]
vy = game.globals["scameray"]
rx = game.lib.random()*2*vx-vx
ry = game.lib.random()*2*vy-vy
game.globals["camerax"]+=rx
game.globals["cameray"]+=ry
# Je dessine
values = list(self.objects.values())
tri = lambda x: x.depth # Donne la profondeur de l'objet
values.sort(key=tri)
for i in values:
i.draw() # Lancer le script d'affichage de chaques objets
# Je stabilise la caméra
game.globals["camerax"]-=rx
game.globals["cameray"]-=ry
# Get the right ratio
widthratio = game.DISPLAY_WIDTH/game.globals["cameraw"]
heightratio = game.DISPLAY_HEIGHT/game.globals["camerah"]
game.globals["tempsubsurface"].blit(game.window,[0,0])
temp = game.pygame.transform.scale(game.globals["tempsubsurface"],(game.DISPLAY_WIDTH,game.DISPLAY_HEIGHT))
game.realwindow.blit(temp,[0,0])

37
gamedata/objects/info.py Normal file
View File

@ -0,0 +1,37 @@
from gamedata.objects.base import BaseObject
class Info(BaseObject):
def __init__(self,game,message,color=[255]*3,temps=1):
super().__init__(0,0,game,game.DISPLAY_WIDTH,game.DISPLAY_HEIGHT)
self.timer = game.lib.Timer(temps)
self.depth = 999
self.txtSurface = game.fontfilebig.render(message,False,color)
self.blackSurface = game.pygame.Surface((game.DISPLAY_WIDTH,game.DISPLAY_HEIGHT))
self.blackSurface.fill([0]*3)
self.blackSurface.set_alpha(100)
def step(self):
game = self.game
self.timer.tick(game.dt)
if self.timer.getloops()>1:
game.gameloop.delid(self.id)
def draw(self):
game = self.game
self.txtSurface.set_alpha(255)
self.blackSurface.set_alpha(255)
if self.timer.getloops()==1:
alpha = min(1,self.timer.getratio())
self.txtSurface.set_alpha(alpha*100)
self.blackSurface.set_alpha(alpha*255)
game.window.blit(self.blackSurface,[0,0])
game.lib.drawcenter(game,self.txtSurface,game.DISPLAY_WIDTH/2,game.DISPLAY_HEIGHT/2)

View File

@ -0,0 +1,32 @@
import gamedata.objects.menu.menu as menu
class MainMenu(menu.Menu):
def __init__(self,x,y,game,w=100,h=100):
super().__init__(x,y,game,w,h) # initialise l'objet de base avec les bons arguments
# Les dicos des boutons
def fnPlay(self,game):
pass
btnPlay = {"name":"Play","function":fnPlay}
def fnOptions(self,game):
game.scene = game.scenes.options
btnOptions= {"name":"Options","function": fnOptions}
def fnQuit(self,game):
game.running = False
btnQuit= {"name":"Quit","function": fnQuit}
# Spacing between buttons
self.vpadding = 20
self.hpadding = 20
# Initialising grid
self.grid = [
[btnPlay],
[btnOptions],
[btnQuit]
]
self.create(self.grid,self.rect)
def draw(self):
# Display game title
self.game.window.blit(self.game.sprite_lib["gui/title.png"],(0,self.baserect[1]-self.game.DISPLAY_HEIGHT/8))

View File

@ -0,0 +1,51 @@
import gamedata.objects.base as base
import gamedata.objects.button as button
class Menu(base.BaseObject):
def __init__(self,x,y,game,w=100,h=100):
super().__init__(x,y,game,w,h) # initialise l'objet de base avec les bons arguments
self.init = False
# Initialisation de son sprite
self.sprite = None
# Variables de styles
self.hpadding = 2 # Les espaces entre les différents boutons
self.vpadding = 2
# Liste qui se remplira avec les objets bouttons
self.lbuttons = []
# Les dicos des boutons
def fnExemple(self,game):
print("Exemple")
btnExemple = {"name":"Bouton !!","function": fnExemple}
# Initialisation de la grille du menu
self.grid = [
[btnExemple],
[btnExemple,None]
]
def create(self,grid,rect):
game = self.game
elementheight = (rect[3]-(len(grid)-1)*self.vpadding)//len(grid)
for i in range(len(grid)):
elementwidth = (rect[2]-(len(grid[i])-1)*self.hpadding)//len(grid[i])
for j in range(len(grid[i])):
posx = rect[0]+j*(elementwidth+self.hpadding)
posy = rect[1]+i*(elementheight+self.vpadding)
if type(grid[i][j]).__name__=="dict":
# Si c'est un dico, l'emplacement est un bouton
folder = "base"
if "folder" in grid[i][j].keys():
folder = grid[i][j]["folder"]
btn = button.Button(posx,posy,game,elementwidth,elementheight,folder)
btn.text = grid[i][j]["name"]
btn.click = grid[i][j]["function"]
btn.menuowner = self # Le bouton a une référence à son menu
self.lbuttons.append(btn) # Je le garde en memoire
game.gameloop.summon(btn)
if type(grid[i][j]).__name__ in ("tuple","list"):
# Sinon, c'est une sous-grille
self.create(grid[i][j],[posx,posy,elementwidth,elementheight],game)

View File

@ -0,0 +1,16 @@
import gamedata.objects.menu.menu as menu
class OptionMenu(menu.Menu):
def __init__(self,x,y,game,w=100,h=100):
super().__init__(x,y,game,w,h) # initialise l'objet de base avec les bons arguments
# Les dicos des boutons
def fnRetour(self,game):
game.scene = game.scenes.main
btnRetour= {"name":"Retour","function": fnRetour}
# Initialisation de la grille du menu
self.grid = [
[btnRetour]
]
self.create(self.grid,self.rect)

View File

@ -0,0 +1,46 @@
from gamedata.objects.base import BaseObject
class Particle(BaseObject):
def __init__(self,game,sprites,posx,posy,velx=0,vely=0,modvelx=0,modvely=0,flipx=False,flipy=False,fps=15):
super().__init__(posx,posy,game)
self.vel = [velx,vely]
self.mod = [modvelx,modvely]
self.timer = game.lib.Timer(1/fps) # Les particules s'animent en 15 FPS par défaut
self.sprites = []
self.offsets = []
for i in sprites:
self.sprites.append(game.pygame.transform.flip(i,flipx,flipy))
w,h = i.get_size()
self.offsets.append([w/2,h/2])
self.alpha = 1
def step(self):
game = self.game
for j in range(2):
self.rect[j]+=self.vel[j]*game.dt*60
self.vel[j]+=self.mod[j]*game.dt*60
self.timer.tick(game.dt)
if self.timer.getloops()>=len(self.sprites): # Je me supprimme une fois l'animation finie
game.gameloop.delid(self.id)
self.alpha = max(1-(((self.timer.getloops()+1-self.timer.getratio())/len(self.sprites)))**3,0)
def draw(self):
game = self.game
spriteindex = self.timer.getloops()
posx,posy = self.rect[:2]
offx,offy = self.offsets[spriteindex]
pos = posx-offx-game.globals["camerax"],posy-offy-game.globals["cameray"]
self.sprites[spriteindex].set_alpha(self.alpha*255)
game.window.blit(self.sprites[spriteindex],pos)
self.sprites[spriteindex].set_alpha(255)

View File

@ -0,0 +1,16 @@
from gamedata.objects.sliders.slider import Slider
class BGMSlider(Slider):
def __init__(self,x,y,game,w=100,h=64,folder="base"):
super().__init__(x,y,game,w,h,folder) # initialise l'objet de base avec les bons arguments
self.currentvalue = self.getvalue()
self.posttext = " % Musique"
def change(self):
self.game.globals["bgmvolume"] = self.currentvalue/100
self.game.reinit_volumes()
def getvalue(self):
return self.game.globals["bgmvolume"]*100

View File

@ -0,0 +1,16 @@
from gamedata.objects.sliders.slider import Slider
class SFXSlider(Slider):
def __init__(self,x,y,game,w=100,h=64,folder="base"):
super().__init__(x,y,game,w,h,folder) # initialise l'objet de base avec les bons arguments
self.currentvalue = self.getvalue()
self.posttext = " % Effets Sonores"
def change(self):
self.game.globals["sfxvolume"] = self.currentvalue/100
self.game.reinit_volumes()
def getvalue(self):
return self.game.globals["sfxvolume"]*100

View File

@ -0,0 +1,79 @@
import gamedata.objects.base as base
class Slider(base.BaseObject):
def __init__(self,x,y,game,w=100,h=64,folder="base"):
super().__init__(x,y,game,w,h) # initialise l'objet de base avec les bons arguments
self.posttext = " %"
self.max = 100
self.currentvalue = self.getvalue()
self.bgsprite = self.gensprite(w,h,folder)
self.sprite = game.pygame.transform.scale(game.sprite_lib["gui/slider/"+folder+"/circle.png"],(h,h))
self.maxwidth = w-h
self.rect = [self.getvalue()/self.max*(self.maxwidth)+self.baserect[0],self.baserect[1],h,h]
self.sfx = game.sound_lib["sfx/click.wav"]
self.dragged = False
def change(self):
print("Value : "+self.currentvalue)
def getvalue(self):
return self.game.globals["sfxvolume"]*100
def postovalue(self):
self.currentvalue = (self.rect[0]-self.baserect[0])/(self.maxwidth)*self.max
def gensprite(self,w,h,folder):
game = self.game
left = game.sprite_lib["gui/slider/"+folder+"/left.png"]
left = game.pygame.transform.scale(left,(round(h/left.get_height()*left.get_width()),h))
right = game.sprite_lib["gui/slider/"+folder+"/right.png"]
right = game.pygame.transform.scale(right,(round(h/right.get_height()*right.get_width()),h))
middle = game.sprite_lib["gui/slider/"+folder+"/middle.png"]
middle = game.pygame.transform.scale(middle,(w-left.get_width()-right.get_width(),h))
surface = game.pygame.Surface((w,h),game.pygame.SRCALPHA)
surface.blit(left,(0,0))
surface.blit(middle,(left.get_width(),0))
surface.blit(right,(left.get_width()+middle.get_width(),0))
return surface
def step(self):
game = self.game
if self.rect[0]<=game.inputs["mouse"]["pos"][0]+game.globals["camerax"]<=self.rect[0]+self.rect[2]:
if self.rect[1]<=game.inputs["mouse"]["pos"][1]+game.globals["cameray"]<=self.rect[1]+self.rect[3]:
if game.inputs["mouse"]["click"]>1:
self.rect[0] = game.inputs["mouse"]["pos"][0]+game.globals["camerax"]-self.rect[3]/2
self.rect[0] = min(self.rect[0],self.baserect[0]+self.maxwidth)
self.rect[0] = max(self.rect[0],self.baserect[0])
self.dragged = True
self.postovalue()
if self.dragged and game.inputs["mouse"]["click"]==0:
# Le slider a été laché
self.change()
self.dragged = False
def draw(self):
game = self.game
game.window.blit(self.bgsprite,(self.baserect[0]-game.globals["camerax"],self.baserect[1]-game.globals["cameray"]))
game.window.blit(self.sprite,(self.rect[0]-game.globals["camerax"],self.rect[1]-game.globals["cameray"]))
txt = game.fontfile.render(str(round(self.currentvalue))+self.posttext,False,[255]*3)
px = self.baserect[0]+self.baserect[2]+50-game.globals["camerax"]
py = self.rect[1]+self.rect[3]/2-txt.get_height()/2-game.globals["camerax"]
game.window.blit(txt,[px,py])

24
gamedata/scenes.py Normal file
View File

@ -0,0 +1,24 @@
from gamedata.objects.menu.mainmenu import MainMenu
from gamedata.objects.bg.movingbackground import MovingBackground
from gamedata.objects.bg.menubackground import MenuBackground
from gamedata.objects.menu.optionmenu import OptionMenu
from gamedata.objects.sliders.bgmslider import BGMSlider
from gamedata.objects.sliders.sfxslider import SFXSlider
def main(game):
game.scaleCamera()
game.gameloop.reinit() # Je réinitialis la boucle
bg = MenuBackground(game)
menu = MainMenu(game.DISPLAY_WIDTH/4,round(game.DISPLAY_HEIGHT*3/8),game,game.DISPLAY_WIDTH//2,game.DISPLAY_HEIGHT//2)
game.gameloop.summon(bg)
game.gameloop.summon(menu)
def options(game):
game.gameloop.reinit()
game.globals["camerax"] = 0
game.globals["cameray"] = 0
s = BGMSlider(40,40,game,400,40)
s2 = SFXSlider(40,100,game,400,40)
menu = OptionMenu(round(game.DISPLAY_WIDTH/8),round(game.DISPLAY_HEIGHT*9/10),game,round(game.DISPLAY_WIDTH*6/8),round(game.DISPLAY_HEIGHT/10-game.DISPLAY_HEIGHT/30))
game.gameloop.summon(s)
game.gameloop.summon(s2)

Binary file not shown.

14
launcher.py Normal file
View File

@ -0,0 +1,14 @@
import os,sys
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): # Change le dossier d'execution si le jeu est packagé
os.chdir(sys._MEIPASS)
from gamedata.game import *
game = Game()
while game.running:
game.game_loop()
pygame.quit()