Coverage for rollnjump/gameloop.py : 100%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Roll 'n' Jump
2# Written in 2020, 2021 by Samuel Arsac, Hugo Buscemi,
3# Matteo Chencerel, Rida Lali
4# To the extent possible under law, the author(s) have dedicated all
5# copyright and related and neighboring rights to this software to the
6# public domain worldwide. This software is distributed without any warranty.
7# You should have received a copy of the CC0 Public Domain Dedication along
8# with this software. If not, see
9# <http://creativecommons.org/publicdomain/zero/1.0/>.
11"""Fonctions pour la boucle principale du jeu."""
13import os
14import random as rd
15import rollnjump.conf as cf
16from rollnjump.conf import State
17import rollnjump.utilities as ut
18import rollnjump.menu as mn
19import rollnjump.worldgen as wrld
20import rollnjump.player as plyr
21import rollnjump.lang as lg
22import rollnjump.score as scre
23import rollnjump.sprites as spt
24import rollnjump.key as ky
27def main_loop(players, mouse=None):
28 """
29 Applique les mises à jour nécessaires au jeu.
31 Parameters
32 ----------
33 players : Player list
34 Liste des joueurs
35 mouse : int * int, optionnel
36 Impose une position du curseur de la souris.
38 Returns
39 -------
40 Player list
41 Liste des joueurs actualisée
42 """
43 if mouse is None: # pragma: no cover
44 mouse = mn.scaled_mouse_pos(ut.mouse_pos())
46 if cf.STATE == State.menu: # On est dans le menu
47 cf.NB_PLAYERS = 1
48 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
49 "title.png")), (357, 132))
50 for P in rd.sample(players, len(players)):
51 P.move()
52 mn.oneplayer_button.print(mouse)
53 mn.multiplayer_button.print(mouse)
54 mn.settings_button.print(mouse)
55 mn.records_button.print(mouse)
56 mn.credits_button.print(mouse)
57 mn.sound_button.print(mouse)
59 elif cf.STATE == State.setup: # Paramètres
60 mn.language_button.print(mouse)
61 mn.return_button.print(mouse)
62 mn.commands_button.print(mouse)
64 elif cf.STATE == State.languages: # Choix de la langue (1e fois)
65 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
66 "title.png")), (357, 132))
68 for lang in mn.flagbutton:
69 lang.print(mouse)
71 elif cf.STATE == State.langchange: # Changement de la langue
72 mn.return_button.print(mouse)
73 for lang in mn.flagbutton:
74 lang.print(mouse)
76 elif cf.STATE == State.multiplayer_set: # Régler le multijoueur
77 mn.return_button.print(mouse)
78 mn.print_text(mn.MULTIMENU[cf.LANG],
79 mn.Multi_nb_pos,
80 cf.GREY,
81 ut.font(mn.FONT_PIXEL, 3 * cf.RESULT_FONT_SIZE // 4))
82 mn.start_button.print(mouse)
83 for i in range(cf.NB_PLAYERS_MAX - 1):
84 mn.multi_button[i].print(mouse, cf.NB_PLAYERS == i + 2)
85 for i in range(cf.NB_PLAYERS):
86 mn.print_image(os.path.join(
87 cf.ASSETS, "img", "mono" + cf.COLORS[i],
88 "mono" + cf.COLORS[i] + "0.png"),
89 (cf.SCREEN_WIDTH // 8 + i * cf.SCREEN_WIDTH // 4 - 50,
90 5 * cf.SCREEN_HEIGHT // 12),
91 scale=4)
92 mn.print_text(ut.keyname(plyr.JUMP_KEYS[i]),
93 (cf.SCREEN_WIDTH // 8
94 + i * cf.SCREEN_WIDTH // 4,
95 2 * cf.SCREEN_HEIGHT // 3),
96 cf.GREY,
97 ut.font(mn.FONT_PIXEL,
98 2 * cf.RESULT_FONT_SIZE // 3))
100 elif cf.STATE == State.keyset: # Changement des commandes
101 mn.return_button.print(mouse)
102 for button in ky.modifybutton:
103 button.print(mouse)
104 for i in range(cf.NB_PLAYERS_MAX):
105 mn.print_text(cf.COLORSTRAD[cf.LANG][i],
106 (370, 135 + i * 150),
107 cf.GREY,
108 ut.font(mn.FONT_PIXEL, cf.RESULT_FONT_SIZE))
109 mn.print_text(ut.keyname(plyr.JUMP_KEYS[i]),
110 (700, 135 + i * 150),
111 cf.GREY,
112 ut.font(mn.FONT_PIXEL, cf.RESULT_FONT_SIZE))
113 if cf.CAPT:
114 mn.print_image((os.path.join(cf.UI, "messagebox.png")), (189, 249))
115 mn.print_text(ky.TEXTCAPT[cf.LANG]
116 + cf.COLORSTRAD[cf.LANG][cf.CAPT_PLYR],
117 (640, 350),
118 cf.GREY,
119 ut.font(mn.FONT_PIXEL, cf.RESULT_FONT_SIZE // 2))
121 elif cf.STATE == State.ingame: # On est en jeu
123 # Décompte des secondes
124 cf.FRAMES += 1
125 if cf.FRAMES % cf.FPS == 0:
126 cf.SECONDS += 1
127 cf.SPEED += cf.ACC
128 scre.score(cf.SECONDS)
130 nb_player_alive = 0
131 # Déplacement des joueurs
132 for i, P in rd.sample(list(enumerate(players)), len(players)):
133 if P.alive:
134 P.move()
135 nb_player_alive += 1
136 plyr.WINNER = i
138 # Affichage de la commande en début de game
139 if cf.SECONDS < 3 and cf.NB_PLAYERS == 1:
140 mn.print_text(mn.INDICBUTTON[cf.LANG]
141 + ut.keyname(plyr.JUMP_KEYS[0]),
142 (cf.SCREEN_WIDTH // 2, 70),
143 cf.GREY,
144 ut.font(mn.FONT_PIXEL,
145 3 * cf.RESULT_FONT_SIZE // 4))
147 # Gestion de la mort
149 if cf.NB_PLAYERS > 1 >= nb_player_alive:
150 # Fin du mode multijoueur
151 cf.STATE = State.gameover_multi
152 cf.NEWHS = scre.maj(cf.SECONDS)
153 elif nb_player_alive == 0:
154 # Fin du mode solo
155 cf.STATE = State.gameover
156 cf.NEWHS = scre.maj(cf.SECONDS)
157 cf.NEWRC = scre.get_best_score() < cf.SECONDS
158 mn.player_name_area.select()
160 elif cf.STATE == State.gameover: # Menu de fin solo
162 scre.score_endgame(cf.SECONDS)
163 if cf.CAPT: # Demander au joueur son nom avant de MaJ le scoreboard
164 mn.print_image((os.path.join(cf.UI, "messagebox.png")), (189, 249))
165 mn.print_text(scre.NAMEASK[cf.LANG],
166 (640, 300),
167 cf.GREY,
168 ut.font(mn.FONT_PIXEL, cf.RESULT_FONT_SIZE // 2))
169 mn.player_name_area.print()
170 else:
171 if cf.NEWHS: # Nouveau record
172 if cf.NEWRC:
173 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
174 cf.LANG,
175 "highscore.png")), (428, 350))
176 else:
177 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
178 "top5mes.png")), (428, 350))
179 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
180 "gameover.png")), (395, 100))
181 mn.restart_button.print(mouse)
182 mn.return_button.print(mouse)
184 elif cf.STATE == State.gameover_multi: # Menu de fin multi
186 scre.winner_endgame()
188 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
189 "gameover.png")), (395, 100))
190 mn.restart_button.print(mouse)
191 mn.return_button.print(mouse)
193 elif cf.STATE == State.credits: # Affichage des credits
195 cf.DISPLAYSURF.blit(ut.load_image(os.path.join(cf.UI,
196 cf.LANG,
197 "credits.png")), (0, 0))
198 mn.return_button.print(mouse)
200 elif cf.STATE == State.highscore: # Affichage des meilleurs scores
202 # Récupération des meilleurs scores
203 records = scre.get_scores()
204 number_scores = len(records)
205 font_size = cf.HIGHSCORES_FONT_SIZE
206 size_height = font_size * 2 * number_scores
207 if number_scores == 0:
208 mn.print_text(mn.NOSCORES[cf.LANG], (640, 360), cf.GREY,
209 ut.font(mn.FONT_PIXEL, font_size),
210 True)
211 else:
212 for best_score in range(number_scores):
213 position_score = 10 * font_size - (size_height // 2)\
214 + best_score * 2 * font_size + font_size // 2
215 text_display = records[best_score][1] + " : "
216 text_display += str(records[best_score][0])
217 mn.print_text(text_display,
218 (640, position_score), cf.GREY,
219 ut.font(mn.FONT_PIXEL, font_size),
220 True)
221 mn.return_button.print(mouse)
223 return players
226def reset_world():
227 """
228 Réinitialise le monde.
230 Returns
231 -------
232 Player list
233 Une liste de joueurs réinitialisés de longueur NB_PLAYERS
234 """
235 # remet le monocycle à la taille normale
236 for color in cf.COLORS:
237 ut.resize_list(spt.img_dict['mono' + color + '_img'],
238 cf.SIZE['normal'])
239 cf.SPEED = cf.INITIAL_SPEED
240 cf.SECONDS = 0
241 cf.FRAMES = 0
242 cf.NEW_ITEM_TIME = rd.randint(cf.ITEM_PROBA_MIN,
243 cf.ITEM_PROBA_MAX)
244 cf.FLAG_ITEM = False
245 # efface les items, plateformes et le background
246 spt.ground = ut.group_sprite_define()
247 spt.clouds = ut.group_sprite_define()
248 spt.trees = ut.group_sprite_define()
249 spt.items = ut.group_sprite_define()
250 wrld.initgen()
251 return [plyr.Player(cf.COLORS[i]) for i in range(cf.NB_PLAYERS)]
254def event_handling(players, event, mouse=None):
255 """
256 Permet de gérer les événements.
258 Parameters
259 ----------
260 players : Player list
261 Liste des joueurs
262 event : Event
263 L'événement à traiter
265 Returns
266 -------
267 Player list
268 Renvoie la liste des joueurs mis à jour
269 """
270 if mouse is None: # pragma: no cover
271 mouse = mn.scaled_mouse_pos(ut.mouse_pos())
273 if event.type == ut.KEYDOWN:
274 if cf.STATE == State.ingame:
275 for i, P in enumerate(players):
276 if event.key == plyr.JUMP_KEYS[i]: # Saut
277 P.jump()
279 elif cf.STATE == State.keyset and cf.CAPT:
280 if event.key == ut.K_ESCAPE:
281 cf.CAPT = False
282 else:
283 if event.key in plyr.JUMP_KEYS:
284 plyr.JUMP_KEYS[plyr.JUMP_KEYS.index(event.key)] \
285 = plyr.JUMP_KEYS[cf.CAPT_PLYR]
286 plyr.JUMP_KEYS[cf.CAPT_PLYR] = event.key
287 plyr.JUMP_KEYS[cf.CAPT_PLYR] = event.key
288 ky.set_keys(plyr.JUMP_KEYS)
289 cf.CAPT = False
291 elif cf.STATE == State.gameover and cf.CAPT:
292 if event.key == ut.K_RETURN:
293 scre.PLAYER = mn.player_name_area.input
294 scre.set_best_score(cf.SECONDS)
295 cf.CAPT = False
296 mn.player_name_area.deselect()
297 else:
298 mn.player_name_area.read(event.key)
300 if event.type == ut.MOUSEBUTTONDOWN:
302 if cf.STATE == State.menu and\
303 mn.oneplayer_button.click(mouse):
304 # Clic de la souris sur le bouton "Un joueur"
305 cf.NB_PLAYERS = 1
306 players = reset_world()
307 cf.STATE = State.ingame
308 wrld.stop_ground() # Arrêt de la création du sol du menu
310 elif cf.STATE == State.menu and\
311 mn.multiplayer_button.click(mouse):
312 # Clic de la souris sur le bouton "Multi-joueur"
313 cf.STATE = State.multiplayer_set
315 elif cf.STATE == State.menu and\
316 mn.records_button.click(mouse):
317 # Clic de la souris sur le bouton "Records"
318 cf.STATE = State.highscore
320 elif cf.STATE == State.menu and\
321 mn.settings_button.click(mouse):
322 cf.STATE = State.setup
324 elif cf.STATE == State.menu and\
325 mn.sound_button.click(mouse): # pragma: no cover
326 if cf.FLAG_MUSIC:
327 cf.FLAG_MUSIC = False
328 ut.pause_music()
329 mn.sound_button.image = 'soundoff.png'
330 mn.sound_button.image_hover = 'soundoffpushed.png'
331 else:
332 cf.FLAG_MUSIC = True
333 ut.unpause_music()
334 mn.sound_button.image = 'soundon.png'
335 mn.sound_button.image_hover = 'soundonpushed.png'
337 elif cf.STATE == State.languages:
338 for i in range(len(mn.flagbutton)):
339 if mn.flagbutton[i].click(mouse):
340 cf.STATE = State.menu
341 lg.set_lang(lg.AVAILABLE[i])
343 elif cf.STATE == State.multiplayer_set:
344 for i in range(cf.NB_PLAYERS_MAX - 1):
345 if mn.multi_button[i].click(mouse):
346 cf.NB_PLAYERS = i + 2
347 if mn.return_button.click(mouse):
348 cf.STATE = State.menu
349 if mn.start_button.click(mouse):
350 players = reset_world()
351 cf.STATE = State.ingame
352 wrld.stop_ground() # Arrêt de la création du sol du menu
354 elif cf.STATE == State.langchange:
355 for i in range(len(mn.flagbutton)):
356 if mn.flagbutton[i].click(mouse):
357 cf.STATE = State.setup
358 lg.set_lang(lg.AVAILABLE[i])
359 if mn.return_button.click(mouse):
360 cf.STATE = State.setup
362 elif cf.STATE == State.gameover or\
363 cf.STATE == State.gameover_multi:
364 if mn.return_button.click(mouse):
365 # Clic de la souris sur le bouton "Retour"
366 cf.NB_PLAYERS = 1
367 players = reset_world()
368 cf.STATE = State.menu
369 if mn.restart_button.click(mouse):
370 # Clic sur recommencer, on réinitialise le monde
371 players = reset_world()
372 cf.STATE = State.ingame
373 wrld.stop_ground()
375 elif cf.STATE == State.highscore and\
376 mn.return_button.click(mouse):
377 # Clic de la souris sur le bouton "Records"
378 cf.STATE = State.menu
380 elif cf.STATE == State.setup and\
381 mn.language_button.click(mouse):
382 cf.STATE = State.langchange
384 elif cf.STATE == State.setup and\
385 mn.commands_button.click(mouse):
386 cf.STATE = State.keyset
387 cf.CAPT = False
389 elif cf.STATE == State.setup and\
390 mn.return_button.click(mouse):
391 # Clic de la souris sur le bouton "Retour"
392 cf.STATE = State.menu
394 elif cf.STATE == State.credits and\
395 mn.return_button.click(mouse):
396 # Clic de la souris sur le bouton "Retour"
397 cf.STATE = State.menu
399 elif cf.STATE == State.menu and\
400 mn.credits_button.click(mouse):
401 # Clic de la souris sur le bouton "Retour"
402 cf.STATE = State.credits
404 elif cf.STATE == State.keyset:
405 if mn.return_button.click(mouse):
406 cf.STATE = State.setup
407 for i in range(len(ky.modifybutton)):
408 if ky.modifybutton[i].click(mouse):
409 cf.CAPT = True
410 cf.CAPT_PLYR = i
412 if event.type == ut.VIDEORESIZE: # pragma: no cover
413 ut.resize_window(event.size)
415 if event.type == ut.QUIT: # pragma: no cover
416 ut.quit_game()
418 return players