I'm learning pygame with this mummy games, but the movement of the player is not responding as wanted. Sometimes, it work, sometimes, it continues to move even if the key has been released. Why pygame does not detect all the times when I release or push my arrow keys ? Thanks for any help. The way the arrow keys are used is described in "game", end of the "update" methode.
Main :
"""
Created on Mon Jun 14 09:54:56 2021
@author: Graven
"""
import pygame as pg
import math
from game import Game
pg.init() # charger les composants de pygame
clock = pg.time.Clock()
# Générer la fenêtre du jeu
screenSize = (1080, 720)
pg.display.set_caption('Comet fall game') #(title, icontitle) Définir le titre de la fenêtre
screen = pg.display.set_mode(screenSize) # (size, flag...) taille de la fenêtre
# Importer l'arrière plan
background = pg.image.load('assets/bg.jpg')
# Importer la bannière
banner = pg.image.load('assets/banner.png')
banner = pg.transform.scale(banner, (500, 500))
banner_rect = banner.get_rect()
banner_rect.x = math.ceil(screen.get_width() / 4)
# importerle bouton pour lancer la partie
play_button = pg.image.load('assets/button.png')
play_button = pg.transform.scale(play_button, (400, 150))
play_button_rect = play_button.get_rect()
play_button_rect.x = math.ceil(screen.get_width() / 3.33)
play_button_rect.y = math.ceil(screen.get_height() / 2)
# Charger le jeu
game = Game()
running = True # jeu en cours d'execution
# Boucle tant que running est vrai
while running :
# pg.time.delay(10)
# Appliquer l'arrière plan du jeu
screen.blit(background, (-1000, -200)) # injecter l'image sur l'écran
# Vérifier si notre jeu a commencé ou non
if game.is_playing:
# Déclencher les instructions de la partie
game.update(screen, screenSize)
# Vérifier si le jeu n'a pas encore commencé
else :
# Ajouter l'écran de bienvenue
screen.blit(play_button, play_button_rect)
screen.blit(banner,banner_rect)
# mettre à jour l'écran
pg.display.flip()
# clock.tick(1000)
# si le joueur ferme cette fenetre ou click sur start
for event in pg.event.get(): # reprendre tous les évenements possibles
# vérifier que l'evenement est fermeture de fenetre
if event.type == pg.QUIT :
running = False
pg.quit()
elif event.type == pg.MOUSEBUTTONDOWN:
# Vérification pour savoir si le curseur est en collision avec le boutton
if play_button_rect.collidepoint(event.pos):
# mettre le jeu en mode "lancé"
game.start()
Game :
"""
Created on Mon Jun 14 10:40:05 2021
@author: Graven
"""
import pygame as pg
from player import Player
from monster import Monster
clock = pg.time.Clock()
# Créer une seconde classe qui représente le jeu
class Game :
def __init__(self):
# Définir si le jeu a commencé ou non
self.is_playing = False
# Générer notre joueur
self.all_players = pg.sprite.Group() # Uniquement pour la fonction collision qui vérifie un sprite avec un groupe
self.player = Player(self)
self.all_players.add(self.player)
# Enregistrer toutes les touches actionnées
self.pressed = {}
# Groupe de monstre
self.all_monsters = pg.sprite.Group()
self.k=0
def start(self):
# lors d'une nouvelle partie, respawn des monstres
self.is_playing = True
# self.spawn_monster()
# self.spawn_monster()
def game_over(self):
# Remettre le jeu à neuf, retirer les monstres, remettre 100 pv et jeu en attente
self.all_monsters = pg.sprite.Group()
self.player.health = self.player.max_health
self.is_playing = False
def update(self, screen, screenSize):
# Appliquer l'image du joueur
screen.blit(self.player.image, self.player.rect)
# Visualiser la barre de vie du joueur
self.player.update_health_bar(screen, self.player.chargeState)
# Récupérer les projectiles du joueur
for projectile in self.player.all_projectile:
projectile.move()
# Récupérer les monstres du jeu
for monster in self.all_monsters:
monster.forward()
monster.update_health_bar(screen)
# Appliquer l'ensemble des images de mon groupe de projectiles
self.player.all_projectile.draw(screen)
# Appliquer l'ensemble des images de mon groupe de monstre
self.all_monsters.draw(screen)
# Charge du projectile
if self.player.charge_projectile:
self.player.chargeState += 1
else:
self.player.chargeState = 0
# Vérifier si le joueur souhaite se déplacer
if self.pressed.get(pg.K_RIGHT) and self.player.rect.x < screenSize[0] - self.player.rect.width:
self.player.move_right()
elif self.pressed.get(pg.K_LEFT) and self.player.rect.x > 0:
self.player.move_left()
# si le joueur réalise un évenement
for event in pg.event.get(): # reprendre tous les évenements possibles
# vérifier que l'evenement est fermeture de fenetre
if event.type == pg.QUIT :
pg.quit()
# Détecter si un joueur lache une touche du clavier
elif event.type == pg.KEYDOWN:
self.pressed[event.key] = True
# Détecter si espace est enclenché pour lancer le projectile
if event.key == pg.K_SPACE:
self.player.charge_projectile = True
elif event.type == pg.KEYUP and self.player.charge_projectile :
self.player.launch_projectile()
self.player.charge_projectile = False
self.pressed[event.key] = False
elif event.type == pg.KEYUP :
self.pressed[event.key] = False
# self.k += 1
# print(self.k, self.pressed)
def check_collision(self, sprite, group):
return pg.sprite.spritecollide(sprite, group, False, pg.sprite.collide_mask)
def spawn_monster(self):
monster = Monster(self)
self.all_monsters.add(monster)
Player :
"""
Created on Mon Jun 14 10:39:16 2021
@author: Graven
"""
import pygame as pg
from projectile import Projectile
# Créer une première classe qui représente le joueur
class Player(pg.sprite.Sprite) :
def __init__(self, game):
super().__init__()
self.game = game
self.health = 100
self.max_health = 100
self.chargeState = 0
self.attack = 0.5
self.max_charge = 100
self.velocity = 3
self.image = pg.image.load('assets/player.png')
self.rect = self.image.get_rect()
self.rect.x = 450
self.rect.y = 500
self.all_projectile = pg.sprite.Group()
self.charge_projectile = False
def damage(self, amout):
self.health -= amout
if self.health <= 0 :
self.game.game_over()
def move_right(self):
# si le joueur n'est pas en collision avec un monstre
if not self.game.check_collision(self, self.game.all_monsters):
self.rect.x += self.velocity
def move_left(self):
self.rect.x -= self.velocity
def launch_projectile(self):
# Créer une nouvelle instance de la classe projectile
self.all_projectile.add(Projectile(self))
def update_health_bar(self, surface, max_charge):
# Définir une couleur pour la jauge de vie(vert) et son arrière plan (gris)
if max_charge < self.max_charge :
bar_color = (111, 210, 46)
else:
bar_color = (255, 128, 0)
back_bar_color = (60, 63,60)
# Définir la position de la jauge de vie et sa largeur/épaisseur
bar_position = [self.rect.x +50, self.rect.y + 20, self.health, 7] # Définir la position de l'arrière plan dela jauge
back_bar_position = [self.rect.x + 50, self.rect.y + 20, self.max_health, 7]
# Dessiner la barre de vie
pg.draw.rect(surface, back_bar_color, back_bar_position)
pg.draw.rect(surface, bar_color, bar_position)
Monster
# -*- coding: utf-8 -*-
"""
Created on Mon Jun 14 18:48:46 2021
@author: Graven
"""
import pygame as pg
import random
# Création d'une classe qui gère la notion de monstre
class Monster(pg.sprite.Sprite):
def __init__(self, game):
self.game = game
super().__init__()
self.max_health = 60 + random.randint(0,60)
self.health = self.max_health
self.attack = 0.3
self.image = pg.image.load('assets/mummy.png')
self.rect = self.image.get_rect()
self.rect.x = 1080 + random.randint(0, 300)
self.rect.y = 540
self.velocity = random.randint(1,3)
def damage(self, amount):
self.health -= amount
if self.health <= 0 :
# Réapparaitre comme un nouveau monstre
self.rect.x = 1080 + random.randint(0, 300)
self.max_health = 60 + random.randint(0,60)
self.health = self.max_health
self.velocity = random.randint(1,3)
def update_health_bar(self, surface):
# Définir une couleur pour la jauge de vie(vert) et son arrière plan (gris)
bar_color, back_bar_color = (111, 210, 46), (60, 63,60)
# Définir la position de la jauge de vie et sa largeur/épaisseur
bar_position = [self.rect.x + 10, self.rect.y - 20, self.health, 5]
# Définir la position de l'arrière plan dela jauge
back_bar_position = [self.rect.x + 10, self.rect.y - 20, self.max_health, 5]
# Dessiner la barre de vie
pg.draw.rect(surface, back_bar_color, back_bar_position)
pg.draw.rect(surface, bar_color, bar_position)
def forward(self):
# si le monster n'est pas en collision avec le joueur
if not self.game.check_collision(self, self.game.all_players):
self.rect.x -= self.velocity
else:
# Si le monstre est en collision avec le joueur, inflige des degats
self.game.player.damage(self.attack)
Projectile :
# -*- coding: utf-8 -*-
"""
Created on Mon Jun 14 11:41:52 2021
@author: Graven
"""
import pygame as pg
# définir la classe qui gère le projectile de notre joueur
class Projectile(pg.sprite.Sprite):
#définir le constructeur
def __init__(self, player):
super().__init__()
self.velocity = 5
self.player = player
self.image = pg.image.load('assets/projectile.png')
self.rect = self.image.get_rect()
self.damage = int(self.player.attack * min(self.player.chargeState, self.player.max_charge)**1.1)
self.image = pg.transform.scale(self.image, (self.damage, self.damage))
self.rect.x = player.rect.x + 95
self.rect.y = player.rect.y + 115 - self.damage/2
self.origin_image = self.image
self.angle = 0
def rotate(self):
# Tourner le projectile
self.angle += 2
self.image = pg.transform.rotozoom(self.origin_image, self.angle, 1)
self.rect = self.image.get_rect(center = self.rect.center)
def remove(self):
self.player.all_projectile.remove(self)
def move(self):
self.rect.x += self.velocity
# self.rotate()
# centre_proj = self.rect.center
# print('centre_proj',centre_proj)
# Vérifier su le projectile entre en collision avec un monstre
for monstre_rencontre in self.player.game.check_collision(self, self.player.game.all_monsters):
# Attribuer les dégats
monstre_rencontre.damage(self.damage)
#supprimer le projectile
self.remove()
# Vérifier si le projectie n'est plus présent sur l'écran
if self.rect.x > 1080:
# Supprimer le projectile
self.remove()
pygame.event.get()
get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get()
is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
Get the events once per frame and use them in multiple loops or pass the list of events to functions and methods where they are handled:
class Game:
# [...]
def update(self, screen, screenSize, eventList):
# [...]
for event in eventList:
# [...]
while running :
eventList = pg.event.get()
# [...]
if game.is_playing:
# Déclencher les instructions de la partie
game.update(screen, screenSize, eventList)
# [...]
for event in eventList:
# [...]