本章,你将学习如何在 Pygame 中绘制图形。
导航
文章目录
- 导航
- 抗锯齿
- draw 模块
- 实例:跟随鼠标的图形
- 创建初始窗口
- 添加变量
- 捕捉鼠标事件
- 绘制图形
- 完整代码
抗锯齿
抗锯齿(anti-aliasing,简称 AA)是一种消除显示器输出的画面中图物边缘出现凹凸锯齿的技术。实现抗锯齿效果需要更多的计算时间,因此在进行高质量绘制的同时,也会带来一定的性能缺陷。
draw 模块
pygame.draw
模块提供了一些函数以在Surface
对象上绘制各种形状。
这些函数的共同点是:
- 第一个参数都是图形要绘制到的
Surface
对象。 - 第二个参数都是绘制的颜色。
- 所有的非抗锯齿函数都有可选的
width
参数:
- 对于非封闭图形,如果
width >= 1
,它表示线条的粗细,如果width < 1
,图形将不会被绘制。 - 对于封闭图形,如果
width >= 1
,它表示线条的粗细,如果width == 0
,图形将被填充,如果width < 1
,图形将不会被绘制。
- 函数返回的都是绘制所影响的矩形区域。
具体定义及作用如下表(详见官方文档):
函数定义 | 函数作用 |
| 绘制一个矩形。
最后的5个可选参数用于绘制圆角矩形。 |
| 绘制一个多边形。
|
| 绘制一个圆。
|
| 绘制一个椭圆。
|
| 绘制一段椭圆弧。
参数 如果 如果 如果 |
| 绘制一条线段。
|
| 绘制多条顶点相交的线段。
例如,对于 |
| 绘制一条抗锯齿的线段。
其他参数同 |
| 绘制多条顶点相交的抗锯齿的线段。
其他参数同 |
实例:跟随鼠标的图形
与上一章一样,为了使读者更清楚地了解pygame.draw
模块的使用,我们将创建一个使图形跟随鼠标的程序。
请创建一个新的文件,命名为following_shapes.py
。
创建初始窗口
请添加以下代码以创建初始窗口:
import math
import sys
import pygame
class FollowingShapes:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((800, 800))
pygame.display.set_caption('Following Shapes')
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
sys.exit()
self.screen.fill((0, 0, 0))
pygame.display.update()
if __name__ == '__main__':
app = FollowingShapes()
app.run()
与前几个程序截然不同的是,我们把主循环封装到了FollowingShapes
类中。当程序所需要处理的工作变得越来越多时,把主代码全部写在顶级语句中并不是一个很好的方式,这样会减低代码的可读性,也会使程序难以维护。时常对代码进行重构,是一个良好的习惯。
在最开始,程序导入了math
库,因为在后期绘制弧线时,我们需要使用math.pi
。
在事件处理中,除了QUIT
事件我们还处理了KEYDOWN
事件,并且使用了key
属性,它表示用户所按下的键。这个属性,并不是所有的事件对象都有的,而是 Pygame 为这个事件添加的特殊属性,这样的事件还有很多,详见官方文档。
添加特殊的属性其实是 Python 的特性之一,可以通过[variable_name].[attribute_name] = [value]
的形式在类的外部添加属性,如下所示:
>>> class Editor:
... pass
...
>>> editor = Editor()
>>> editor.name = 'vscode'
>>> editor.name
'vscode'
但是这种方法仅限于自定义的类。
回到程序,在事件处理中,如果用户按下了Esc
键,也将退出程序,这是因为图形是随着鼠标移动的,如果用户只能把鼠标拖到“关闭”按钮来退出程序,会略显别扭,所以添加了退出程序的快捷键。
在屏幕渲染中调用fill
函数是为了在每次循环时填充屏幕,如果不填充屏幕,鼠标移动后旧的图形依然会留在屏幕上。
添加变量
在构造函数中,添加如下代码:
def __init__(self):
# ...
self.color = (255, 0, 0)
self.pos = (0, 0)
self.mode = 0
# ...
上述代码中,color
属性设置绘制图形所使用的颜色,此处为红色,pos
属性用于保存鼠标的位置,mode
属性指定要绘制的图形。在本实例中,mode
与图形的对应关系如下表:
| 对应的图形 |
0 | 矩形 |
1 | 圆 |
2 | 椭圆 |
3 | 线段 |
4 | 弧线 |
捕捉鼠标事件
为了使图形能够跟随鼠标移动,我们需要捕捉鼠标移动的事件。同时,在本实例的设计中,用户一点击鼠标就会切换图形,所以还需要捕捉按下鼠标的事件。在 Pygame 中,这两个事件分别是MOUSEMOTION
和MOUSEBUTTONDOWN
,捕捉事件的代码如下:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEMOTION:
self.pos = event.pos
elif event.type == pygame.MOUSEBUTTONDOWN:
self.mode += 1
self.mode %= 5
在处理MOUSEMOTION
事件时,我们再次使用了一个特殊属性pos
,它表示鼠标相对于屏幕的坐标。
在处理MOUSEBUTTONDOWN
事件时,我们先将mode
自增1,然后把mode
取模5并赋值给本身,这样做是为了在mode
为4并自增时轮回0。
绘制图形
在代码中添加如下绘制图形的方法:
def draw_shape(self):
rect = pygame.Rect(0, 0, 200, 100)
rect.center = self.pos
if self.mode == 0:
pygame.draw.rect(self.screen, self.color, rect)
elif self.mode == 1:
pygame.draw.circle(self.screen, self.color, self.pos, 100)
elif self.mode == 2:
pygame.draw.ellipse(self.screen, self.color, rect)
elif self.mode == 3:
pygame.draw.line(self.screen, self.color, rect.topleft, rect.bottomright)
elif self.mode == 4:
pygame.draw.arc(self.screen, self.color, rect, 0, math.pi)
该方法的最开始,创建了一个矩形对象rect
,并将它的中心设置为鼠标坐标,是因为大部分绘制都是基于这个矩形的:
- 绘制矩形时,
rect
为矩形的坐标。 - 绘制椭圆时,
rect
为椭圆的边界矩形。 - 绘制线段时,
rect
也是线段的边界矩形,即线段是rect
的对角线。 - 绘制弧线时,
rect
是包含弧线的椭圆的边界矩形。
而绘制圆时,因为rect
的长宽不相等,所以没有使用,把中心设置为鼠标坐标,半径设置为100。
最后,在run
方法中调用draw_shape
方法:
# ...
self.screen.fill((0, 0, 0))
self.draw_shape()
pygame.display.update()
# ...
完整代码
import math
import sys
import pygame
class FollowingShapes:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((800, 800))
pygame.display.set_caption('Following Shapes')
self.color = (255, 0, 0)
self.pos = (0, 0)
self.mode = 0
def draw_shape(self):
rect = pygame.Rect(0, 0, 200, 100)
rect.center = self.pos
if self.mode == 0:
pygame.draw.rect(self.screen, self.color, rect)
elif self.mode == 1:
pygame.draw.circle(self.screen, self.color, self.pos, 100)
elif self.mode == 2:
pygame.draw.ellipse(self.screen, self.color, rect)
elif self.mode == 3:
pygame.draw.line(self.screen, self.color, rect.topleft, rect.bottomright)
elif self.mode == 4:
pygame.draw.arc(self.screen, self.color, rect, 0, math.pi)
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEMOTION:
self.pos = event.pos
elif event.type == pygame.MOUSEBUTTONDOWN:
self.mode += 1
self.mode %= 5
self.screen.fill((0, 0, 0))
self.draw_shape()
pygame.display.update()
if __name__ == '__main__':
app = FollowingShapes()
app.run()
代码运行截图:
结语
以上,就是本章的所有内容。