This repository has been archived by the owner on Nov 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.pyw
285 lines (254 loc) · 14.3 KB
/
main.pyw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/usr/bin/env python
# -*- coding: utf8 -*-
from settings import *
from sprites import *
from random import randint
from os import environ, path
if __name__ == "__main__": from updater import *
else: quit()
# Tentative de chargement de la librairie Pygame, retourne un message d'erreur dans le cas contraire
try: import pygame as pg
except: input("Unable to load the Pygame library, please check that it is properly installed on this computer...")
class Game:
def __init__(self):
"""
Initialisation de la fenêtre du jeu:
"""
pg.init() # Initialisation de Pygame
pg.mixer.init() # Initialisation du son de Pygame
environ["SDL_VIDEO_CENTERED"] = '1' # Centrage de la fenêtre
pg.display.set_caption(GAME_TITLE) # Titrage de la fenêtre
pg.display.set_icon( # Définition de l'icon de la fenêtre
pg.image.load(path.join('images', 'icon.png'))
)
self.window = pg.display.set_mode((WIDTH, HEIGHT)) # Affichage de la fenêtre
self.clock = pg.time.Clock() # Définition du chronomètre (pour suivre la fluidité du jeu)
self.font_name = pg.font.match_font(FONT_NAME) # Paramêtrage du font (style d'écriture)
self.load_data() # Chargement des données
self.running = True # Comprend que le jeu est lancé
def new(self):
"""
Création d'une nouvelle partie
"""
self.all_sprites = pg.sprite.LayeredUpdates() # Création d'un groupe contenant toutes les instances d'entitées
self.platforms = pg.sprite.Group() # Création d'un groupe contenant toutes les platformes
self.clouds = pg.sprite.Group() # Création d'un groupe contenant tous les nuages
self.player = Player(self) # Création du joueur
p1 = Platform( # Création de la platforme initiale
self, 0, HEIGHT - 25, WIDTH // 7 * 5, 25, True
)
self.all_sprites.add(self.player) # Ajout du joueur dans le groupe d'objets
self.all_sprites.add(p1) # Ajout de la platforme initale dans le groupe d'entitées
self.platforms.add(p1) # Ajout de la platforme initale dans le groupe de platformes
self.score = 0 # Création du compteur de points
pg.mixer.music.load(path.join(
self.snd_directory, 'HAPPY_VICTORY! By HeatleyBros.ogg'
))
self.run() # Lancement de la partie
def run(self):
"""
Execution des differentes fonctions nécessaires au fonctionnement du jeu
C'est ici qu'est située la boucle principale de la partie !
"""
pg.mixer.music.set_volume(0.1)
pg.mixer.music.play(loops=-1)
self.playing = True
while self.playing:
self.clock.tick(FPS) # Limite l'affichage d'ips (fps) selon les réglages
self.events() # Écoute les evenements
self.update() # Met a jour les données du jeu
self.draw() # Affiche les données du jeu
pg.mixer.music.fadeout(100)
def update(self):
"""
Met a jour tout ce qui est affiché (mouvement, apparence etc...)
"""
self.all_sprites.update() # Met a jour les instances d'objets
x1 = WIDTH
if self.score + len(self.platforms) <= 1: x1 = int(WIDTH / 4 * 3)
# Apparition de nuages en font d'ecran
while len(self.clouds) < 2:
c = Cloud(
self,
randint(x1, WIDTH * 2),
randint(0, int(HEIGHT / 4)),
randint(PLATFORM_HEIGHT * 4, PLATFORM_HEIGHT * 6),
randint(PLATFORM_HEIGHT * 2, PLATFORM_HEIGHT * 4)
)
pg.sprite.spritecollide(c, self.clouds, True) # On supprime le(s) nuage(s) touché(s) par le nouveau nuage
self.clouds.add(c)
self.all_sprites.add(c)
if self.player.position.x >= CAMERA_POSITION: # Test si le joueur est a 2/3 de l'écran
player_velocity = max( # Sauvegarde du maximum entre la valeur absolue de la vélocité du joueur et "2"...
abs(self.player.velocity.x), 2 # ...pour bouger la camera quand le joueur passe par la gauche de l'écran
)
self.player.position.x -= player_velocity # Ajoute cette valeur a la "camera" pour avancer fluidement
for p in self.platforms: # Déplacement fluide des plateformes
p.rect.x -= int(player_velocity)
for c in self.clouds:
c.rect.x -= int(player_velocity / 2) # Déplacement "fluide" des nuages
# Apparition de nouvelles plateformes
while len(self.platforms) < PLATFORMS:
p = Platform(
self, # Création d'une nouvelle plateforme
randint(x1, WIDTH * GENERATION), # Coordonée sur l'axe des abscisses
randint(int((HEIGHT / 3) * 2), HEIGHT - PLATFORM_HEIGHT), # Coordonée sur l'axe des ordonnées
randint(
PLATFORM_HEIGHT * 2, PLATFORM_MAX_WIDTH), # Longeur maximum de la platforme
PLATFORM_HEIGHT # Largeur de la platforme
)
self.platforms.add(p) # Ajout de la nouvelle platforme dans le groupe de plateformes
self.all_sprites.add(p) # Ajout de la nouvelle platforme dans le groupe d'entitées
def events(self):
"""
Écoute des actions du joueur
"""
for event in pg.event.get(): # Écoute les evenements du joueur
if event.type == pg.QUIT or ( # Écoute si le joueur clique sur la croix "rouge" pour fermer le jeu
event.type == pg.KEYDOWN and
event.key == pg.K_ESCAPE # Écoute si le joueur presse "escape" pour fermer le jeu
):
if self.playing:
self.playing = False # Arrête la partie si elle est en cours
self.running = False # Arrête le jeu
def draw(self):
"""
Affichage de ce qui est a afficher
"""
self.window.fill(BACKGROUD_COLOR) # Remplie tout l'écran de noir pour repartir d'une image de base
self.all_sprites.draw(self.window) # "Dessine" tout ce qui doit être affiché
self.draw_text( # Affichage du score
f"Score : {self.score}",
PLATFORM_HEIGHT, BLACK,
WIDTH / 2, PLATFORM_HEIGHT * 2
)
pg.display.flip() # Ne change que ce qui a "bougé" entre deux images (frames) pour les fps
def draw_text(self, text, size, color, x, y):
"""
Fonction permetant d'afficher du texte de manière simple
"""
font = pg.font.Font(self.font_name, size) # Définition de l'objet font
text_surface = font.render(text, True, color) # Vrai (True) pour l'anti-aliasing
text_rect = text_surface.get_rect() # Détection de la surface occupée par le texte
text_rect.midtop = (int(x), int(y)) # Paramétrage de l'emplacement du texte
self.window.blit(text_surface, text_rect) # Affichage du texte
def show_start_screen(self):
"""
Fonction affichant l'écran de départ du jeu
"""
self.window.fill(BACKGROUD_COLOR) # Remplissage de la fenêtre en noir
if not up_to_date or not updater_up_to_date:
if not up_to_date:
self.draw_text(
f'A new version of {GAME_TITLE} may be available: {latest_version}.',
20, BLACK, WIDTH / 2, 24
)
if not updater_up_to_date:
self.draw_text(
f'A new version of the updater may be available: {updater_latest_version}.',
20, BLACK, WIDTH / 2, 24 * 2
)
self.draw_text(
f'Run the updater to download the latest version.',
20, BLACK, WIDTH / 2, 24 * 3
)
self.draw_text(GAME_TITLE, 64, WHITE, WIDTH / 2, HEIGHT / 4) # Affichage du titre du jeu
self.draw_text(
"Utilisez les fleches pour bouger !", 32, WHITE,
WIDTH / 2, HEIGHT / 2
)
self.draw_text(
"Traversez le bord gauche de l'ecran pour aller a droite.",
32, WHITE, WIDTH / 2, (HEIGHT / 2) + 32
)
self.draw_text(
f"Highscore : {self.highscore}", 32, WHITE, WIDTH / 2,
(HEIGHT / 4) + 64
)
self.draw_text(
"Appuyez sur n'importe quelle touche pour jouer...", 32,
WHITE, WIDTH / 2, (HEIGHT / 4) * 3
)
pg.display.flip() # Flip pour afficher ce qui est a afficher
pg.mixer.music.load(path.join(
self.snd_directory, 'Mii.ogg'
))
pg.mixer.music.set_volume(0.1)
pg.mixer.music.play(loops=-1)
self.wait_for_key() # Attente qu'une touche soit pressée pour finir la fonction
pg.mixer.music.fadeout(100)
def show_game_over_screen(self):
self.window.fill(BACKGROUD_COLOR)
self.draw_text("GAME OVER", 64, WHITE, WIDTH / 2, HEIGHT / 4)
self.draw_text(
f"Score : {max(self.score, 0)}", 32, WHITE, WIDTH / 2,
HEIGHT / 2
)
self.draw_text(
f"Appuyez sur n'importe quelle touche pour rejouer...",
32, WHITE, WIDTH / 2, (HEIGHT / 4) * 3
)
if self.score > self.highscore:
self.highscore = self.score
self.draw_text(
f"Nouvel highscore : {self.score} !", 32, YELLOW,
WIDTH / 2, (HEIGHT / 2) + 64
)
with open(SAVE_NAME, 'w') as f:
f.write(str(self.highscore))
else:
self.draw_text(
f"Highscore : {self.highscore}", 32, YELLOW,
WIDTH / 2, (HEIGHT / 2) + 64
)
pg.display.flip() # Flip pour afficher ce qui est a afficher
pg.mixer.music.load(path.join(
self.snd_directory, 'Mii.ogg'
))
pg.mixer.music.set_volume(0.1)
pg.mixer.music.play(loops=-1)
# Attente qu'une touche soit pressée pour finir la fonction
self.wait_for_key()
pg.mixer.music.fadeout(100)
def wait_for_key(self): # Définition de la fonction d'attente qu'une touche soit pressée
while True:
self.clock.tick(5) # Rafraichissement ralenti (5 images/s)
for event in pg.event.get():
if event.type == pg.QUIT or ( # Fermeture de la fenêtre si le joueur ne veut pas jouer
event.type == pg.KEYDOWN and
event.key == pg.K_ESCAPE
):
self.running = False
return
if event.type == pg.KEYDOWN: # Fin de l'attente quand le joueur appuie sur une touche (sauf esc)
return
def load_data(self): # Chargement des données
self.directory = path.dirname(__file__) # Sauvegarde du répertoir du jeu
img_directory = path.join( # Entrée dans le dossier de ressources
self.directory, 'images'
)
self.snd_directory = path.join(
self.directory, 'sounds'
)
self.jump_sound = pg.mixer.Sound(path.join(
self.snd_directory, 'jump.ogg'
))
self.death_sound = pg.mixer.Sound(path.join(
self.snd_directory, 'death.ogg'
))
# Chargement de l'highscore
try:
with open(SAVE_NAME, 'r') as f: # On essaye d'ouvrir le fichier de l'highscore
try: self.highscore = int(f.read()) # On prend l'highscore
except: self.highscore = 0 # Ou on prend 0
except: self.highscore = 0 # Si le fichier est introuvable on prend 0
self.spritesheet = Spritesheet(path.join( # Chargement du spritesheet du joueur
img_directory, SPRITESHEET
))
game = Game() # Création de l'instance game
game.show_start_screen() # Affichage de l'écran de départ
while game.running:
game.new() # Création et execution du jeu
if game.running: game.show_game_over_screen() # Affichage de l'écran de fin
pg.quit() # Fermeture de la fenêtre
quit() # Fermeture du programme