第29章 项目10:DIY街机游戏
1.问题
“Self-Defense Against Fresh Fruit”:军士长指挥自己的士兵使用自我防御战术对抗以石榴、芒果、青梅和香蕉等新鲜水果入侵者。防御战术包括使用枪、释放老虎以及从敌人头顶扔下16吨重的秤砣。游戏改变后,需要控制香蕉在自我防御过程中尽力视图存活下来。
游戏的运行效果应该和设计的一样,此外,代码应该模块化并且容易扩展。游戏状态可以作为另外一个有用的游戏需求,此外,添加新的状态也应能轻松地实现。
2.工具 —— Pygame
32位下载地址:http://www.pygame.org/download.shtml
下载完成后双击安装即可。
64位下载地址:http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame
使用pip install D:\python64\pygame-1.9.2b1-cp27-cp27m-win_amd64.whl安装。
未报错,安装成功。
(1) Pygame
Pygame模块会自动导入其他的Pygame模块。
Pygame模块包括surface函数,可以返回一个新的surface对象。
Init函数是Pygame游戏的核心,必须在进入游戏的主事件循环之前调用。会自动初始化其他所有模块(比如font 和image)。
(2) Pygame.locals
包括在你自己的模块作用域内使用的名字(变量)。包括事件类型、键和视频模式等的名字。
(3) Pygame.display
包括处理pygame显示方式的函数。包括普通窗口和全屏模式。
Flip:更新显示
Update:更新一部分时候使用update.
Set_mode:设定显示的类型和尺寸。
Set_caption:设定pygame程序的标题
Get_surface:调用flip和blit前返回一个可用于发图的surface对象。
(4) Pygame.font
包括font函数,用于表现不同的字体。
(5) Pygame.sprite
游戏精灵,Group用做sprite对象的容器。调用group对象的update对象,会自动调用所有sprite对象的update方法。
(6) Pygame.mouse
隐藏鼠标光标,获取鼠标位置。
(7) Pygame.event
追踪鼠标单击、按键按下和释放等事件。
(8) Pygame.image
用于处理保存在GIF、PNG或者JPEG文件内的图像。
3.初次实现
图片文件:weight.png和banana.jpg
这两个图片太大,使用时截成小图放入目录中。
29-1 weights.py ——简单的“天上掉秤砣动画”
# coding=utf-8
import sys,
pygame
from pygame.locals
import *
from random
import randrange
pygame.init()
class Weight(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# 在画sprite时使用的图像和矩形
self.image = weight_image
self.rect
= self.image.get_rect()
self.reset()
def reset(self):
"""
将秤砣移动到屏幕顶端的随机位置。
"""
self.rect.top = -self.rect.height
self.rect.centerx
= randrange(screen_size[0])
def update(self):
"""
更新秤砣,显示下一帧
"""
self.rect.top += 1
if self.rect.top > screen_size[1]:
self.reset()
# 初始化
pygame.init()
screen_size = 800, 600
pygame.display.set_mode(screen_size,
FULLSCREEN)
pygame.mouse.set_visible(0)
# 载入秤砣的图像
weight_image =
pygame.image.load('weight.png')
weight_image = weight_image.convert() #
...to match the display
# weight_image = pygame.image.load('weight.png').convert_alpha()# 转化
# 创建一个子图片组(sprite group),增加Weight
sprites =
pygame.sprite.RenderUpdates()
sprites.add(Weight())
# 获取屏幕并填充
screen = pygame.display.get_surface()
bg = (255, 255, 255) # 白色
screen.fill(bg)
pygame.display.flip() # 全屏更新
# 用于清除子图形
def clear_callback(surf,
rect):
surf.fill(bg, rect)
while True:
# 检查退出事件:
for
event in
pygame.event.get():
if event.type == QUIT:
sys.exit()
if event.type == KEYDOWN and
event.key == K_ESCAPE:
sys.exit()
# 清除前面的位置
sprites.clear(screen, clear_callback)
# 更新所有子图形:
sprites.update()
# 绘制所有子图形:
updates = sprites.draw(screen)
# 更新所需的显示部分:
pygame.display.update(updates)
运行后截图:
4.再次实现
29-2 config.py —— Squish的配置文件
#
coding=utf-8
# Squish的配置文件
# ------------------------------
# 请放心地按照自己的喜好修改下面的配置文件
# 如果游戏太快或太慢,请修改速度变量
# 改变这些设置,一遍在游戏中使用其他图像:
banana_image = 'banana.png'
weight_image = 'weight.png'
splash_image = 'weight.png'
# 改变这些设置以影响一般的外观:
screen_size = 800, 600
background_color = 255, 255, 255
margin = 30
full_screen = 1
font_size = 48
# 这些设置会影响游戏的表现行为:
drop_speed = 1
banana_speed = 10
speed_increase = 1
weights_per_level = 10
banana_pad_top = 40
banana_pad_side = 20
29-3 objects.py —— Squish的Game对象
#
coding=utf-8
import pygame,
config, os
from random
import randrange
# 这个模块包括Squish的游戏对象。
class SquishSprite(pygame.sprite.Sprite):
"""
Squish中所有子图形的范型超类。
"""
def
__init__(self,
image):
pygame.sprite.Sprite.__init__(self)
self.image
= pygame.image.load(image).convert()
self.rect
= self.image.get_rect()
screen =
pygame.display.get_surface()
shrink = -config.margin * 2 #
-60
size =
screen.get_rect(); #
(0,0,800,600)
self.area
= screen.get_rect().inflate(shrink, shrink)
# (30,30,740,540)
print(self.area)
class Weight(SquishSprite):
"""
落下的秤砣。它使用了SquishSprite构造函数设置它的秤砣图像,并且会以给定的速度作为
构造函数的参数来设置下落的速度。
"""
def
__init__(self,
speed):
SquishSprite.__init__(self, config.weight_image)
self.speed
= speed
self.reset()
def reset(self):
"""
将秤砣移动到屏幕顶端(视线外),放置到任意水平位置上。
"""
# random between (30,770)
x = randrange(self.area.left,
self.area.right)
self.rect.midbottom
= x, 0
def update(self):
"""
根据它的速度将秤砣垂直移动(下落)一段距离。并且根据它是否触及屏幕底端来设置landed属性。
"""
self.rect.top += self.speed
self.landed
= self.rect.top >= self.area.bottom
class Banana(SquishSprite):
"""
绝望的香蕉。它使用SquishSprite构造函数设置香蕉的图像,并且会停留在屏幕底端。
它的水平位置由当前的鼠标位置(有一定限制)决定
"""
def
__init__(self):
SquishSprite.__init__(self, config.banana_image)
self.rect.bottom
= self.area.bottom
# 在没有香蕉的部分进行填充。如果秤砣移动到这些区域,它不会被判定为碰撞(或者说是将香蕉压扁):
self.pad_top = config.banana_pad_top
self.pad_side
= config.banana_pad_side
def update(self):
"""
将Banana中心点的横坐标设定为当前鼠标指针的横坐标,并且使用rec的clamp方法确保Banana停留在所允许的范围内。
"""
self.rect.centerx = pygame.mouse.get_pos()[0]
self.rect
= self.rect.clamp(self.area)
def touches(self,
other):
"""
确定香蕉是否触碰到了另外的子图形(比如秤砣)。除了使用rec的colliderect方法外,
首先要计算一个不包括香蕉图像顶端和侧边“空区域”的新矩形(使用rect的inflate方法对顶端和侧边进行填充)。
"""
# 使用适当的填充缩小边界:
bounds = self.rect.inflate(-self.pad_side, -self.pad_top)
# 移动边界,将它们放置到banana的底部。
bounds.bottom = self.rect.bottom
# 检查边界是否和其他对象的rect交叉。
return
bounds.colliderect(other.rect)
29-4 squish.py —— 主Game模块
#
coding=utf-8
import os,
sys, pygame
from pygame.locals
import *
import objects,
config
# 这个模块包括Squish游戏的主要游戏逻辑。
class State:
"""
范型游戏状态类,可以处理时间并在给定的表面上显示自身。
"""
def
handle(self, event):
"""
只处理退出时间的默认事件处理。
"""
if
event.type == QUIT:
sys.exit()
if event.type == KEYDOWN and
event.key == K_ESCAPE:
sys.exit()
def firstDisplay(self,
screen):
"""
用于第一次显示状态。使用背景色填充屏幕。
"""
screen.fill(config.background_color)
# 记得要使用flip,让更改可见
pygame.display.flip()
def display(self,
screen):
"""
用于在已经显示过一次状态后再次显示。默认的行为是什么都不做。
"""
pass
class Level(State):
"""
游戏等级。用于计算已经落下了多少秤砣,移动子图形以及其他和游戏逻辑相关的任务。
"""
def
__init__(self,
number=1):
self.number
= number
# 本关内还要落下多少秤砣?
self.remaining = config.weights_per_level
speed = config.drop_speed
# 为每个大于1 的等级都增加一个speed_increase
speed += (self.number
- 1) * config.speed_increase
# 创建秤砣和香蕉:
self.weight = objects.Weight(speed)
self.banana
= objects.Banana()
both = self.weight,
self.banana
# This could contain more sprites...
self.sprites
= pygame.sprite.RenderUpdates(both)
def update(self,
game):
"从前一帧更新游戏状态"
# 更新所有子图形:
self.sprites.update()
# 如果香蕉碰到了秤砣,那么告诉游戏切换到GameOver状态::
if self.banana.touches(self.weight):
game.nextState = GameOver()
# 否则在秤砣落地时将其复位。
# 如果在本馆内所有秤砣都落下了,则让游戏切换到LevelCleared 状态::
elif
self.weight.landed:
self.weight.reset()
self.remaining
-= 1
if self.remaining == 0:
game.nextState =
LevelCleared(self.number)
def display(self,
screen):
"""
在第一次显示(只清空屏幕)后显示状态。与firstDisplay不同,这个方法使用pygame.display.update对
self.sprites.draw提供的、需要更新的矩形列表进行更新。
"""
screen.fill(config.background_color)
updates = self.sprites.draw(screen)
pygame.display.update(updates)
class Paused(State):
"""
简单的暂停游戏状态,按下键盘上任意键或者点击鼠标都会结束这个状态。
"""
finished = 0 # 用户结束暂停了吗?
image = None # 如果需要图片的话,将这个变量设置为文件名
text = ''
# 将它设定为一些提示性文本
def
handle(self, event):
"""
通过对State进行委托(一般处理退出事件)以及对按键和鼠标点击最、作为反应来处理事件。
如果键被按下或者鼠标被点击,将self.finished设定为真。
"""
State.handle(self,
event)
if event.type in [MOUSEBUTTONDOWN, KEYDOWN]:
self.finished
= 1
def update(self,
game):
"""
更新等级。如果按键被按下或者鼠标被点击(比如self.finished为真),那么告诉我们切换到下一个
由self.nextState()表示的状态(应该由子类实现)
"""
if
self.finished:
game.nextState = self.nextState()
def firstDisplay(self,
screen):
"""
暂停状态第一次出现时,绘制图像(如果有的话)并且生成文本。
"""
#首先,使用填充背景色的方式清空屏幕:
screen.fill(config.background_color)
# 使用默认的外观和指定的大小创建Font对象
font = pygame.font.Font(None, config.font_size)
# 获取self.text中的文本行,忽略开头和结尾的空行:
lines = self.text.strip().splitlines()
# 计算文本的高度(使用 font.get_linesize())以获取每行文本的高度:
height = len(lines) *
font.get_linesize()
# 计算文本的放置位置(屏幕中心):
center, top =
screen.get_rect().center #
为400,300
top -= height // 2 #
260
# 如果有图片要显示的话...
if
self.image:
# 载入图片:
image = pygame.image.load(self.image).convert()
# 获取它的rect:
r = image.get_rect() # 为rect(0,0,166,132)
# 将图像向下移动其高度的一半的距离:
top += r.height // 2 #
326
# 将图片放置在文本上方20像素处:
r.midbottom = center, top - 20 #
400,306
# 将图像移动到屏幕上:
screen.blit(image, r)
antialias = 1 #
Smooth the text
black = 0, 0, 0 #
Render it as black
# 生成所有行,从计算过的top开始,并且对于每一行向下移动font.get_linesize()像素:
for
line in
lines:
text =
font.render(line.strip(), antialias, black)
r = text.get_rect() # 0,0,312,37
r.midtop = center, top #
400,326
screen.blit(text, r)
top += font.get_linesize()
# 显示所有更改:
pygame.display.flip()
class Info(Paused):
"""
简单的暂停状态,显示有关游戏的信息。在Level状态后显示(第一级)
"""
nextState = Level
text = '''''
In this game you are a banana,
trying to survive a course in
self-defense against fruit, where the
participants will "defend"
themselves
against you with a 16 ton weight.'''
class StartUp(Paused):
"""
显示展示图片和欢迎信息的暂停状态。在Info状态后显示。
"""
nextState = Info
image = config.splash_image
text = '''''
Welcome to Squish,
the game of Fruit Self-Defense'''
class LevelCleared(Paused):
"""
提示用户过关的暂停状态。在next
level状态后显示。
"""
def
__init__(self,
number):
self.number
= number
self.text
= '''''Level %i cleared
Click to start next level''' % self.number
def nextState(self):
return Level(self.number+1)
class GameOver(Paused):
"""
提示用户输掉游戏的状态。在first
level后显示。
"""
nextState = Level
text = '''''
Game Over
Click to Restart, Esc to Quit'''
class Game:
"""
负责主事件循环的游戏对象,任务不包括在不同状态间切换。
"""
def
__init__(self,
*args):
# 获取游戏和图像放置的目录::
path = os.path.abspath(args[0]) #
当前代码文件路径
dir = os.path.split(path)[0] #
代码目录
# 移动那个目录(这样图片文件可以在随后打开):
os.chdir(dir) # cd 到代码目录
# 无状态方式启动:
self.state = None
# 在第一个事件循环迭代中移动到StartUp
self.nextState = StartUp()
def run(self):
"""
这个方法动态设定变量。进行一些重要的初始化工作,并且进入主事件循环。
"""
pygame.init() # 初始化所有 pygame 模块。
# 决定以窗口模式还是全屏模式显示游戏
flag = 0 #
默认窗口
if
config.full_screen:
flag = FULLSCREEN # 全屏模式
screen_size = config.screen_size
screen =
pygame.display.set_mode(screen_size, flag)
pygame.display.set_caption('Fruit
Self Defense')
pygame.mouse.set_visible(False)
# 主循环:
while
True:
# (1) 如果nextState被修改了,那么移动到新状态,并且显示它(第一次)
if
self.state != self.nextState:
self.state
= self.nextState
self.state.firstDisplay(screen)
# (2)代理当前状态的事件处理:
for
event in
pygame.event.get():
self.state.handle(event)
# (3) 更新当前状态:
self.state.update(self)
# (4) 显示当前状态:
# time.sleep( 0.5 )
self.state.display(screen)
if __name__
== '__main__':
# print(sys.argv)
game = Game(*sys.argv)
game.run()
运行后截图:
4.再次实现
29-2 config.py —— Squish的配置文件
#
coding=utf-8
# Squish的配置文件
# ------------------------------
# 请放心地按照自己的喜好修改下面的配置文件
# 如果游戏太快或太慢,请修改速度变量
# 改变这些设置,一遍在游戏中使用其他图像:
banana_image = 'banana.png'
weight_image = 'weight.png'
splash_image = 'weight.png'
# 改变这些设置以影响一般的外观:
screen_size = 800, 600
background_color = 255, 255, 255
margin = 30
full_screen = 1
font_size = 48
# 这些设置会影响游戏的表现行为:
drop_speed = 1
banana_speed = 10
speed_increase = 1
weights_per_level = 10
banana_pad_top = 40
banana_pad_side = 20
29-3 objects.py —— Squish的Game对象
#
coding=utf-8
import pygame,
config, os
from random
import randrange
# 这个模块包括Squish的游戏对象。
class SquishSprite(pygame.sprite.Sprite):
"""
Squish中所有子图形的范型超类。
"""
def
__init__(self,
image):
pygame.sprite.Sprite.__init__(self)
self.image
= pygame.image.load(image).convert()
self.rect
= self.image.get_rect()
screen =
pygame.display.get_surface()
shrink = -config.margin * 2 #
-60
size =
screen.get_rect(); #
(0,0,800,600)
self.area
= screen.get_rect().inflate(shrink, shrink)
# (30,30,740,540)
print(self.area)
class Weight(SquishSprite):
"""
落下的秤砣。它使用了SquishSprite构造函数设置它的秤砣图像,并且会以给定的速度作为
构造函数的参数来设置下落的速度。
"""
def
__init__(self,
speed):
SquishSprite.__init__(self, config.weight_image)
self.speed
= speed
self.reset()
def reset(self):
"""
将秤砣移动到屏幕顶端(视线外),放置到任意水平位置上。
"""
# random between (30,770)
x = randrange(self.area.left,
self.area.right)
self.rect.midbottom
= x, 0
def update(self):
"""
根据它的速度将秤砣垂直移动(下落)一段距离。并且根据它是否触及屏幕底端来设置landed属性。
"""
self.rect.top += self.speed
self.landed
= self.rect.top >= self.area.bottom
class Banana(SquishSprite):
"""
绝望的香蕉。它使用SquishSprite构造函数设置香蕉的图像,并且会停留在屏幕底端。
它的水平位置由当前的鼠标位置(有一定限制)决定
"""
def
__init__(self):
SquishSprite.__init__(self, config.banana_image)
self.rect.bottom
= self.area.bottom
# 在没有香蕉的部分进行填充。如果秤砣移动到这些区域,它不会被判定为碰撞(或者说是将香蕉压扁):
self.pad_top = config.banana_pad_top
self.pad_side
= config.banana_pad_side
def update(self):
"""
将Banana中心点的横坐标设定为当前鼠标指针的横坐标,并且使用rec的clamp方法确保Banana停留在所允许的范围内。
"""
self.rect.centerx = pygame.mouse.get_pos()[0]
self.rect
= self.rect.clamp(self.area)
def touches(self,
other):
"""
确定香蕉是否触碰到了另外的子图形(比如秤砣)。除了使用rec的colliderect方法外,
首先要计算一个不包括香蕉图像顶端和侧边“空区域”的新矩形(使用rect的inflate方法对顶端和侧边进行填充)。
"""
# 使用适当的填充缩小边界:
bounds = self.rect.inflate(-self.pad_side, -self.pad_top)
# 移动边界,将它们放置到banana的底部。
bounds.bottom = self.rect.bottom
# 检查边界是否和其他对象的rect交叉。
return
bounds.colliderect(other.rect)
29-4 squish.py —— 主Game模块
#
coding=utf-8
import os,
sys, pygame
from pygame.locals
import *
import objects,
config
# 这个模块包括Squish游戏的主要游戏逻辑。
class State:
"""
范型游戏状态类,可以处理时间并在给定的表面上显示自身。
"""
def
handle(self, event):
"""
只处理退出时间的默认事件处理。
"""
if
event.type == QUIT:
sys.exit()
if event.type == KEYDOWN and
event.key == K_ESCAPE:
sys.exit()
def firstDisplay(self,
screen):
"""
用于第一次显示状态。使用背景色填充屏幕。
"""
screen.fill(config.background_color)
# 记得要使用flip,让更改可见
pygame.display.flip()
def display(self,
screen):
"""
用于在已经显示过一次状态后再次显示。默认的行为是什么都不做。
"""
pass
class Level(State):
"""
游戏等级。用于计算已经落下了多少秤砣,移动子图形以及其他和游戏逻辑相关的任务。
"""
def
__init__(self,
number=1):
self.number
= number
# 本关内还要落下多少秤砣?
self.remaining = config.weights_per_level
speed = config.drop_speed
# 为每个大于1 的等级都增加一个speed_increase
speed += (self.number
- 1) * config.speed_increase
# 创建秤砣和香蕉:
self.weight = objects.Weight(speed)
self.banana
= objects.Banana()
both = self.weight,
self.banana
# This could contain more sprites...
self.sprites
= pygame.sprite.RenderUpdates(both)
def update(self,
game):
"从前一帧更新游戏状态"
# 更新所有子图形:
self.sprites.update()
# 如果香蕉碰到了秤砣,那么告诉游戏切换到GameOver状态::
if self.banana.touches(self.weight):
game.nextState = GameOver()
# 否则在秤砣落地时将其复位。
# 如果在本馆内所有秤砣都落下了,则让游戏切换到LevelCleared 状态::
elif
self.weight.landed:
self.weight.reset()
self.remaining
-= 1
if self.remaining == 0:
game.nextState =
LevelCleared(self.number)
def display(self,
screen):
"""
在第一次显示(只清空屏幕)后显示状态。与firstDisplay不同,这个方法使用pygame.display.update对
self.sprites.draw提供的、需要更新的矩形列表进行更新。
"""
screen.fill(config.background_color)
updates = self.sprites.draw(screen)
pygame.display.update(updates)
class Paused(State):
"""
简单的暂停游戏状态,按下键盘上任意键或者点击鼠标都会结束这个状态。
"""
finished = 0 # 用户结束暂停了吗?
image = None # 如果需要图片的话,将这个变量设置为文件名
text = ''
# 将它设定为一些提示性文本
def
handle(self, event):
"""
通过对State进行委托(一般处理退出事件)以及对按键和鼠标点击最、作为反应来处理事件。
如果键被按下或者鼠标被点击,将self.finished设定为真。
"""
State.handle(self,
event)
if event.type in [MOUSEBUTTONDOWN, KEYDOWN]:
self.finished
= 1
def update(self,
game):
"""
更新等级。如果按键被按下或者鼠标被点击(比如self.finished为真),那么告诉我们切换到下一个
由self.nextState()表示的状态(应该由子类实现)
"""
if
self.finished:
game.nextState = self.nextState()
def firstDisplay(self,
screen):
"""
暂停状态第一次出现时,绘制图像(如果有的话)并且生成文本。
"""
#首先,使用填充背景色的方式清空屏幕:
screen.fill(config.background_color)
# 使用默认的外观和指定的大小创建Font对象
font = pygame.font.Font(None, config.font_size)
# 获取self.text中的文本行,忽略开头和结尾的空行:
lines = self.text.strip().splitlines()
# 计算文本的高度(使用 font.get_linesize())以获取每行文本的高度:
height = len(lines) *
font.get_linesize()
# 计算文本的放置位置(屏幕中心):
center, top =
screen.get_rect().center #
为400,300
top -= height // 2 #
260
# 如果有图片要显示的话...
if
self.image:
# 载入图片:
image = pygame.image.load(self.image).convert()
# 获取它的rect:
r = image.get_rect() # 为rect(0,0,166,132)
# 将图像向下移动其高度的一半的距离:
top += r.height // 2 #
326
# 将图片放置在文本上方20像素处:
r.midbottom = center, top - 20 #
400,306
# 将图像移动到屏幕上:
screen.blit(image, r)
antialias = 1 #
Smooth the text
black = 0, 0, 0 #
Render it as black
# 生成所有行,从计算过的top开始,并且对于每一行向下移动font.get_linesize()像素:
for
line in
lines:
text =
font.render(line.strip(), antialias, black)
r = text.get_rect() # 0,0,312,37
r.midtop = center, top #
400,326
screen.blit(text, r)
top += font.get_linesize()
# 显示所有更改:
pygame.display.flip()
class Info(Paused):
"""
简单的暂停状态,显示有关游戏的信息。在Level状态后显示(第一级)
"""
nextState = Level
text = '''''
In this game you are a banana,
trying to survive a course in
self-defense against fruit, where the
participants will "defend"
themselves
against you with a 16 ton weight.'''
class StartUp(Paused):
"""
显示展示图片和欢迎信息的暂停状态。在Info状态后显示。
"""
nextState = Info
image = config.splash_image
text = '''''
Welcome to Squish,
the game of Fruit Self-Defense'''
class LevelCleared(Paused):
"""
提示用户过关的暂停状态。在next
level状态后显示。
"""
def
__init__(self,
number):
self.number
= number
self.text
= '''''Level %i cleared
Click to start next level''' % self.number
def nextState(self):
return Level(self.number+1)
class GameOver(Paused):
"""
提示用户输掉游戏的状态。在first
level后显示。
"""
nextState = Level
text = '''''
Game Over
Click to Restart, Esc to Quit'''
class Game:
"""
负责主事件循环的游戏对象,任务不包括在不同状态间切换。
"""
def
__init__(self,
*args):
# 获取游戏和图像放置的目录::
path = os.path.abspath(args[0]) #
当前代码文件路径
dir = os.path.split(path)[0] #
代码目录
# 移动那个目录(这样图片文件可以在随后打开):
os.chdir(dir) # cd 到代码目录
# 无状态方式启动:
self.state = None
# 在第一个事件循环迭代中移动到StartUp
self.nextState = StartUp()
def run(self):
"""
这个方法动态设定变量。进行一些重要的初始化工作,并且进入主事件循环。
"""
pygame.init() # 初始化所有 pygame 模块。
# 决定以窗口模式还是全屏模式显示游戏
flag = 0 #
默认窗口
if
config.full_screen:
flag = FULLSCREEN # 全屏模式
screen_size = config.screen_size
screen =
pygame.display.set_mode(screen_size, flag)
pygame.display.set_caption('Fruit
Self Defense')
pygame.mouse.set_visible(False)
# 主循环:
while
True:
# (1) 如果nextState被修改了,那么移动到新状态,并且显示它(第一次)
if
self.state != self.nextState:
self.state
= self.nextState
self.state.firstDisplay(screen)
# (2)代理当前状态的事件处理:
for
event in
pygame.event.get():
self.state.handle(event)
# (3) 更新当前状态:
self.state.update(self)
# (4) 显示当前状态:
# time.sleep( 0.5 )
self.state.display(screen)
if __name__
== '__main__':
# print(sys.argv)
game = Game(*sys.argv)
game.run()
运行后截图:game.MP4
附:摘自:http://eyehere.net/2011/python-pygame-novice-professional-1/
test.py
# coding=utf-8
background_image_filename
= 'sushiplate.jpg'
mouse_image_filename = 'fugu.png'
# 指定图像文件名称
import pygame
# 导入pygame库
from pygame.locals
import *
# 导入一些常用的函数和常量
from sys
import exit
# 向sys模块借一个exit函数用来退出程序
pygame.init()
# 初始化pygame,为使用硬件做准备
screen =
pygame.display.set_mode((640, 480), 0, 32)
# 创建了一个窗口
pygame.display.set_caption("Hello,
World!")
# 设置窗口标题
background =
pygame.image.load(background_image_filename).convert()
mouse_cursor = pygame.image.load(mouse_image_filename).convert_alpha()
# 加载并转换图像
while True:
# 游戏主循环
for
event in
pygame.event.get():
if event.type == QUIT:
# 接收到退出事件后退出程序
exit()
screen.blit(background, (0, 0))
# 将背景图画上去
x, y = pygame.mouse.get_pos()
# 获得鼠标位置
x -= mouse_cursor.get_width() / 2
y -= mouse_cursor.get_height() / 2
# 计算光标的左上角位置
screen.blit(mouse_cursor, (x, y))
# 把光标画上去
pygame.display.update()
# 刷新一下画面
运行后截图:
fugu.png和sushiplate.jpg