用pygame绘制完整弧线
我现在正在用Pygame编写一个吃豆人游戏,但在处理精灵的时候遇到了困难。我想画一个黄色的圆圈,上面有一个黑色的弧,就像一个没有切掉一块的派。我查了很多文档,但里面的内容对我来说太复杂了(我还在高中)。感谢你们的阅读和回复,祝好。
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()
我试着用 pygame.draw.arc(...)
来画一个弧,并把 width=0
,就像画矩形一样,如果 width=0
,矩形会被填满,但弧却没有。
1 个回答
恭喜你完成这个项目!
问题是,Pygame的绘图功能没有其他绘图工具那么全面,像“饼图”这样的图形绘制选项根本就没有。
现在有几个解决办法:(1) 使用其他绘图工具库,比如Cairo、pyglet、matplotlib或者PIL(不确定最新的PIL是否也支持“饼图”)——然后把生成的像素复制到一个Pygame可以用的对象里;(2) 在图像处理软件中提前绘制好图像,然后在Pygame项目运行时从“.png”文件中加载这些图像(这可能是更简单的办法);(3) 如果你想更深入地了解“背后的工作原理”,可以用数学函数来绘制吃豆人形状,这样你能更好地控制,比如在填充区域添加渐变和其他颜色变化效果。
第三种方法需要一些三角函数的思考,以及一些基本的形状栅格化规则,这些都是学习的基础,能帮助你理解事物是如何运作的:基本思路是使用两个嵌套的循环来生成你想绘制的吃豆人的所有(x, y)坐标——对于每个坐标,你需要判断它是否应该被填充(如果要做更复杂的效果,可能还需要计算自定义颜色)。对于吃豆人形状来说,(x,y)需要在半径为“r”的圆内,并且在指定的角度范围之外,你需要用math.asin
和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()
传入一个表面(比如64x64像素,或者你想要的其他尺寸),或者直接把屏幕传过去进行测试——它会在“0”角度(从左到右的水平线)绘制一个吃豆人形状。
当然,这样每帧渲染图像太慢了:在游戏设置阶段绘制好各种吃豆人图像,然后把它们保存在不同的Pygame Surface
对象中,游戏时可以用.blit
来快速显示。