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

第29章 项目10:DIY街机游戏的更多相关文章

  1. 最牛叉的街机游戏合集 & 模拟器

    亲爱的小伙伴们,是否还记得那年我们玩的疯狂的街机游戏吗,街机中心提供400多个街机游戏,让你爽到底. 例如:拳皇96,拳皇97,恐龙新世纪.名将.快打旋风.惩罚者.魂斗罗.超级玛丽.雪山兄弟.忍者神龟 ...

  2. 业余时间折腾了个微信小程序版本的街机游戏模拟器(吾爱街机),8090后的童年回忆,欢迎大家体验

    好多年没来博客园了,有段时间想玩街机游戏,发现都需要下载安装,现在小程序这么流行,是不是可以集成到小程序里(无需下载,在线玩),出于这想法,就业余时间折腾了下,分享给大家,偶尔可以回味畅玩下. 中间遇 ...

  3. Atitit. 常用街机系统and 模拟器总结 snk neo geo cps mame sfc smc

    Atitit. 常用街机系统and 模拟器总结 snk neo geo cps mame sfc smc 1. #-------常用 游戏类型 1 2. 街机的历史 2 3. #=========== ...

  4. 你还记得2017年火爆的VR街机店,这一年他们过得还好吗?

    对于当下太过急于成功.一夜暴富的人们来说,似乎总是会急不可耐地去抓住每一个有可能成为大势的风口.在这份普遍存在的浮躁心理下,蕴含着极大的不确定性--既让大众认识到太多的创新产品和服务,也让很多参与者痛 ...

  5. 从零开始手把手教你使用原生JS+CSS3实现幸运水果机游戏

    项目体验地址 免费视频教程 游戏介绍 幸运水果机是一款街机游戏,游戏界面由24个方格拼接成一个正方形,每个方格中都有一个不同的水果图形,方格下都有一个小灯.玩家使用游戏币选择希望押注的目标,按下开始后 ...

  6. 开发者不容错过的10款免费JavaScript游戏引擎

    摘要:使用HTML5.JavaScript可以帮助开发者开发出各种与众不同的游戏及游戏特效,比如3D动画.Canvas等.本文介绍10款被广泛使用的基于HTML5的JavaScript游戏引擎. 在G ...

  7. 第29章 电容触摸屏—触摸画板—零死角玩转STM32-F429系列

    第29章     电容触摸屏—触摸画板 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  8. 完美编译街机模拟器MAME(Android版)基于MAME4all

    重新编译MAME4droid源码 github上开源项目MAME4all可将MAME模拟器运行在iOS和Android上,还有一个比较有名的叫MAME4droid(MAME for android), ...

  9. 【RL-TCPnet网络教程】第29章 NTP网络时间协议基础知识

    第29章      NTP网络时间协议基础知识 本章节为大家讲解NTP (Network Time Protocol,网络时间协议)和SNTP(简单网络时间协议,Simple Network Time ...

随机推荐

  1. Java Script基础(十二) 正则表达式

    一.正则表达式中常用的符号 虽然可以使用string函数来完成验证,但是这种验证方式不够严谨,而且编写比较麻烦.而正则表达式是一种描述字符模式的对象,由一些特殊的符号组成,其组成的字母模式用来匹配各种 ...

  2. Java Script基础(七) HTML DOM模型

    一.HTML DOM. HTML DOM的特性和方法是专门针对HTML的,HTML中的每个节点都是一个对象,通过访问属性和方法的方式,让一些DOM操作更加简便,在HTML DOM中有专门用来处理白哦个 ...

  3. spring事务管理出错。No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy ...

  4. java 集合类简单的分析1

          java中的集合类是很常见的,ArrayList,HashSet,HashMap等,现在就让我们来看下他们的各个类之间的关系图.      Collection ├List │├Linke ...

  5. codeforces 678C C. Joty and Chocolate(水题)

    题目链接: C. Joty and Chocolate time limit per test 1 second memory limit per test 256 megabytes input s ...

  6. 51nod 数数字(水题)

    题目链接: 数数字 基准时间限制:1 秒 空间限制:262144 KB 统计一下 aaa ⋯ aaa n个a × b 的结果里面有多少个数字d,a,b,d均为一位数. 样例解释: 3333333333 ...

  7. JAXL发送房间消息

    使用composer形式安装的JAXL <?php require_once "vendor/autoload.php"; $client = new JAXL(array( ...

  8. MVC 菜鸟学习记录1

    Asp.Net MVC 模式是一种表现模式.它将web应用程序分成三个主要组件即:    Model.View.Controller M:Model 主要是存储或者是处理数据的组件 Model其实是实 ...

  9. c#中的方法的定义和运用

    首先,理解下,函数和方法: 其实两者是一样的,只是个叫法不同. C#中叫做Method,中文叫方法: C++中称为Function,中文叫函数. 函数是Function,多指以前面向过程编程时候,将逻 ...

  10. UILabel自适应高、宽

    根据Label和字体大小自适应高度 - (CGFloat)getHeightWithLabel:(UILabel *)label andFontSize:(CGFloat)size { label.n ...