python游戏开发之色彩与绘图
pygame色彩机制
-
使用pygame.Color类表示色彩
Color类使用RGB或者RGBA(A代表透明度,可选)色彩模式。
可以使用色彩名字:
色彩的RGB或RBGA值:Color(190, 190, 190, 255)
色彩的名字:Color("grey")
RGB即红绿蓝三原色,范围从0~255之间。
A为α通道,参考值为0~255,越高越不透明 -
pygame.Color的属性
pygame.Color.r Color类的R值
pygame.Color.g Color类的G值
pygame.Color.b Color类的B值
pygame.Color.a Color类的A值
pygame.Color.normalize 可以使得所有的参数归一化一个0~1之间的浮点数 -
修改小球的背景颜色
需求:通过小球运动的位置不同,分别改变其背景中R,G,B三原色的值。
import sys, pygame
pygame.init()
size = width, height = (600, 400)
speed = [1, 1]
bgcolor = pygame.Color("black")
fps = 300
still = False
icon = pygame.image.load("滑稽球1.jpg")
pygame.display.set_icon(icon)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("壁球小游戏鼠标版")
ball = pygame.image.load("滑稽球1.jpg")
ballrect = ball.get_rect()
fclock = pygame.time.Clock()
def RGBChannel(a):
return 0 if a<0 else(255 if a>255 else(int(a)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speed[0] = speed[0] if speed[0] == 0 else (abs(speed[0]) - 1) * int(speed[0] / abs(speed[0]))
elif event.key == pygame.K_RIGHT:
speed[0] = speed[0] + 1 if speed[0] > 0 else speed[0] - 1
elif event.key == pygame.K_UP:
speed[1] = speed[1] + 1 if speed[1] > 0 else speed[1] - 1
elif event.key == pygame.K_DOWN:
speed[1] = speed[1] if speed[1] == 0 else (abs(speed[1]) - 1) * int(speed[1] / abs(speed[1]))
elif event.key == pygame.K_ESCAPE:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
still = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
still = False
ballrect = ballrect.move(event.pos[0] - ballrect.left, event.pos[1] - ballrect.top)
elif event.type == pygame.MOUSEMOTION:
if event.buttons[0] == 1:
ballrect = ballrect.move(event.pos[0] - ballrect.left, event.pos[1] - ballrect.top)
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
if ballrect.right > width and ballrect.right + speed[0] > ballrect.right:
# 因为对于鼠标的控制而言,我们是设置的鼠标位置为矩形框的左上角,所以只考虑右下方突破边界的情况
speed[0] = -speed[0]
elif ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
if ballrect.bottom > height and ballrect.bottom + speed[1] > ballrect.bottom:
speed[1] = -speed[1]
if pygame.display.get_active():
if not still:
ballrect = ballrect.move(speed[0], speed[1])
bgcolor.r = RGBChannel(ballrect.left/width*255)
bgcolor.g = RGBChannel(ballrect.top/height*255)
bgcolor.b = RGBChannel(min(speed[0], speed[1])/max(speed[0], speed[1], 1))
screen.fill(bgcolor)
screen.blit(ball, ballrect)
pygame.display.update()
fclock.tick(fps)
pygame的图形绘制机制
所有图形绘制之后,欧pygame都会使用一个rect类(矩形类)来表示一个范围。
pygame.rect
表示一个矩形范围,因而有四个基本的参数值:(left, top)矩形左上角的坐标,width,height宽度与高度,通过这四个值唯一确定矩形的位置。
同样rect类也提供了一些方法例如:rect.move(),rect.copy()等等
pygame.draw
pygame 通过pygame.draw来绘制不同的图形,包括矩形、圆形、椭圆等等。
- pygame.draw.rect(surface, color, rect, width=0)
surface 表示的是绘制在什么区域,一般而言就是当前的屏幕screen
color表示矩形的颜色
rect表示矩形的区域,通过一个四元素的元组确定即左上角坐标与宽、高
width表示的是矩形的线条宽度,默认为0即矩形全部为color颜色,如果不为0,那么就会绘制一个空心区域
import sys, pygame
pygame.init()
size = width, height = (600, 400)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("pygame图形绘制")
gold = 255, 251, 0
red = pygame.Color("red")
rect1 = pygame.draw.rect(screen, gold, (100, 100, 200, 100), 5)
rect2 = pygame.draw.rect(screen, red, (210, 210, 200, 100))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.display.update()
以上是在pygame中绘制矩形的示例代码。
2. pygame.draw.polygon(surface, color, pointlist, width=0)
多边形需要给一个pointlist即一个顶点坐标的列表。
-
pygame.draw.circle(surface, color, pos, radicus, width=0)
圆形通过一个圆心坐标和半径来绘制。 -
pygame.draw.ellipse(surface, color, rect, width=0)
椭圆形的定义方式是通过一个外切矩形来确定。
rect表示一个矩形区域 -
pygame.draw.arch(surface, color, rect, start_angle, stop_angle, width=0)
这里绘制的是一个椭圆形的部分。
同样通过一个外切矩形来确定唯一的椭圆。
start_angle来表示起始角度;
stop_angle来表示终止角度;仍然使用的是笛卡尔坐标系。 -
pygame.draw.line(surface, color, start_pos, end_pos, width=1)
start_pos表示的是起始坐标;
end_pos 表示的是终点坐标;
默认的线条宽度是1。 -
pygame.draw.lines(suraface, color, closed, pointlist, width=1)
closed 如果为True会把起始和终止点连接使得多线形成闭合图形。 -
pygame.draw.aaline(surface, color, start_pos, end_pos, blend=1)
直线绘制需要跨越像素,放大一定程度必然会出现锯齿。
pygame提供了绘制无锯齿线的方法,注意这里的“无锯齿”只是尽可能地减少锯齿的出现,而不可能真的全面消除锯齿的存在。
blend:不为0时,与线条所在背景颜色混合。 -
pygame.draw.aalines(surface, color, pointlist, blend=1)
绘制无锯齿多线。
pygame文字绘制机制
通过使用pygame.freetype来把文字绘制到屏幕上。
无论是中文还是其他语言,文字都是通过点阵图的方式绘制到屏幕上面。
freetype是增强方法,必须要额外进行import pygame.freetype才能使用。
系统字体
对于windows系统,通常把字体存储在C:\windows\fonts目录下。
字体通常是*.ttc或者*.ttf格式的文件。
使用字体
首先需要创建一个字体对象。
pygame.freetype.Font来创建字体对象;
pygame.freetype.render()/render_to()来输出字体。
- pygame.freetype.Font(File, size=0)
File表示字体文件存储的位置,建议使用绝对路径
size表示的字体的大小。 - Font.render_to(surf, dest, text, fgcolor = None, bgcolor = None, rotation, size)
返回的是一个rect 类型。
surf:绘制字体的平面
dest:绘制字体的在屏幕的位置
text:字体的内容,字符串
fgcolor:字体颜色
bgcolor: 背景颜色
rotation:逆时针旋转的角度
size:字体的大小,如果不另外设置会使用之前的Font的大小。
import sys, pygame
import pygame.freetype
pygame.init()
size = width, height = (600, 400)
screen = pygame.display.set_mode(size)
f1 = pygame.freetype.Font("C://windows//Fonts//msyh.ttc", 36)
rect = f1.render_to(screen, (200, 160), "世界和平", )
- Font.render(text, fgcolor=None, bgcolor=None, rotation, size)
相比于render_to()它少了前两个参数。
它会返回一个rect对象与一个surf对象,来表示把文字绘制到一个新的屏幕上。
pygame绘图机制的精髓
- surface类
表示的是绘图平面,绘图层、图层;
表示的是图形或文字图像最终绘制的位置。
图层是可以和主图层的并列存在的,但是只有主图层的图像会被显示在屏幕上。 - rect类
表示一个矩形区域,但是它只对应一个主图层上的区域。
它是表示主图层上某一个区域的位置信息或指针;
可以指定某个图层绘制在特定区域上。 - 主图层
由pygame.display.set_mode()生成的surface对象就是主图层。
如果希望把其他图层的东西绘制到主图层上就要使用blit方法,例如:
screen.blit(ball, ballrect)
这就是把小球的图像ball的图层将其绘制到ballrect的区域上。
壁球小游戏文字型
需求:把壁球替换为一段文字,可以进行移动;
关键要素:文字的绘制与刷新。
可以使用render_to()方法或者render()方法来绘制文字。
import sys, pygame
import pygame.freetype
pygame.init()
size = width, height = 600, 400
speed = [1, 1]
Black = 0, 0, 0
Gold = 255, 251, 0
pos = [230, 160]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("pygame壁球小游戏文字型")
fps = 300
fclock = pygame.time.Clock()
f1 = pygame.freetype.Font("C://windows//Fonts//msyh.ttc", 36)
f1rect = f1.render_to(screen, pos, "世界和平", fgcolor=Gold, size=50)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speed[0] = speed[0] - 1 if speed[0] > 0 else 0
elif event.key == pygame.K_RIGHT:
speed[0] = speed[0] + 1
elif event.key == pygame.K_UP:
speed[1] = speed[1] + 1
elif event.key == pygame.K_DOWN:
speed[1] = speed[1] - 1 if speed[1] > 0 else 0
if pos[0] < 0 or pos[0] + f1rect.width > width:
speed[0] = -speed[0]
if pos[1] < 0 or pos[1] + f1rect.height > height:
speed[1] = -speed[1]
pos[0] = pos[0] + speed[0]
pos[1] = pos[1] + speed[1]
screen.fill(Black)
f1rect = f1.render_to(screen, pos, "世界和平", fgcolor=Gold, size=50)
pygame.display.update()
fclock.tick(fps)
以上内容来自北京理工大学嵩天老师及其团队的《Python游戏开发入门》课程第四周的内容。
非常感谢嵩天老师及其团队给我们带来这样优质的课程。