My entry for the VimJam2 https://justayte.itch.io/pinmik-panik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
9.5 KiB

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.Surface((self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT))
self.screen = pygame.display.set_mode((self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT),pygame.RESIZABLE)
self.screenw,self.screenh = self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT
self.screenoffx,self.screenoffy = 0,0
self.resizescreenw,self.resizescreenh = self.DISPLAY_WIDTH,self.DISPLAY_HEIGHT
pygame.display.set_caption("Pinmik Panik !")
pygame.init()
pygame.mixer.init()
font = "gamedata/font.ttf"
self.fontfile = pygame.font.Font(font,32)
self.fontfilesmall = pygame.font.Font(font,16)
self.fontfilebig = pygame.font.Font(font,64)
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.datadir = lib.get_save_dir("pinmikpanik")
self.dataname = "highscore.ini"
self.settingsname = "settings.ini"
highscore = lib.loadscore(self.datadir,self.dataname)
bgm,sfx = lib.loadsettings(self.datadir,self.settingsname)
bgm,sfx = bgm/100,sfx/100
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["debug"] = False
self.globals["highscore"] = highscore
self.globals["pause"] = False
self.scaleCamera()
self.globals["bgmvolume"] = bgm
self.globals["sfxvolume"] = sfx
self.reinit_volumes()
self.pasttime = time.time()
# Je charge la scene de base
scenes.main(self)
self.sound_lib["bgm/menu.ogg"].play(-1)
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
}
}
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.VIDEORESIZE:
self.screenw,self.screenh = int(event.w),int(event.h)
self.screen = pygame.display.set_mode((self.screenw,self.screenh),pygame.RESIZABLE)
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
x,y = pygame.mouse.get_pos()
x-=self.screenoffx
y-=self.screenoffy
x/=self.resizescreenw/self.DISPLAY_WIDTH
y/=self.resizescreenh/self.DISPLAY_HEIGHT
self.inputs["mouse"]["pos"] = x,y
self.inputs["mouse"]["rel"] = pygame.mouse.get_rel() # Déplacement par rapport à la frame précédente
# Getting mouse position on camera
mx = self.inputs["mouse"]["pos"][0]*self.globals["cameraw"]/self.DISPLAY_WIDTH+self.globals["camerax"]
my = self.inputs["mouse"]["pos"][1]*self.globals["camerah"]/self.DISPLAY_HEIGHT+self.globals["cameray"]
self.inputs["mouse"]["campos"] = [mx,my]
# 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))