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

By | 2011/04/26

OK,到该讲显示的时候了。没人可以否定好的画面是一款游戏吸引人最直接最诱人的因素,虽说滥画面高游戏度的作品也有,但优秀的画面无疑是一张过硬的通行证,可以让你争取到更多的机会。

其实上两回也已经打开过显示了,不过没有特别说明而已,pygame.display.set_mode(xxx)就是创建一个游戏窗口,也就是显示的意思。

全屏显示

我们在第一个程序里使用了如下的语句

screen = pygame.display.set_mode((640, 480), 0, 32)

也讲述了各个参数的意思,当我们把第二个参数设置为FULLSCREEN时,就能得到一个全屏窗口了

screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32)

注意:如果你的程序有什么问题,很可能进入了全屏模式就不太容易退出来了,所以最好先用窗口模式调试好,再改为全屏模式。

在全屏模式下,显卡可能就切换了一种模式,你可以用如下代码获得您的机器支持的显示模式:

>>> import pygame
>>> pygame.init()
>>> pygame.display.list_modes()

看一下一个实例:

background_image_filename = 'sushiplate.jpg'

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

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
background = pygame.image.load(background_image_filename).convert()

Fullscreen = False

while True:

    for event in pygame.event.get():
        if event.type == QUIT:
            exit()
    if event.type == KEYDOWN:
        if event.key == K_f:
            Fullscreen = not Fullscreen
            if Fullscreen:
                screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32)
            else:
                screen = pygame.display.set_mode((640, 480), 0, 32)

    screen.blit(background, (0,0))
    pygame.display.update()

运行这个程序,默认还是窗口的,按“f ”,显示模式会在窗口和全屏之间切换。程序也没有什么难度,应该都能看明白。

可变尺寸的显示

虽然一般的程序窗口都能拖边框来改变大小,pygame的默认显示窗口是不行的,而事实上,很多游戏确实也不能改变显示窗口的大小,我们可以使用一个参数来改变这个默认行为。

background_image_filename = 'sushiplate.jpg'

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

SCREEN_SIZE = (640, 480)

pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32)

background = pygame.image.load(background_image_filename).convert()

while True:

    event = pygame.event.wait()
    if event.type == QUIT:
        exit()
    if event.type == VIDEORESIZE:
        SCREEN_SIZE = event.size
        screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32)
        pygame.display.set_caption("Window resized to "+str(event.size))

    screen_width, screen_height = SCREEN_SIZE
    # 这里需要重新填满窗口
    for y in range(0, screen_height, background.get_height()):
        for x in range(0, screen_width, background.get_width()):
            screen.blit(background, (x, y))

    pygame.display.update()

当你更改大小的时候,后端控制台会显示出新的尺寸,这里我们学习到一个新的事件VIDEORESIZE,它包含如下内容:

  • size  —  一个二维元组,值为更改后的窗口尺寸,size[0]为宽,size[1]为高
  • w  —  宽
  • h  —  一目了然,高;之所以多出这两个,无非是为了方便

注意:在我的Windows 7 64bit上运行的时候,一改变窗口大小就非法退出;在Linux机器上很正常,应该是系统的兼容性问题(Pygame还只支持32位),不过想来平时都不会更改游戏窗口大小,问题不大。

至于无边框的窗口等,看一看本教程的第一篇就能知道了,不再赘述。

其他、复合模式

我们还有一些其他的显示模式,但未必所有的操作系统都支持(放心windows、各种比较流行的Linux发行版都是没问题的),一般来说窗口就用0全屏就用FULLSCREEN,这两个总是OK的。

如果你想创建一个硬件显示(surface会存放在显存里,从而有着更高的速度),你必须和全屏一起使用:

screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE | FULLSCREEN, 32)

当然你完全可以把双缓冲(更快)DOUBLEBUF也加上,这就是一个很棒的游戏显示了,不过记得你要使用pygame.display.flip()来刷新显示。pygame.display.update()是将数据画到前面显示,而这个是交替显示的意思。

稍微说一下双缓冲的意思,可以做一个比喻:我的任务就是出黑板报,如果只有一块黑板,那我得不停的写,全部写完了稍微Show一下就要擦掉重写,这样一来别人看的基本都是我在写黑板报的过程,看到的都是不完整的黑板报;如果我有两块黑板,那么可以挂一块给别人看,我自己在底下写另一块,写好了把原来的换下来换上新的,这样一来别人基本总是看到完整的内容了。双缓冲就是这样维护两个显示区域,快速的往屏幕上换内容,而不是每次都慢慢地重画。

