First commit, engine import
BIN
gamedata/assets/empty.png
Normal file
After Width: | Height: | Size: 620 B |
BIN
gamedata/assets/grid.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
gamedata/assets/gui/button/base/corner_dl.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
gamedata/assets/gui/button/base/corner_dr.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
gamedata/assets/gui/button/base/corner_ul.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
gamedata/assets/gui/button/base/corner_ur.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
gamedata/assets/gui/button/base/down.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
gamedata/assets/gui/button/base/left.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
gamedata/assets/gui/button/base/middle.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
gamedata/assets/gui/button/base/right.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
gamedata/assets/gui/button/base/up.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
gamedata/assets/gui/button/baseAct/corner_dl.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
gamedata/assets/gui/button/baseAct/corner_dr.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/gui/button/baseAct/corner_ul.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
gamedata/assets/gui/button/baseAct/corner_ur.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
gamedata/assets/gui/button/baseAct/down.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/gui/button/baseAct/left.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/gui/button/baseAct/middle.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
gamedata/assets/gui/button/baseAct/right.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/gui/button/baseAct/up.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/gui/slider/base/circle.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
gamedata/assets/gui/slider/base/left.png
Normal file
After Width: | Height: | Size: 795 B |
BIN
gamedata/assets/gui/slider/base/middle.png
Normal file
After Width: | Height: | Size: 612 B |
BIN
gamedata/assets/gui/slider/base/right.png
Normal file
After Width: | Height: | Size: 848 B |
BIN
gamedata/assets/gui/title.png
Executable file
After Width: | Height: | Size: 13 KiB |
BIN
gamedata/assets/icon.png
Normal file
After Width: | Height: | Size: 909 B |
BIN
gamedata/assets/particles/bolt/0.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
gamedata/assets/particles/bolt/1.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
gamedata/assets/particles/bolt/2.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
gamedata/assets/shadow.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
gamedata/assets/solid.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
70
gamedata/definitions.py
Normal 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
243
gamedata/game.py
Normal 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
@ -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])
|
||||
|
31
gamedata/objects/bg/backgrounddrawer.py
Normal 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))
|
23
gamedata/objects/bg/menubackground.py
Normal 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)
|
12
gamedata/objects/bg/movingbackground.py
Normal 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
|
89
gamedata/objects/button.py
Normal 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))
|
68
gamedata/objects/gameloop.py
Normal 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
@ -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)
|
||||
|
||||
|
32
gamedata/objects/menu/mainmenu.py
Normal 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))
|
51
gamedata/objects/menu/menu.py
Normal 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)
|
16
gamedata/objects/menu/optionmenu.py
Normal 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)
|
46
gamedata/objects/particles.py
Normal 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)
|
16
gamedata/objects/sliders/bgmslider.py
Normal 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
|
16
gamedata/objects/sliders/sfxslider.py
Normal 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
|
79
gamedata/objects/sliders/slider.py
Normal 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
@ -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)
|
BIN
gamedata/sounds/sfx/click.wav
Normal file
14
launcher.py
Normal 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()
|
||||
|