# /// script # dependencies = [ # "pygame", # "pyserial", # ] # /// import os import random import pygame from serial import Serial pygame.init() arduino = Serial("/dev/ttyACM0") # Font that is used to render the text font20 = pygame.font.Font('freesansbold.ttf', 20) # RGB values of standard colors BLACK = (0, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) BLUE = (30, 144, 255) VIOLET = (148, 0, 211) # Basic parameters of the screen info = pygame.display.Info() WIDTH, HEIGHT = 900, 600 BAR_LARGEUR = HEIGHT // 8 BAR_EPAISSEUR = HEIGHT // 60 screen = pygame.display.set_mode((WIDTH, HEIGHT)) #passer en mode plein écran #WIDTH, HEIGHT = info.current_w, info.current_h #screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) pygame.display.set_caption("Pong") clock = pygame.time.Clock() FPS = 30 #fonction pour lister tous les fichiers dans un répertoire def list_files_in_directory(directory): """List all files in the given directory.""" files = [ f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) ] return files # pouvoir class Power: def __init__(self): self.actif = 0 self.count = 0 def is_activate(self): return self.actif def activate(self, power, geek, listOfGeeks, ball): self.actif = 1 #pouvour agrandir la barre if power == 1: for geek_objet in listOfGeeks: if geek_objet == geek: #agrandi la barre de +50% if geek_objet.width < geek_objet.height: geek_objet.height *= 1.5 else: geek_objet.width *= 1.5 else: #réduit la barre de +30% if geek_objet.width < geek_objet.height: geek_objet.height *= 0.7 else: geek_objet.width *= 0.7 # accélère la ball du tireur elif power == 2: ball.speed += 100 #change la direction de la balle #elif power == 3: # return #shot à chaque #elif power == 4: def desactivate(self, power, geek, listOfGeeks, ball): self.actif = 1 #pouvour barres reprennent leurs tailles initiales if power == 1: for geek_objet in listOfGeeks: #agrandi la barre de +50% if geek_objet.width < geek.height: geek_objet.height = BAR_LARGEUR else: geek_objet.width = BAR_LARGEUR # Perso class class Perso: def __init__(self, posx, posy, width, nom_perso, striker): self.posx = posx self.posy = posy self.width = width self.score = 0 self.vie = 10 self.pouvoir = 0 self.nom_perso = nom_perso self.striker = striker self.img_perso = pygame.image.load("./" + self.nom_perso + '/image/perso.png').convert_alpha() size_x = self.img_perso.get_width() size_y = self.img_perso.get_height() #conserve le ratio width/height de l'image initial self.img_perso = pygame.transform.smoothscale( self.img_perso, (self.width, size_y / size_x * self.width)) def display(self): screen.blit(self.img_perso, (self.posx, self.posy)) def game_over(self): #change l'image du personnage self.img_perso = pygame.image.load("./" + self.nom_perso + '/image/perso.png').convert_alpha() size_x = self.img_perso.get_width() size_y = self.img_perso.get_height() self.img_perso = pygame.transform.smoothscale( self.img_perso, (self.width, size_y / size_x * self.width)) #agrandi la barre pour prendre la totalité de l'écran et change sa couleur self.striker.color = WHITE #agrandi la barre de +50% if self.striker.width < self.striker.height: self.striker.height = HEIGHT else: self.striker.width *= HEIGHT #change les sons de rebond self.striker.sons_frappe = list_files_in_directory( "./Game_over/impact") #self.striker.son_frappe = [] self.striker.son_frappe[:] = [] for f in self.striker.sons_frappe: self.striker.son_frappe.append( pygame.mixer.Sound("./Game_over/impact/" + f)) def point_perdu(self): self.vie -= 3 if self.vie < 0: self.vie = 0 self.game_over() # Striker class class Striker: # Take the initial position, dimensions, speed and color of the object def __init__(self, posx, posy, width, height, speed, color, nom_perso): self.posx = posx self.posy = posy self.width = width self.height = height self.speed = speed self.color = color self.pouvoir = 0 self.nom_perso = nom_perso # Rect that is used to control the position and collision of the object self.geekRect = pygame.Rect(posx, posy, width, height) # Object that is blit on the screen self.geek = pygame.draw.rect(screen, self.color, self.geekRect) # intégration des sons self.sons_frappe = list_files_in_directory("./" + self.nom_perso + "/impact") self.son_frappe = [] for self.f in self.sons_frappe: self.son_frappe.append( pygame.mixer.Sound("./" + self.nom_perso + "/impact/" + self.f)) self.sons_perte = list_files_in_directory("./" + self.nom_perso + "/perte") self.son_perte = [] for self.f in self.sons_perte: self.son_perte.append( pygame.mixer.Sound("./" + self.nom_perso + "/perte/" + self.f)) self.sons_pouvoir = list_files_in_directory("./" + self.nom_perso + "/pouvoir") self.son_pouvoir = [] for self.f in self.sons_pouvoir: self.son_pouvoir.append( pygame.mixer.Sound("./" + self.nom_perso + "/pouvoir/" + self.f)) # Used to display the object on the screen def display(self): self.geek = pygame.draw.rect(screen, self.color, self.geekRect) def updatey(self, yFac): self.posy = self.posy + self.speed * yFac # Restricting the striker to be below the top surface of the screen if self.posy <= 0: self.posy = 0 # Restricting the striker to be above the bottom surface of the screen elif self.posy + self.height >= HEIGHT: self.posy = HEIGHT - self.height # Updating the rect with the new values self.geekRect = (self.posx, self.posy, self.width, self.height) def updatex(self, xFac): self.posx = self.posx + self.speed * xFac # Restricting the striker to be below the left surface of the screen if self.posx <= (WIDTH - HEIGHT) // 2: self.posx = (WIDTH - HEIGHT) // 2 # Restricting the striker to be above the right surface of the screen elif self.posx + self.width >= WIDTH - (WIDTH - HEIGHT) // 2: self.posx = WIDTH - (WIDTH - HEIGHT) // 2 - self.width # Updating the rect with the new values self.geekRect = (self.posx, self.posy, self.width, self.height) def sonFrappe(self): pygame.mixer.Sound.play(random.choice(self.son_frappe)) def sonPerte(self): pygame.mixer.Sound.play(random.choice(self.son_perte)) def sonBonus(self): pygame.mixer.Sound.play(random.choice(self.son_pouvoir)) def displayScore(self, text, score, x, y, color): text = font20.render(text + str(score), True, color) textRect = text.get_rect() textRect.center = (x, y) screen.blit(text, textRect) def getRect(self): return self.geekRect # Ball class class Ball: def __init__(self, posx, posy, radius, speed, color, type_mouvement): self.posx = posx self.posy = posy self.radius = radius self.speed = speed self.speed_start = speed self.color = color self.xFac = 1 self.yFac = -1 self.ball = pygame.draw.circle(screen, self.color, (self.posx, self.posy), self.radius) self.type_mouvement = type_mouvement self.firstTime = 1 self.compteur = 1 self.change = 1 def display(self): self.ball = pygame.draw.circle(screen, self.color, (self.posx, self.posy), self.radius) def update(self): #mouvement rectiligne if self.type_mouvement == 1: self.posx += self.speed * self.xFac self.posy += self.speed * self.yFac #mouvement elif self.type_mouvement == 2: if self.compteur % 5 == 0: self.change = self.change * -1 self.posx += self.speed * self.xFac self.posy += self.change * self.speed * self.yFac self.compteur += 1 #mouvement sinusoïdal elif self.type_mouvement == 3: self.posx += self.speed * self.xFac self.posy += self.speed * self.yFac + self.compteur if self.compteur > 5: self.change = -1 elif self.compteur < -5: self.change = 1 self.compteur += self.change #mouvement vitesse fluctuante elif self.type_mouvement == 4: self.posx += self.speed * self.xFac self.posy += self.speed * self.yFac if self.compteur % 5 == 0: self.speed += self.change if self.compteur >= 20: self.change = -1 elif self.compteur <= -20: self.change = 1 self.compteur += self.change # si la balle atteint la limite du plateau, le point est marqué if self.posx <= (WIDTH - HEIGHT) // 2 and self.firstTime: self.firstTime = 0 return 1 elif self.posx >= HEIGHT + (WIDTH - HEIGHT) // 2 and self.firstTime: self.firstTime = 0 return -1 elif self.posy <= 0 and self.firstTime: self.firstTime = 0 return 2 elif self.posy >= HEIGHT and self.firstTime: self.firstTime = 0 return -2 else: return 0 def vitesse(self, valeur): self.speed += valeur def reset(self): self.posx = WIDTH // 2 self.posy = HEIGHT // 2 #self.xFac *= -1 #self.xFac = random.uniform(-1, 1) self.xFac = 1 self.yFac = random.uniform(-1, 1) self.firstTime = 1 self.speed = self.speed_start self.change = 1 self.compteur = 1 #self.type_mouvement = random.randint(1,5) self.type_mouvement = 1 # Used to reflect the ball along the X-axis et Y-aris def hitx(self, geek): self.xFac *= -1 #print(geek.posy) #print(self.posy) #if self.posy < geek.posy + geek.height//3 # self.yFac *= -1 def hity(self): self.yFac *= -1 def getRect(self): return self.ball # Game Manager def main(): running = True # Defining the objects geek1 = Striker(20 + (WIDTH - HEIGHT) // 2, HEIGHT // 2 - 50, BAR_EPAISSEUR, BAR_LARGEUR, HEIGHT // 60, GREEN, "./Yoshi") geek2 = Striker(WIDTH - (WIDTH - HEIGHT) // 2 - 30, HEIGHT // 2 - 50, BAR_EPAISSEUR, BAR_LARGEUR, HEIGHT // 60, VIOLET, "./Bittrip") geek3 = Striker(WIDTH // 2 - 50, 30, BAR_LARGEUR, BAR_EPAISSEUR, HEIGHT // 60, RED, "./Mario") geek4 = Striker(WIDTH // 2 - 50, HEIGHT - 30, BAR_LARGEUR, BAR_EPAISSEUR, HEIGHT // 60, BLUE, "./Worms") perso1 = Perso(20, 50, (WIDTH - HEIGHT) // 3, "Yoshi", geek1) perso2 = Perso(WIDTH - (WIDTH - HEIGHT) // 3 - 20, HEIGHT - (WIDTH - HEIGHT) // 3 * 1.3 - 50, (WIDTH - HEIGHT) // 3, "Bittrip", geek2) perso3 = Perso(WIDTH - (WIDTH - HEIGHT) // 3 - 20, 50, (WIDTH - HEIGHT) // 3, "Mario", geek3) perso4 = Perso(20, HEIGHT - (WIDTH - HEIGHT) // 3 * 1.3 - 50, (WIDTH - HEIGHT) // 3, "Worms", geek4) ball = Ball(WIDTH // 2, HEIGHT // 2, HEIGHT // 120, HEIGHT // 100, WHITE, 3) power = Power() bonus_geek1, bonus_geek2, bonus_geek3, bonus_geek4 = 0, 0, 0, 0 listOfGeeks = [geek1, geek2, geek3, geek4] # Initial parameters of the players geek1Score, geek2Score, geek3Score, geek4Score = 0, 0, 0, 0 geek1YFac, geek2YFac, geek3XFac, geek4XFac = 0, 0, 0, 0 geek1Pouvoir, geek2Pouvoir, geek3Pouvoir, geek4Pouvoir = 0, 0, 0, 0 while running: #affichage noir, avec des bandes blanches au milieu screen.fill(BLACK) pygame.draw.rect(screen, WHITE, pygame.Rect(0, 0, (WIDTH - HEIGHT) // 2, HEIGHT)) pygame.draw.rect( screen, WHITE, pygame.Rect(WIDTH - (WIDTH - HEIGHT) // 2, 0, (WIDTH - HEIGHT) // 2, HEIGHT)) # Event handling for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: geek2YFac = -1 if event.key == pygame.K_DOWN: geek2YFac = 1 if event.key == pygame.K_z: geek1YFac = -1 if event.key == pygame.K_s: geek1YFac = 1 if event.key == pygame.K_q: geek3XFac = -1 if event.key == pygame.K_d: geek3XFac = 1 if event.key == pygame.K_LEFT: geek4XFac = -1 if event.key == pygame.K_RIGHT: geek4XFac = 1 if event.key == pygame.K_p: geek4Pouvoir = 1 if event.key == pygame.K_o: geek3Pouvoir = 1 if event.type == pygame.KEYUP: if event.key == pygame.K_UP or event.key == pygame.K_DOWN: geek2YFac = 0 if event.key == pygame.K_z or event.key == pygame.K_s: geek1YFac = 0 if event.key == pygame.K_q or event.key == pygame.K_d: geek3XFac = 0 if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT: geek4XFac = 0 if event.key == pygame.K_p: geek4Pouvoir = 0 if event.key == pygame.K_o: geek3Pouvoir = 0 # Collision detection for geek in listOfGeeks: if pygame.Rect.colliderect(ball.getRect(), geek.getRect()): geek.sonFrappe() ball.vitesse(1) if geek == geek1 or geek == geek2: ball.hitx(geek) elif geek == geek3 or geek == geek4: ball.hity() #if geek==geek4 and power.is_activate: #ball.type_mouvement = random.randint(1,4) arduino.reset_input_buffer() arduino.readline() # flush a partial line line = arduino.readline() a0, a1 = [ float(elem.split(":")[1]) for elem in line.decode().strip().split(",") ] # Updating the objects geek1.updatey(geek1YFac) geek1.posy = a0 * HEIGHT / 1024 geek1.geekRect = (geek1.posx, geek1.posy, geek1.width, geek1.height) # geek2.updatey(geek2YFac) geek2.posy = a1 * HEIGHT / 1024 geek2.geekRect = (geek2.posx, geek2.posy, geek2.width, geek2.height) geek3.updatex(geek3XFac) geek4.updatex(geek4XFac) point = ball.update() # activation des pouvoirs if geek4Pouvoir and bonus_geek4: power.activate(2, geek4, listOfGeeks, ball) bonus_geek4 -= 1 geek4.sonBonus() if geek3Pouvoir and bonus_geek3: power.activate(1, geek3, listOfGeeks, ball) bonus_geek3 -= 1 geek3.sonBonus() # -1 -> Geek_2 a perdu # +1 -> Geek_1 a perdu # +2 -> Geek_3 a perdu # -2 -> Geek_4 a perdu # 0 -> aucun n'a perdu le point if point == -1: perso2.point_perdu() geek2Score -= 1 geek2.sonPerte() elif point == 1: perso1.point_perdu() geek1Score -= 1 geek1.sonPerte() elif point == 2: perso3.point_perdu() geek3Score -= 1 geek3.sonPerte() bonus_geek3 += 1 elif point == -2: perso4.point_perdu() geek4Score -= 1 geek4.sonPerte() bonus_geek4 += 1 # Someone has scored # a point and the ball is out of bounds. # So, we reset it's position if point: ball.reset() # Displaying the objects on the screen geek1.display() geek2.display() geek3.display() geek4.display() perso1.display() perso2.display() perso3.display() perso4.display() ball.display() # Displaying the scores of the players geek1.displayScore("Yoshi : ", geek1Score, 100, 20, GREEN) geek2.displayScore("Bit trip : ", geek2Score, WIDTH - 100, HEIGHT - 20, VIOLET) geek3.displayScore("Mario : ", geek3Score, WIDTH - 100, 20, RED) geek4.displayScore("Banjo : ", geek4Score, 100, HEIGHT - 20, BLUE) pygame.display.update() clock.tick(FPS) if __name__ == "__main__": main() pygame.quit()