pygame-snake/main.py

181 lines
6.1 KiB
Python
Raw Permalink Normal View History

2018-05-03 14:12:54 +02:00
import argparse
2018-04-29 11:20:05 +02:00
import logging
2018-04-29 20:58:38 +02:00
import os
import pickle
2018-04-30 21:43:49 +02:00
from tkinter import Tk, simpledialog, messagebox
2018-04-29 11:20:05 +02:00
import pygame
from pygame import locals as pglocals
2018-04-30 20:57:24 +02:00
from config import (RESOLUTION, MAP_RESOLUTION,
SNAKE_COLOR, BACKGROUND_COLOR, FONT_COLOR,
2018-04-30 21:43:49 +02:00
INITIAL_SNAKE_SIZE, SCORES_FILE, MAX_HIGH_SCORES_COUNT)
2018-04-29 11:20:05 +02:00
from objects import Snake, Apple
from utils import get_score_text, Direction
2018-05-03 14:12:54 +02:00
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', help='Show debug logs', action='store_true')
args = parser.parse_args()
level = logging.INFO
if args.verbose:
level = logging.DEBUG
logging.basicConfig(level=level)
2018-04-29 11:20:05 +02:00
logger = logging.getLogger(__name__)
pygame.init()
2018-04-30 22:15:55 +02:00
Tk().wm_withdraw() # to hide the main window
2018-04-29 11:20:05 +02:00
def main():
clock = pygame.time.Clock()
logger.debug('pygame initialized')
if not pygame.font:
logger.warning('Fonts disabled')
if not pygame.mixer:
logger.warning('Sound disabled')
screen = pygame.display.set_mode(RESOLUTION) # type: pygame.Surface
pygame.display.set_caption('Snake')
2018-04-29 20:58:38 +02:00
scores = []
if os.path.isfile(SCORES_FILE):
with open(SCORES_FILE, 'rb') as scores_file:
scores = pickle.load(scores_file)
2018-04-29 11:20:05 +02:00
2018-04-30 21:43:49 +02:00
logger.info(f'Previous high scores : {scores}')
2018-04-29 11:20:05 +02:00
2018-04-30 22:15:55 +02:00
# Retry loop
2018-04-29 11:20:05 +02:00
while True:
2018-04-29 20:58:38 +02:00
screen.fill(BACKGROUND_COLOR)
snake = Snake()
screen.fill(SNAKE_COLOR, snake.head)
apple = Apple()
apple.display(screen)
score = 0
score_text, score_rect = get_score_text(score)
screen.blit(score_text, score_rect)
2018-04-30 20:57:24 +02:00
screen.fill(FONT_COLOR, pygame.Rect(0, MAP_RESOLUTION[1], MAP_RESOLUTION[0], 5))
2018-04-29 20:58:38 +02:00
pygame.display.flip()
2018-05-07 08:53:33 +02:00
if scores:
display_scores(scores)
2018-04-30 22:15:55 +02:00
# Main game loop
2018-04-29 20:58:38 +02:00
while True:
for event in pygame.event.get():
if event.type == pglocals.QUIT:
logger.warning('Received QUIT event')
return
if event.type == pglocals.KEYDOWN:
2018-04-30 20:28:56 +02:00
if event.key == pglocals.K_DOWN or event.key == pglocals.K_s:
2018-04-29 20:58:38 +02:00
snake.direction = Direction.DOWN
2018-04-30 20:28:56 +02:00
elif event.key == pglocals.K_LEFT or event.key == pglocals.K_q:
2018-04-29 20:58:38 +02:00
snake.direction = Direction.LEFT
2018-04-30 20:28:56 +02:00
elif event.key == pglocals.K_UP or event.key == pglocals.K_z:
2018-04-29 20:58:38 +02:00
snake.direction = Direction.UP
2018-04-30 20:28:56 +02:00
elif event.key == pglocals.K_RIGHT or event.key == pglocals.K_d:
2018-04-29 20:58:38 +02:00
snake.direction = Direction.RIGHT
2018-04-30 20:38:24 +02:00
elif event.key == pglocals.K_ESCAPE:
pause = True
while pause:
clock.tick(5)
2018-04-30 21:01:23 +02:00
for subevent in pygame.event.get():
if subevent.type == pglocals.KEYDOWN and subevent.key == pglocals.K_ESCAPE:
2018-04-30 20:38:24 +02:00
pause = False
break
2018-04-29 20:58:38 +02:00
dirty_rects = snake.move(screen, apple)
if snake.dead:
logger.info(f'Vous avez perdu ! Score : {score}')
break
if snake.head.colliderect(apple.rect):
apple.renew()
score += apple.score
2018-04-30 20:40:05 +02:00
logger.debug(f'Apple eaten, new score : {score}')
2018-04-29 20:58:38 +02:00
screen.fill(BACKGROUND_COLOR, score_rect)
old_score_rect = score_rect
score_text, score_rect = get_score_text(score)
screen.blit(score_text, score_rect)
dirty_rects.append(score_rect.union(old_score_rect))
dirty_rects.append(apple.display(screen))
pygame.display.update(dirty_rects)
# Run faster as snake grows
2018-04-30 22:15:55 +02:00
clock.tick(10 - INITIAL_SNAKE_SIZE + len(snake.slots))
2018-04-29 20:58:38 +02:00
display_end_screen(screen, score)
scores = save_score(score, scores)
2018-04-30 21:43:49 +02:00
2018-04-30 20:40:57 +02:00
restart = False
while not restart:
2018-04-29 20:58:38 +02:00
for event in pygame.event.get():
if event.type == pglocals.QUIT:
logger.info('Received QUIT event')
logger.info(f'High scores : {scores}')
return
if event.type == pglocals.KEYDOWN:
if event.key == pglocals.K_r:
2018-04-30 21:06:55 +02:00
logger.info('Restarting game')
2018-04-29 20:58:38 +02:00
restart = True
2018-04-30 21:43:49 +02:00
elif event.key == pglocals.K_s:
2018-04-30 22:15:55 +02:00
display_scores(scores)
2018-04-29 20:58:38 +02:00
clock.tick(5)
2018-04-29 11:20:05 +02:00
2018-04-30 22:15:55 +02:00
def display_scores(scores):
scores_str = '\n'.join(map(lambda s: f"{s['player']} : {s['score']}", scores))
messagebox.showinfo("Tableau des scores", scores_str)
def save_score(score, scores):
username = simpledialog.askstring(
"Enregistrer le score",
f"Entrez votre nom d'utilisateur ou laissez vide pour ne pas enregistrer."
)
if username:
scores.append({'player': username, 'score': score})
logger.info(f'Saving {username}: {score}')
scores = sorted(scores, key=lambda x: x['score'], reverse=True)[:MAX_HIGH_SCORES_COUNT]
logger.info(f'New high scores : {scores}')
with open(SCORES_FILE, 'wb') as scores_file:
pickle.dump(scores, scores_file)
else:
logger.debug('Not saving score')
return scores
def display_end_screen(screen, score):
screen.fill(BACKGROUND_COLOR)
font = pygame.font.Font(None, 60)
text = font.render(f"PERDU ! Score : {score}", 1, FONT_COLOR)
text_rect = text.get_rect() # type: pygame.Rect
text_rect.center = screen.get_rect().center
screen.blit(text, text_rect)
font = pygame.font.Font(None, 30)
text = font.render(f"R pour recommencer", 1, FONT_COLOR)
text_rect = text.get_rect() # type: pygame.Rect
text_rect.center = screen.get_rect().center
text_rect.top += 45
screen.blit(text, text_rect)
text = font.render(f"S pour les scores", 1, FONT_COLOR)
text_rect = text.get_rect() # type: pygame.Rect
text_rect.center = screen.get_rect().center
text_rect.top += 70
screen.blit(text, text_rect)
pygame.display.flip()
2018-04-29 11:20:05 +02:00
if __name__ == '__main__':
main()