# pyg0051_defilement_image.py ''' Reprise de pyg0051_defilement_image.py, combiné avec pyg0028_bases_mouvements.py La fluidité des déplacements a été améliorée. ''' import pygame from pygame.locals import * import os # ===== Variables globales ====================== # Variable qui continue la boucle si = 1, stoppe si = 0 continuer = 1 # Position de la personne relativement au fond nPosX = 200 # Position en X du personnage nPosY = 200 # Position en Y du personnage nDirLX = 0 # Sens de déplacement du personnage selon X. 0 => il ne bougle pas nDirRX = 0 # Sens de déplacement du personnage selon X. 0 => il ne bougle pas nDirUY = 0 # Sens de déplacement du personnage selon Y. 0 => il ne bougle pas nDirDY = 0 # Sens de déplacement du personnage selon Y. 0 => il ne bougle pas fLanceOK = True # Indique que l'on peut lancer un projectile nCount = 0 # Juste pour compter les projectiles proj = 0 # une variable qui contiendra le dernier projectile créé projFirst = 0 # une variable qui référence le premier projectile s'il existe, 0 sinon nCountProj = 0 # Compte le nombre de projectiles existant class Projectile: ################# '''Classe des projectiles, pour les rendre autonomes''' def __init__(self, nPosX, nPosY): #"""""""""""""""""""""""""""""""" global projFirst, nCount,nCountProj nCount += 1 nCountProj += 1 self.nCount = nCount self.nProjPosX = nPosX self.nProjPosY = nPosY self.precedent = 0 # il n'y a pas de précédent, car c'est le premier de la suite self.suivant = projFirst # l'ancien premier de la suite devient le suivant du premier if (projFirst != 0): projFirst.precedent = self # le précédent de l'ancien premier devient moi-même, le nouveau premier projFirst = self # Indique que ce projectile (moi-même) est le premier de la liste def __del__(self): #""""""""""""""""" # Pour détruire l'objet proprement et libérer la mémoire qu'il utilise. # Pas utile ici, juste pour information. print('Final-destruction de', self.nCount) def FinExistance(self): #"""""""""""""""""""""" # Pour changer les liens de la suite de projectiles. global projFirst, nCountProj nCountProj -= 1 # Un projectile de moins print('destruction de', self.nCount) if (self.precedent != 0): # Le projectile qui est en train d'être détruit possède un précédent self.precedent.suivant = self.suivant # change le lien 'suivant' du précédent else: # On est en train de détruire le premier projectile projFirst = self.suivant # Le suivant est le premier de la suite de projectiles if (self.suivant != 0): # Le projectile qui est en train d'être détruit possède un suivant self.suivant.precedent = self.precedent # change le lien 'precedent' du suivant # else: # On est en train de détruire le dernier de la suite. def mouvement(self): #""""""""""""""""""" # Monte le projectile d'un pixel self.nProjPosY -= 1 self.nProjPosX -= nDirRX - nDirLX fenetre.blit(projectile, (self.nProjPosX, self.nProjPosY)) if (self.suivant != 0): # Lance le mouvement du suivant self.suivant.mouvement() # Si le projectile a atteint le haut de l'écarn, il est détruit if (self.nProjPosY < -20): # Destruction de l'objet projectile print('Fin de', self.nCount) self.FinExistance() # Destruction du projectile. # Pour positionner la fenêtre Pygame. #os.environ['SDL_VIDEO_WINDOW_POS'] = '20,100' os.environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % (120, 200) # Information sur le display # https://www.pygame.org/docs/ref/display.html # Initialisation des modules de Pygame pygame.init() # Création d'une fenêtre graphique de Pygame ##fenetre = pygame.display.set_mode((640, 480)) # Permet de rendre la fenêtre de taille ajustable. fenetre = pygame.display.set_mode((640,480), RESIZABLE) # Une image pour le fond de la fenêtre fond = pygame.image.load("images/background_herbe_double.jpg").convert() perso1 = pygame.image.load("images/perso_1.png").convert_alpha() projectile = pygame.image.load("images/BouleBleue.png").convert_alpha() # Ne fonctionne pas !??? perso1.set_colorkey((255,255,255)) #Rend le blanc (valeur RGB : 255,255,255) de l'image transparent nPosYMax = 1279 # Affiche l'image dans la fenêtre fenetre.blit(fond, (-nPosX, 0)) fenetre.blit(fond, (nPosYMax-nPosX, 0)) # Affiche le personnage au-dessus de l'herbe fenetre.blit(perso1, (290, nPosY)) # Actualise la fenêtre pygame.display.flip() # Pour avoir un autorepeat si une touche est pressée. pygame.key.set_repeat(10, 3) # répétition de la touche toutes les ... [ms] # Pour définir une vitesse d'exécution, # en limitant en attendant qu'un certain temps se soit écoulé avant de continuer. myClock = pygame.time.Clock() # ================================================ # Boucle principale while continuer or (nCountProj > 0): # on attend également que tous les projectiles ont été détruits. # Boucle sur tous les événements gérés par Pygame for event in pygame.event.get(): if event.type == QUIT or event.type == KEYDOWN and event.key == K_ESCAPE: # La fenêtre a été fermée ou La touche ESC a été pressée. continuer = 0 # Indique de sortire de la boucle. if event.type == KEYDOWN: # KEYUP existe aussi # Change les coordonnées de la position de la personne if event.key == K_LEFT: nDirLX = 1 if event.key == K_RIGHT: nDirRX = 1 if event.key == K_UP: nDirUY = 1 if event.key == K_DOWN: nDirDY = 1 if (event.key == K_SPACE) and fLanceOK: fLanceOK = False # pour ne pas permettre de lancer plusieurs projecties en même temps # Adjonction d'un projectile, au début de la suite des projectiles Projectile(290 + 20, nPosY) # une variable est inutile. C'est la variable projFirst qui sera utilisée if event.type == KEYUP: # pour ne pas permettre de lancer plusieurs projectiles en même temps if event.key == K_LEFT: nDirLX = 0 if event.key == K_RIGHT: nDirRX = 0 if event.key == K_UP: nDirUY = 0 if event.key == K_DOWN: nDirDY = 0 if (event.key == K_SPACE): fLanceOK = True # Déplacement du personnage nPosX += nDirRX - nDirLX nPosY += nDirDY - nDirUY # Affiche le fond, puis la personne par-dessus fenetre.blit(fond, (-nPosX, 0)) fenetre.blit(fond, (nPosYMax-nPosX, 0)) fenetre.blit(perso1, (290, nPosY)) # Limite nPosX dans l'intervalle [0 ; 640] if (nPosX < 0): nPosX += nPosYMax+1 if (nPosX > nPosYMax): nPosX -= nPosYMax+1 # Affiche les projectiles par dessus ce qui prédèce if (projFirst != 0): # Il y a un ou des projectiles projFirst.mouvement() # Met en mouvement la suite de projectiles # Actualise la fenêtre pygame.display.flip() # Limitation de la vitesse à ... images par seconde # 100 => attend que 1000 / 100 [ms] se soit écoulé depuis le dernier appel, # avant de continuer. # 100 => limite à 100 images par secondes, soit 100 exécutions de la boucle par seconde myClock.tick(200) # c.f. https://www.pygame.org/docs/ref/time.html#pygame.time.Clock.tick del proj # Inutile, permet d'afficher la variable qui contient l'objet pygame.display.quit() # ferme la fenêtre, c.f. https://www.pygame.org/docs/ref/display.html pygame.quit() # quitte pygame, c.f. https://www.pygame.org/docs/ref/pygame.html