用Python和Pygame写游戏-从入门到精通(7)

By | 2011/06/04

我们上一个章节使用了pygame.draw中的一些函数,这个模块的作用是在屏幕上绘制各种图形。事实上,你可以不加载任何图片,只是要这些图形来制作一个游戏(经典游戏Asteroids便是,这里有一个HTML5写就的例子。好像访问不了?搜个Flash版吧,多得很)。

注:该图与该文无任何联系(最近在玩神鬼寓言3,感觉还是不错的~)

pygame.draw中函数的第一个参数总是一个surface,然后是颜色,再后会是一系列的坐标等。稍有些计算机绘图经验的人就会知道,计算机里的坐标,(0,0)代表左上角。而返回值是一个Rect对象,包含了绘制的领域,这样你就可以很方便的更新那个部分了。

函数 作用
rect 绘制矩形
polygon 绘制多边形(三个及三个以上的边)
circle 绘制圆
ellipse 绘制椭圆
arc 绘制圆弧
line 绘制线
lines 绘制一系列的线
aaline 绘制一根平滑的线
aalines 绘制一系列平滑的线

我们下面一个一个详细说明。

pygame.draw.rect

用法:pygame.draw.rect(Surface, color, Rect, width=0)

pygame.draw.rect在surface上画一个矩形,除了surface和color,rect接受一个矩形的坐标和线宽参数,如果线宽是0或省略,则填充。我们有一个另外的方法来画矩形——fill方法,如果你还记得的话。事实上fill可能还会快一点点,因为fill由显卡来完成。

pygame.draw.polygon

用法:pygame.draw.polygon(Surface, color, pointlist, width=0)

polygon就是多边形,用法类似rect,第一、第二、第四的参数都是相同的,只不过polygon会接受一系列坐标的列表,代表了各个顶点。

pygame.draw.circle

用法:pygame.draw.circle(Surface, color, pos, radius, width=0)

很简单,画一个圆。与其他不同的是,它接收一个圆心坐标和半径参数。

pygame.draw.ellipse

用法:pygame.draw.ellipse(Surface, color, Rect, width=0)

你可以把一个ellipse想象成一个被压扁的圆,事实上,它是可以被一个矩形装起来的。pygame.draw.ellipse的第三个参数就是这个椭圆的外接矩形。

pygame.draw.arc

用法:pygame.draw.arc(Surface, color, Rect, start_angle, stop_angle, width=1)

arc是椭圆的一部分,所以它的参数也就比椭圆多一点。但它是不封闭的,因此没有fill方法。start_angle和stop_angle为开始和结束的角度。

pygame.draw.line

用法:pygame.draw.line(Surface, color, start_pos, end_pos, width=1)

我相信所有的人都能看明白。

pygame.draw.lines

用法:pygame.draw.lines(Surface, color, closed, pointlist, width=1)

closed是一个布尔变量,指明是否需要多画一条线来使这些线条闭合(感觉就和polygone一样了),pointlist是一个点的数组。

上面的表中我们还有aaline和aalines,玩游戏的都知道开出“抗锯齿(antialiasing)”效果会让画面更好看一些,模型的边就不会是锯齿形的了,这两个方法就是在画线的时候做这事情的,参数和上面一样,省略。

我们用一个混杂的例子来演示一下上面的各个方法:

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit

from random import *
from math import pi

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
points = []

while True:

    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
        if event.type == KEYDOWN:
            # 按任意键可以清屏并把点回复到原始状态
            points = []
            screen.fill((255,255,255))
        if event.type == MOUSEBUTTONDOWN:
            screen.fill((255,255,255))
            # 画随机矩形
            rc = (randint(0,255), randint(0,255), randint(0,255))
            rp = (randint(0,639), randint(0,479))
            rs = (639-randint(rp[0], 639), 479-randint(rp[1], 479))
            pygame.draw.rect(screen, rc, Rect(rp, rs))
            # 画随机圆形
            rc = (randint(0,255), randint(0,255), randint(0,255))
            rp = (randint(0,639), randint(0,479))
            rr = randint(1, 200)
            pygame.draw.circle(screen, rc, rp, rr)
            # 获得当前鼠标点击位置
            x, y = pygame.mouse.get_pos()
            points.append((x, y))
            # 根据点击位置画弧线
            angle = (x/639.)*pi*2.
            pygame.draw.arc(screen, (0,0,0), (0,0,639,479), 0, angle, 3)
            # 根据点击位置画椭圆
            pygame.draw.ellipse(screen, (0, 255, 0), (0, 0, x, y))
            # 从左上和右下画两根线连接到点击位置
            pygame.draw.line(screen, (0, 0, 255), (0, 0), (x, y))
            pygame.draw.line(screen, (255, 0, 0), (640, 480), (x, y))
            # 画点击轨迹图
            if len(points) > 1:
                pygame.draw.lines(screen, (155, 155, 0), False, points, 2)
            # 和轨迹图基本一样,只不过是闭合的,因为会覆盖,所以这里注释了
            #if len(points) >= 3:
            #    pygame.draw.polygon(screen, (0, 155, 155), points, 2)
            # 把每个点画明显一点
            for p in points:
                pygame.draw.circle(screen, (155, 155, 155), p, 3)

    pygame.display.update()

