Hide keyboard shortcuts

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/>. 

10 

11"""Fonctions pour la boucle principale du jeu.""" 

12 

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 

25 

26 

27def main_loop(players, mouse=None): 

28 """ 

29 Applique les mises à jour nécessaires au jeu. 

30 

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. 

37 

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()) 

45 

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) 

58 

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) 

63 

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)) 

67 

68 for lang in mn.flagbutton: 

69 lang.print(mouse) 

70 

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) 

75 

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)) 

99 

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)) 

120 

121 elif cf.STATE == State.ingame: # On est en jeu 

122 

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) 

129 

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 

137 

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)) 

146 

147 # Gestion de la mort 

148 

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() 

159 

160 elif cf.STATE == State.gameover: # Menu de fin solo 

161 

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) 

183 

184 elif cf.STATE == State.gameover_multi: # Menu de fin multi 

185 

186 scre.winner_endgame() 

187 

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) 

192 

193 elif cf.STATE == State.credits: # Affichage des credits 

194 

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) 

199 

200 elif cf.STATE == State.highscore: # Affichage des meilleurs scores 

201 

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) 

222 

223 return players 

224 

225 

226def reset_world(): 

227 """ 

228 Réinitialise le monde. 

229 

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)] 

252 

253 

254def event_handling(players, event, mouse=None): 

255 """ 

256 Permet de gérer les événements. 

257 

258 Parameters 

259 ---------- 

260 players : Player list 

261 Liste des joueurs 

262 event : Event 

263 L'événement à traiter 

264 

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()) 

272 

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() 

278 

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 

290 

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) 

299 

300 if event.type == ut.MOUSEBUTTONDOWN: 

301 

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 

309 

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 

314 

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 

319 

320 elif cf.STATE == State.menu and\ 

321 mn.settings_button.click(mouse): 

322 cf.STATE = State.setup 

323 

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' 

336 

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]) 

342 

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 

353 

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 

361 

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() 

374 

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 

379 

380 elif cf.STATE == State.setup and\ 

381 mn.language_button.click(mouse): 

382 cf.STATE = State.langchange 

383 

384 elif cf.STATE == State.setup and\ 

385 mn.commands_button.click(mouse): 

386 cf.STATE = State.keyset 

387 cf.CAPT = False 

388 

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 

393 

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 

398 

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 

403 

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 

411 

412 if event.type == ut.VIDEORESIZE: # pragma: no cover 

413 ut.resize_window(event.size) 

414 

415 if event.type == ut.QUIT: # pragma: no cover 

416 ut.quit_game() 

417 

418 return players