I'm currently coding a Pac-man with Pygame, and I'm blocked by the sprite. I want to make a yellow circle with a black (or back color) arc, like if it was a pie without a piece of a cake. I read documentations about it but all things I found wasn't at my level (I'm in high school). Thanks for reading and answering me back, Regards.
import pygame
from pygame.locals import *
from board import *
from math import *
import time
import sys
screen_width, screen_height = 660, 700
case_h = (screen_height-50)//32
case_w = screen_width//30
def create_window(longueur, largeur, titre, back_color):
"""
Création de la fenêtre principale
:param screen_width : la longueur de l'écran (en pixels)
:type screen_width : int
:param screen_height : la largeur de l'écran (en pixels)
:type screen_height : int
:param titre : nom donné à la fenêtre
:type titre : str
"""
# Création de la fenêtre
windows = pygame.display.set_mode((longueur, largeur))
windows.fill(back_color)
# Nommage de la fenêtre
pygame.display.set_caption('Pac-Man')
return windows
def key_pressed():
"""
Lecture du clavier du joueur
"""
global run, direction
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_LEFT:
direction = 'gauche'
if event.key == pygame.K_RIGHT:
direction = 'droite'
if event.key == pygame.K_UP:
direction = 'haut'
if event.key == pygame.K_DOWN:
direction = 'bas'
def draw_board(boards):
"""
Affichage du plateau
:param boards : matrice contenant les cases à afficher
:type boards : list
"""
for i in range(len(boards)):
for j in range(len(boards[i])):
if boards[i][j] == 1:
pygame.draw.circle(windows, (255, 255, 0), (case_w*(j+0.5),
case_h*(i+0.5)), 4)
if boards[i][j] == 2:
pygame.draw.circle(windows, (255, 255, 0), (case_w*(j+0.5),
case_h*(i+0.5)), 6)
if boards[i][j] == 3:
pygame.draw.line(windows, (0, 0, 255), (case_w*(j+0.5), case_h*i),
(case_w*(j+0.5), case_h*(i+1)))
if boards[i][j] == 4:
pygame.draw.line(windows, (0, 0, 255), (case_w*j, case_h*(i+0.5)),
(case_w*(j+1), case_h*(i+0.5)))
if boards[i][j] == 5:
pygame.draw.arc(windows, (0, 0, 255), [case_w*(j-0.5), case_h*(i+0.5)
, case_w, case_h], 0, pi/2, 1)
if boards[i][j] == 6:
pygame.draw.arc(windows, (0, 0, 255), [case_w*(j+0.5), case_h*(i+0.5)
, case_w, case_h], pi/2, pi, 1)
if boards[i][j] == 7:
pygame.draw.arc(windows, (0, 0, 255), [case_w*(j+0.5), case_h*(i-0.5)
, case_w, case_h], pi, (3*pi)/2, 1)
if boards[i][j] ==8:
pygame.draw.arc(windows, (0, 0, 255), [case_w*(j-0.5), case_h*(i-0.5)
, case_w, case_h], (3*pi)/2, 2*pi, 1)
if boards[i][j] == 9:
pygame.draw.line(windows, (255, 255, 255), (case_w*j, case_h*(i+0.5)),
(case_w*(j+1), case_h*(i+0.5)))
def pac_man_move(direction):
"""
Création et affichage du Pac-man
:param direction : direction du Pac-man
:param direction : str
"""
global posx, posy
pygame.draw.rect(windows, (255, 255, 0), (case_w*posx, case_h*posy, case_w, case_h))
if direction == 'gauche':
posx -= 0.1
elif direction == 'droite':
posx += 0.1
elif direction == 'haut':
posy -= 0.1
elif direction == 'bas':
posy += 0.1
def draw_test():
global posx, posy
pygame.draw.arc(windows, (255, 255, 0), (case_w*posx, case_h*posy, case_w*(posx+1), case_h*(posy+1)), (11*pi)/6, pi/6, width=1)
run = True
posx = 15
posy = 24
direction = 'droite'
windows = create_window(screen_width, screen_height, 'Pac-Man', (0, 0, 0))
while run:
windows.fill((0, 0, 0))
draw_board(boards)
pac_man_move(direction)
key_pressed()
if posx < 0:
posx = 30
elif posx > 30:
posx = 0
time.sleep(0.0125)
pygame.display.update()
I tried to make an arc with pygame.draw.arc(...)
and width=0
, as when you draw a rectangle, if width=0
, it fills the rectangle, but not with an arc.
congratulations for the project!
The problem is the drawing API for Pygame is not as complete as other drawing APIs around there, and the option for drawing a "pie chart" like sprite is simply lacking.
At this point there are some options: (1) use another drawing API as library, such as Cairo, pyglet, matplotlib or PIL (not sure if the latest has the "pie chart" thing as well) - and copy the generated pixels to a pygame compatible object; (2) pre-draw the image in an imaging program, and load these images from ".png" files at runtime for the pygame project (might be the simpler path); and (3) which can provide you with more learning of "how things work" under the hood: use basic primitives to draw the pacman shape with mathematical functions alone - this can give you better control in the sense you can add gradients and other color-changing effects across your filled area as well.
The 3rd approach above will require some trignometric thinking, along with same basic rules for rasterising shapes, which are a learning that will give you some foundation on how things work:
The basic idea is just have two nested for-loops that will yield all (x, y) values for the region of interest (ROI) where you are drawing your pacman - for each coordinate you then test if that should be filled or not (and when doing fancier stuff, maybe calculate a custom color). In the case of a Pacman shape, (x,y) should be inside a circle of radius "r", and outside an specified angle range, you will have to find out using math.asin
and math.acos
def pacman(surf, total_r, min_ang):
width, height = sc.get_size()
cx, cy = width // 2, height // 2
for y in range(height):
for x in range(width):
nx, ny = (x - cx) / cx, (y - cy) / cy
r = (nx ** 2 + ny ** 2 ) ** 0.5
alpha = math.degrees(math.asin(ny / r if r else 0.00001))
if r < total_r and (abs(alpha) > min_ang or nx < 0) :
color = (255, 255, 0)
else:
color = (0, 0, 0)
surf.set_at((x,y), color)
# pygame.display.flip()
Pass a surface (like a 64x64 pixel, or whatever you want), or just your screen straight to test it - it will draw a pacman-like shape mirrored at the angle "0" (horizontal line from left to right)
Then, of course, rendering an image like this is too slow to do every frame: draw your various pac-man sprites at a game setup stage, and keep then in different pygame Surface
objects you can stamp with .blit
at game time.