运行这个程序,在上面点鼠标就会有图形出来了;按任意键可以重新开始。另外这个程序只是各个命令的堆砌,并不见得是一个好的程序代码。

到这次为止,文字、颜色、图像、图形都讲好了,静态显示的部分都差不多了。然而多彩的游戏中只有静态的东西实在太让人寒心了(GalGame大多如此),下次开始我们学习游戏中的动画制作。

>> 用Python和Pygame写游戏-从入门到精通(8)

 

27 thoughts on “用Python和Pygame写游戏-从入门到精通(7)

    1. 糯米粥

      用弧度,不是角度。我TM 的硬试了 半天。没看明白。圆弧弧度取值0 -2π。麻烦作者改一下次。或者说明一下,我真服了。快郁闷死。

      Reply
  1. Amb

    请教博主,如何绘制出能抗锯齿的圆形呢,circle锯齿太严重了

    Reply
    1. xishui Post author

      罪过罪过,我居然没有看到阁下上一次问的问题,是用图片解决啊,不错的想法;
      pygame 1.9之后提供了一个gfxdraw模块,提供aacircle方法,与aaline类似,绘制抗锯齿的东西。不过这个模块并不是兼容的,有的平台上可能不存在,所以我没有说明,不过如果仅是在Windows上开发,可以尝试用一下。

      Reply
  2. Zhu

    @Amb:
    用图片代替?? 难道是传说中的贴图方法??

    Reply
  3. xumaomao

    在ubuntu下试验gfxdraw貌似可以用的。不过函数的参数跟pygame.draw不太相同:把color参数放在最后了。比如:
    gfxdraw.aaellipse(surface,中心横坐标,中心纵坐标,半短轴长度,半长轴长度,colors)
    gfxdraw.aacircle(surface,中心横坐标,中心纵坐标,半径,colors)

    Reply
    1. Johnetta

      This is not quite what I was hoping for. I was looking for an NFL Films program. This is an edited version of the regular TV broadcast of the NFC championship game in which the Saints beat the Vikings to qualify for the Super Bowl. That’s OK, but it should have been identified as such in the description. It was still a great game and a good viewing experience, especially for lofsngu-fering Saints fans who want to relive every moment of a championship season endlessly!

      Reply
  4. fox

    if event.type == QUIT:
    exit()
    之后没有break就不能正常退出了在linux下

    Reply
  5. IamShit

    你好。。大神,看了你的教程之后还是连如何在画布上显示一个动态GIF都做不出来。。。。不知道能不能给个实例。。

    Reply
    1. xishui Post author

      可以给个思路,参考下Sprite篇,GIF要把每一帧取出来,然后定时绘制上去…… 但是很少有游戏这么做,大多是使用Sprite中的方法,同一幅图的不同位移来做的。

      Reply
      1. Daniel

        我有个问题想问作者,pygame能不能设置窗口打开时出现在屏幕上的位置呢?

        Reply
  6. yang123

    用fill画矩形?那也得先画出矩形再fill吧。求解

    Reply
  7. wzzzx

    请问一下,为什么不断的点击鼠标,达到一定次数之后会报错?
    错误原因如下:
    pygame.draw.circle(screen,rc,rp,rr,3)
    ValueError: width greater than radius

    Reply
    1. Stormy

      Reading how unspun wrote about Newmont and Buyat case, I was worinedng whether Unspun ever worked closely with Newmont, hence receiving a lot of PR fee from the company. Is this blog also a part of your PR work? I thought it was about your personal views and to satisfy your penchant for gossips.

      Reply
    2. Replying

      你填入了width参数等于3,这时绘制的不再是填充的实心圆形,而是有线条宽度的一个空心圆,如果圆的半径恰好随机到小于3的一个数,那么圆的线条宽度比圆的半径还大,自然就画不出来了。

      Reply
  8. Pingback: 用Python和Pygame写游戏-从入门到精通(7) – 小猫编程站

  9. Pingback: 用Python和Pygame写游戏-从入门到精通(7)-演道网

  10. StoryofTime

    if event.type == MOUSEBUTTONDOWN: 下的screen.fill((255,255,255))的作用是覆盖之前绘制的图形

    Reply
  11. Pingback: 用 Python 和 Pygame 写游戏 – 从入门到精通(目录) – ITPCB

  12. Pingback: pygame学习 | Coding栈

发表评论

您的电子邮箱地址不会被公开。