Coverage for rollnjump/player.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"""Module de gestion des joueurs."""
13import random as rd
15import rollnjump.conf as cf
16import rollnjump.sprites as spt
17import rollnjump.utilities as ut
19JUMP_KEYS = [ut.K_SPACE, ut.K_RETURN, ut.K_s, ut.K_u]
20"""Touches de saut des joueurs."""
21WINNER = 0
22"""Joueur gagnant."""
25class Player(ut.Sprite):
26 """
27 Gestion du joueur.
29 Attributes
30 ----------
31 images : Surface list
32 Liste des images de l'objet
33 img : int
34 Indice dans la liste d'images
35 rect : Rect
36 Rectangle de collision du joueur
37 width : int
38 largeur du joueur
39 height : int
40 hauteur du joueur
41 alive : bool
42 True si le joueur est vivant
43 pos : Vector2
44 Position du joueur
45 vel : Vector2
46 Vitesse du joueur
47 acc : Vector2
48 Accélération du joueur
49 FLAG_JUMP : bool
50 drapeau de saut
51 FLAG_JUMP_2 : bool
52 drapeau pour le double saut
53 state : str
54 état du joueur, est modifié par la prise d'item
55 timer : int
56 durée des effets d'un item
57 """
59 # pylint: disable=too-many-instance-attributes
61 def __init__(self, color="green"):
62 """
63 Initialisation du joueur.
65 Parameters
66 ----------
67 color : str, optionnel
68 La couleur du joueur parmi cf.COLORS
69 """
70 # Initialisation de la classe parent
71 # ut.add_to_group(self, cf.player_sprite)
72 super().__init__()
73 # Liste d'images de l'objet, et indice de cette liste
74 # [:] pour une copie parfaite, à cause du multijoueur pour l'instant
75 self.images = spt.img_dict["mono" + color + "_img"][:]
76 self.img = 0
77 # Création de l'objet
78 self.rect = self.images[0].get_rect()
80 # dimensions
81 self.width, self.height = cf.SIZE['normal']
83 # Est vivant
84 self.alive = True
86 # Position
87 # X : milieu de l'écran
88 # moins la largeur sur 2 pour être centré (car topleft)
89 x = cf.SCREEN_WIDTH // 2 - self.width // 2
90 y = spt.GROUND_HEIGHT - self.height
91 self.pos = ut.Vec(x, y)
92 self.rect.topleft = self.pos
94 # Vitesse
95 self.vel = ut.Vec(0, 0)
96 # Accélération
97 self.acc = ut.Vec(0, cf.G)
99 # Drapeau de disponibilité du saut
100 self.FLAG_JUMP = True
101 # Drapeau de disponibilité du second saut
102 self.FLAG_JUMP_2 = False
104 # état dans lequel est le joueur, est modifié par la prise d'item.
105 # normal, fast, slow, little, big, delay
106 self.state = "normal"
108 # Lorsqu'on prend un item, ça a une durée limitée
109 # D'où ce timer (en frames)
110 self.timer = 0
112 def jump(self):
113 """Lance le saut du personnage."""
114 if self.FLAG_JUMP:
115 self.FLAG_JUMP = False
116 self.vel.y = -cf.V_JMP
117 self.FLAG_JUMP_2 = True
118 elif self.FLAG_JUMP_2:
119 self.vel.y = -cf.V_JMP
120 self.FLAG_JUMP_2 = False
122 def move(self):
123 """Met à jour pos, vec et acc."""
124 # Gestion de l'état dans lequel on est (selon l'item mangé)
125 if self.state != "normal":
126 self.timer -= 1
127 # si le timer est fini on redevient normal
128 if self.timer == 0:
129 # l'état delay permet de devenir big avec un délai pour
130 # éviter de rentrer dans une plateforme
131 if self.state == 'delay':
132 self.change_state('big')
133 else:
134 self.end_item()
136 if self.state == "fast":
137 self.vel.x = cf.V_ITEM['fast']
138 # si on arrive aux 2/3 de l'écran ça arrête d'avancer
139 if self.pos.x > (cf.SCREEN_WIDTH * 2) // 3:
140 self.end_item()
142 elif self.state == "slow":
143 self.vel.x = cf.V_ITEM['slow']
144 # si on sort presque de l'écran ça arrête de ralentir
145 if self.pos.x < self.width:
146 self.end_item()
148 ut.update_pos_vel(self, spt.ground)
150 for item in spt.items: # Gestion de la prise d'item
151 if ut.contact(self, item):
152 self.change_state(item.type)
153 item.kill()
155 # On change le sprite du joueur
156 self.img += 0.03 * cf.SPEED
157 # Faire par fraction permet d'accélérer plus lentement les pédales
158 if int(self.img) >= len(self.images):
159 self.img = 0
161 cf.DISPLAYSURF.blit(self.images[int(self.img)], self.rect)
162 if self.in_death_position():
163 self.alive = False
165 def in_death_position(self):
166 """
167 Condition de défaite du joueur.
169 Returns
170 -------
171 bool
172 True si le joueur sort suffisamment de l'écran.
173 """
174 return(self.pos.y > cf.SCREEN_HEIGHT + 50
175 or self.pos.x + self.width < 0)
177 def change_state(self, item_type):
178 """
179 Modifie l'état après la prise d'un objet et supprime ce dernier.
181 Parameters
182 ----------
183 item : Item
184 L'objet récupéré
185 """
186 # resize le player
187 if item_type in ['little', 'big']:
188 self.resize('normal', item_type)
190 # Si quand on devient grand on collide une plateforme, on annule
191 # Et on passe en 'delay' pour l'activer un peu plus tard
192 if item_type == 'big' and ut.collide_group(self, spt.ground):
193 self.resize('big', 'normal')
194 item_type = 'delay'
196 self.state = item_type
197 self.timer = cf.ITEM_TIME[item_type]
199 def end_item(self):
200 """Retour à l'état normal."""
201 # On se remet à la bonne taille, position, etc.
202 if self.state in ['little', 'big']:
203 self.resize(self.state, 'normal')
205 # Si on était petit et qu'on redevient normal,
206 # il se peut qu'on collide une plateforme.
207 # Dans ce cas, on reste petit quelques instants
208 if self.state == 'little' and ut.collide_group(self, spt.ground):
209 self.resize('normal', 'little')
210 self.timer += cf.ITEM_TIME['delay']
211 else:
212 # On se remet dans l'état normal et on annule le FLAG_ITEM
213 self.state = "normal"
214 self.vel.x = 0
216 cf.FLAG_ITEM = False
217 cf.NEW_ITEM_TIME = cf.SECONDS + rd.randint(cf.ITEM_PROBA_MIN,
218 cf.ITEM_PROBA_MAX)
220 def resize(self, size1, size2):
221 """
222 Change la taille du joueur.
224 Parameters
225 ----------
226 size1 : str
227 La taille actuelle (parmi "little", "normal", "big")
228 size2 : str
229 La taille à atteindre
230 """
231 ut.resize_list(self.images, cf.SIZE[size2])
232 self.width, self.height = cf.SIZE[size2]
233 self.pos[0] = self.pos[0] + cf.SIZE[size1][0] // 2\
234 - cf.SIZE[size2][0] // 2
235 self.pos[1] = self.pos[1] + cf.SIZE[size1][1]\
236 - cf.SIZE[size2][1]
237 self.rect = self.images[0].get_rect()
238 self.rect.topleft = self.pos