还有OPENGL模式,这是一个得到广泛应用的3D加速显示模式。不过一旦使用了这个模式,pygame中的2D图像函数就不能用了,我们会在以后讲详细的内容。

这次的东西不是很多,基本就是讲了一个显示参数,如果基础比较好,一看就明白了。不过还是建议实际的输入写一下巩固认识。下一回讲字体模块(游戏没图可以,没字咋整?)~尽请期待

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

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

  1. tangly

    第一个全屏切放 我win7下编译 好像没有通过 有时候感觉开启程序后 关闭不了 只能到任务管理器里面去关掉 这跟系统应该关系不大吧

    Reply
    1. w

      你应该是quit没有加载正确哦,可以检查下

      Reply
    2. 啊啊啊

      pygame和Python都是用的Tkinter的循环,有的命令会冲突导致关闭不了的问题,可以选择把文件保存后直接双击文件运行

      Reply
  2. xishui Post author

    @tangly: 我的可以比较正常的执行,如果是偶发性的不正常,我也说不清原因,可能和现在显卡高级了而pygame利用的借口还是陈旧的有关吧。但个人觉得这种切换操作在实际游戏中是非常少的,所以不用在意。

    Reply
  3. abc

    for y in range(0, screen_height, background.get_height()):
    for x in range(0, screen_width, background.get_width()):
    screen.blit(background, (x, y))
    楼主这两句FOR 看不懂,教教我

    Reply
    1. xishui Post author

      就是横向和纵向的填充,用背景图片的高和宽当步长,从零增长到窗口的高和宽,每次增长都把背景图片画一次(不用担心会画过界,不会出错的)。
      如果您是不明白range(start, end, step)的用法的话,只好请你自行再修炼。“妈妈再也不用担心我的编程,手持《Python核心编程》那里不会翻哪里……”

      Reply
      1. 哈哈哈~

        填充为什么不直接用screen.fill()呢

        Reply
  4. 77

    因为程序在我电脑跑起来时,拖拽窗口之后,又恢复到原来的形状所以我改了下代码,即可实现拖拽后留在当前形状:
    if event.type == VIDEORESIZE:
    SCREEN_SINZE = event.size
    screen = pygame.display.set_mode(event.size,RESIZABLE,32)
    pygame.display.set_caption(“window resized to”+str(event.size))
    #前面需定义全局变量screen_width和screen_height
    screen_width,screen_height = event.size
    for y in range(0,screen_height,background.get_height()):
    for x in range(0,screen_width,background.get_width()):
    screen.blit(background,(x,y))

    Reply
  5. 77

    @77: 额 竟然没有空格。。。if语句后面的5句是并列的 第二个for和最后一句逐步缩进

    Reply
  6. world77

    多谢楼主你的无私分享,这个系列我一定会看完,在此感谢你的资料

    Reply
  7. 有了没

    32位 resize 的时候挂掉、、、、 囧
    2.6的py 1.9.1的pygame o(╯□╰)o

    Reply
  8. Demon Wu

    Win7 python2.7 pygame1.9.1当尺寸比最开始的大就会发生错误,是为什么?

    Reply
  9. xumaomao

    一个有点题外话的问题:在resizable之后,怎么让窗口变大变小的同时图像跟随窗口尺寸缩放啊?

    Reply
  10. fox_lin

    我认为博主第一个例程(全屏与窗口切换那个)第18行的缩进有问题,不知道大家怎么看的?

    Reply
    1. 张晓雷

      没错。按第一次f一定执行第一条,但再按第二次后Fullscreen变False,然后执行第二条,变回全屏,以此类推,这样达到按F来回切换。

      Reply
  11. goonafly

    将屏幕拉大到大于SCREEN_SIZE时出项如下错误Fatal Python error: (pygame parachute) Segmentation Fault

    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application’s support team for more information.

    Reply
    1. dingyun

      我最近在写代码的时候也遇到了这个问题,请问你是怎么解决的?

      Reply
  12. who8736

    @goonafly:
    在20行前加一行就行:
    pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32)
    没弄明白为什么会这样

    Reply
  13. HengGeneral

    在 可变尺寸显示中的26-28表示窗口扩大一点,就再画一张图片…
    如何才能达到这样的效果: 窗口增大的同时, 图片也跟着增大?

    Reply
  14. HengGeneral

    Okay, I got it.
    把26-28换成backgound=background = pygame.transform.scale(background, screen_size) 更换位置即可

    Reply
        1. 木子

          可以替换,不过要把第29行改为
          screen.blit(background, (0, 0))

          Reply
  15. QXX

    py2.7+pygame1.9.1release,调整窗口大小是错误退出,这里http://stackoverflow.com/questions/18838464/pygame-crashes-when-i-try-to-resize-window 说:Try removing the color depth on the resize mode setting:
    screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE)。把”32″去掉后正常了。。。

    Reply
  16. 徐立冉

    我按照您的代码编辑好之后,只能从窗口切换到全屏,无法切换回窗口,请问是什么原因

    Reply
  17. 木头

    当,刚看到可以全屏的时候,立马改写了代码fullscreen,立即运行。结果,结果,全屏了!(很是高兴中)
    咦,突然发现退不出来了,退不出来了(由于linux,没有像win下的神码任务管理器)。最后,只能借用电脑远程进来,kill掉!否则得按下重启键了。噢,下次要想清楚了再运行(不知道有没有跟 木头 一样的呢,嘿嘿)。

    Reply
  18. lucy56198

    我是在mac上运行的,写完set_mode((800*600))并且fill了一个颜色,但是显示出来的状态是,窗口大小确实是800*600,但是填充的大小却只占窗口的1/4并且在做一些鼠标事件的时候,鼠标的位置也会映射到填充的区域而不是直接在整个窗口中工作
    请问这是为什么呢

    Reply
    1. Simona

      mac下你可以全屏?应该点击键盘的什么触发啊?

      Reply
      1. leonzhao

        试了下,无论是SCALE还是SMOOTHSCALE,多次拖拽屏幕,还是会失真严重。
        解决方法,我尝试在每次SCALE之前,重新加载一次图片,就是再加一句
        background = pygame.image.load(background_image_filename).convert()。每次SCALE都是对原始图片,所以效果好了很多:)

        Reply
        1. 张伟

          图片拖拽变形是正常的啊, 比例改变了嘛,
          加这一句没有任何作用.
          不知道你说的是什么意思

          Reply
  19. May

    检查keydown的if部分被我放在for循环中了。
    case1. 放在while下,每次循环while的时候都要检查一次key.type==keydown。|| 也就是说每次while循环,检查两次key.type。
    case2. 放在for下,就只有发生事件的时候才会检查key.type。|| 每次while循环,检查一次key.type。

    我这样理解应该没错吧?
    测试了一下,两种都没有问题。

    ==================

    while True:
    for event in pygame.event.get():
    if event.type == QUIT:
    exit()
    #####################
    if event.type == KEYDOWN:
    if event.key == K_f:
    Fullscreen = not Fullscreen
    if Fullscreen:
    screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32)
    else:
    screen = pygame.display.set_mode((640, 480), 0, 32)
    ####################
    screen.blit(background, (0,0))
    pygame.display.update()
    ================

    Reply
    1. May

      “case1. 放在while下,每次循环while的时候都要检查一次key.type==keydown。|| 也就是说每次while循环,检查两次##### key.type ######。
      case2. 放在for下,就只有发生事件的时候才会检查key.type。|| 每次while循环,检查一次key.type。”

      措辞有点问题,就是想表达case1的成本高于case2.

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

  21. 小梦

    看了下官方文档,最新版本的pygame里面,update()和flip()的区别似乎已经基本没有了。不管哪个都会根据显示模式自动调整刷新模式,唯一的区别是update可以选择刷新区域

    Reply
  22. Pingback: 用Python和Pygame写游戏-从入门到精通(3) – 易可信blog系统

  23. 吴家威

    再一次提醒大家,别乱进全屏:)真是惨痛的教训

    Reply
  24. 为何我把key.type==keydown放到外部做成函数后,能全屏但不能缩小

    Reply
  25. 子虚

    我设置可变尺寸的窗口时,在while True循环之前就写了一个标题名,但是运行的时候没有显示,直接显示的“”Window resized to ” + str(event.size)”,这是为什么?

    Reply
  26. jiaqi

    我就想知道楼主这是什么主题,感觉看着好舒服,望楼主分享

    Reply
  27. 张伟

    event = pygame.event.wait()
    这一行, 之前学的时候都是 for event in pygame.event.get():

    Reply
  28. Pingback: PyOpenGL之3D界面详解(三)-识荒者

  29. 碧笛

    Fullscreen、FULLSCREEN、K_f 的大小写必须严格按楼主的来啊,受教了

    Reply

发表评论

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