10. Python脚本学习实战笔记十 街机游戏实现

10. Python脚本学习实战笔记十 街机游戏实现

本篇名言:“偶尔有烦恼,自己心情最重要;天天快乐当然好,也要风雨调味道;春风得意春虽好,毕竟四季轮流到;烦恼暂时全忘掉,生活定会乐逍”

                  最后来学习如果做一个小游戏。

1.  游戏背景

军士长指挥自己的士兵使用自我防御战术对抗以石榴、芒果、青梅和香蕉等新鲜水果入侵者。防御战术包括使用枪、释放老虎以及从敌人头顶扔下16吨重的秤砣。

游戏改变后,需要控制香蕉在自我防御过程中尽力视图存活下来。

游戏的运行效果应该和设计的一样,此外,代码应该模块化并且容易扩展。游戏状态可以作为另外一个有用的游戏需求,此外,添加新的状态也应能轻松地实现。

2.  工具及准备工作

需要新工具Pygame,从Pygame网站下载。

http://www.pygame.org/download.shtml 下载后直接双击安装即可。

(用于操作声音和图像的模块NumPy 此项目并不需要)。

2.1      Pygame

Pygame模块会自动导入其他的Pygame模块。

Pygame模块包括surface函数,可以返回一个新的surface对象。

Init函数是Pygame游戏的核心,必须在进入游戏的主事件循环之前调用。会自动初始化其他所有模块(比如font 和image)。

 

 

2.2      Pygame.locals

包括在你自己的模块作用域内使用的名字(变量)。包括事件类型、键和视频模式等的名字。

 

2.3      Pygame.display

包括处理pygame显示方式的函数。包括普通窗口和全屏模式。

Flip:更新显示

Update:更新一部分时候使用update.

Set_mode:设定显示的类型和尺寸。

Set_caption:设定pygame程序的标题

Get_surface:调用flip和blit前返回一个可用于发图的surface对象。

 

2.4      Pygame.font

包括font函数,用于表现不同的字体。

 

2.5      Pygame.sprite

游戏精灵,Group用做sprite对象的容器。调用group对象的update对象,会自动调用所有sprite对象的update方法。

 

2.6      Pygame.mouse

隐藏鼠标光标,获取鼠标位置。

2.7      Pygame.event

追踪鼠标单击、按键按下和释放等事件。

2.8      Pygame.image

用于处理保存在GIF、PNG或者JPEG文件内的图像。

 

 

 

 

 

 

 

 

 

3.  初次实现

实现Weight类(pygame.sprite.Sprite的子类)。

importsys, pygame

from pygame.localsimport *

fromrandom import randrange

 

class Weight(pygame.sprite.Sprite):

 

   def __init__(self):

        pygame.sprite.Sprite.__init__(self)

        #image and rect used when drawing sprite:

        self.image = weight_image

        self.rect = self.image.get_rect()

        self.reset()

 

   def reset(self):

        """

        Move the weight to a random position atthe top of the screen.

        """

        self.rect.top = -self.rect.height

        self.rect.centerx =randrange(screen_size[0])

 

   def update(self):

        """

        Update the weight for display in thenext frame.

        """

        self.rect.top += 1

 

        if self.rect.top > screen_size[1]:

            self.reset()

 

# Initialize things

pygame.init()

screen_size = 800, 600

pygame.display.set_mode(screen_size,FULLSCREEN)

pygame.mouse.set_visible(0)

 

# Load the weight image

weight_image = pygame.image.load('weight.png')

weight_image =weight_image.convert() # ...to match the display

 

# Create a sprite group and add aWeight

sprites =pygame.sprite.RenderUpdates()

sprites.add(Weight())

 

# Get the screen surface and fillit

screen =pygame.display.get_surface()

bg = (255, 255, 255) # White

screen.fill(bg)

pygame.display.flip()

 

# Used to erase the sprites:

def clear_callback(surf,rect):

   surf.fill(bg, rect)

 

whileTrue:

   # Check for quit events:

   for event in pygame.event.get():

        if event.type == QUIT:

            sys.exit()

        if event.type == KEYDOWN andevent.key == K_ESCAPE:

            sys.exit()

   # Erase previous positions:

   sprites.clear(screen, clear_callback)

   # Update all sprites:

   sprites.update()

   # Draw all sprites:

   updates = sprites.draw(screen)

   # Update the necessary parts of the display:

   pygame.display.update(updates)

将该文件和weight.png放在一个目录中,运行该文件即可。

4.  再次实现

将游戏逻辑和游戏对象分开,同时增加游戏配置文件。

4.1      Config.py

# Configuration file for Squish

# -----------------------------

 

# Feel free to modify the configuration variables below to taste.

# If the game is too fast or too slow, try to modify the speed

# variables.

 

# Change these to use other images in the game:

banana_image = 'banana.png'

weight_image = 'weight.png'

splash_image = 'weight.png'

 

# Change these to affect the general appearance:

screen_size = 800, 600

background_color = 255, 255, 255

margin = 30

full_screen = 1

font_size = 48

 

# These affect the behavior of the game:

drop_speed = 5

banana_speed = 10

speed_increase = 1

weights_per_level = 10

banana_pad_top = 40

banana_pad_side = 20

 

4.2      Objects.py

 

 

#Listing 29-3. The Squish Game Objects(objects.py)

import pygame, config, os

from random import randrange

 

"This module contains the game objects ofthe Squish game."

 

class SquishSprite(pygame.sprite.Sprite):

 

   """

   Generic superclass for all sprites in Squish.  The constructor

    takescare of loading an image, setting up the sprite rect, and

    thearea within which it is allowed to move. That area is governed

    by thescreen size and the margin.

   """

 

    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

       self.area = screen.get_rect().inflate(shrink, shrink)

 

 

class Weight(SquishSprite):

 

   """

    Afalling weight. It uses the SquishSprite constructor to set up

    itsweight image, and will fall with a speed given as a parameter

    to itsconstructor.

   """

 

    def__init__(self, speed):

       SquishSprite.__init__(self, config.weight_image)

       self.speed = speed

       self.reset()

 

    defreset(self):

       """

       Move the weight to the top of the screen (just out of sight)

       and place it at a random horizontal position.

       """

        x= randrange(self.area.left, self.area.right)

       self.rect.midbottom = x, 0

 

    defupdate(self):

       """

       Move the weight vertically (downwards) a distance

       corresponding to its speed. Also set the landed attribute

       according to whether it has reached the bottom of the screen.

       """

       self.rect.top += self.speed

       self.landed = self.rect.top >= self.area.bottom

 

 

class Banana(SquishSprite):

 

   """

    Adesperate banana. It uses the SquishSprite constructor to set up

    itsbanana image, and will stay near the bottom of the screen,

    withits horizontal position governed by the current mouse

   position (within certain limits).

   """

 

    def __init__(self):

       SquishSprite.__init__(self, config.banana_image)

       self.rect.bottom = self.area.bottom

 

        #These paddings represent parts of the image where there is

        #no banana. If a weight moves into these areas, it doesn't

        # constitute a hit (or, rather, asquish):

       self.pad_top = config.banana_pad_top

       self.pad_side = config.banana_pad_side

 

    defupdate(self):

       """

       Set the Banana's center x-coordinate to the current mouse

       x-coordinate, and then use the rect method clamp to ensure

       that the Banana stays within its allowed range of motion.

       """

       self.rect.centerx = pygame.mouse.get_pos()[0]

       self.rect = self.rect.clamp(self.area)

 

    deftouches(self, other):

       """

       Determines whether the banana touches another sprite (e.g., a

       Weight). Instead of just using the rect method colliderect, a

       new rectangle is first calculated (using the rect method

       inflate with the side and top paddings) that does not include

       the 'empty' areas on the top and sides of the banana.

       """

        #Deflate the bounds with the proper padding:

       bounds = self.rect.inflate(-self.pad_side, -self.pad_top)

        #Move the bounds so they are placed at the bottom of the Banana:

       bounds.bottom = self.rect.bottom

        #Check whether the bounds intersect with the other object's rect:

       return bounds.colliderect(other.rect)

 

 

4.3      Squish.py

importos, sys, pygame

frompygame.locals import *

importobjects, config

 

"This modulecontains the main game logic of the Squish game."

 

class State:

 

   """

    A generic game state class that can handleevents and display

    itself on a given surface.

    """

 

   def handle(self,event):

        """

        Default event handling only deals withquitting.

        """

        if event.type == QUIT:

            sys.exit()

        if event.type == KEYDOWN andevent.key == K_ESCAPE:

            sys.exit()

 

   def firstDisplay(self,screen):

        """

        Used to display the State for the firsttime. Fills the screen

        with the background color.

        """

        screen.fill(config.background_color)

        #Remember to call flip, to make the changes visible:

        pygame.display.flip()

 

   def display(self,screen):

        """

        Used to display the State after it hasalready been displayed

        once. The default behavior is to donothing.

        """

        pass

 

 

class Level(State):

 

   """

    A game level. Takes care of counting howmany weights have been

    dropped, moving the sprites around,and other tasks relating to

    game logic.

    """

 

   def __init__(self,number=1):

        self.number = number

        #How many weights remain to dodge in this level?

        self.remaining =config.weights_per_level

 

        speed = config.drop_speed

        #One speed_increase added for each level above 1:

        speed += (self.number-1) * config.speed_increase

 

        #Create the weight and banana:

        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):

        "Updatesthe game state from the previous frame."

        #Update all sprites:

        self.sprites.update()

        #If the banana touches the weight, tell the game to switch to

        #a GameOver state:

        if self.banana.touches(self.weight):

            game.nextState = GameOver()

        #Otherwise, if the weight has landed, reset it. If all the

       #weights of this level have been dodged, tell the game to

        #switch to a LevelCleared state:

        elif self.weight.landed:

            self.weight.reset()

            self.remaining -= 1

            if self.remaining == 0:

                game.nextState = LevelCleared(self.number)

 

   def display(self,screen):

        """

        Displays the state after the firstdisplay (which simply wipes

        the screen). As opposed tofirstDisplay, this method uses

        pygame.display.update with a list ofrectangles that need to

        be updated, supplied fromself.sprites.draw.

        """

        screen.fill(config.background_color)

        updates = self.sprites.draw(screen)

        pygame.display.update(updates)

 

 

class Paused(State):

 

   """

    A simple, paused game state, which may bebroken out of by pressing

    either a keyboard key or the mouse button.

    """

 

   finished = 0  # Has the userended the pause?

   image = None  # Set this toa file name if you want an image

   text = ''     # Set this tosome informative text

 

   def handle(self,event):

        """

        Handles events by delegating to State(which handles quitting

        in general) and by reacting to keypresses and mouse

        clicks. If a key is pressed or themouse is clicked,

        self.finished is set to true.

        """

        State.handle(self, event)

        if event.type in[MOUSEBUTTONDOWN, KEYDOWN]:

            self.finished = 1

 

   def update(self,game):

        """

        Update the level. If a key has beenpressed or the mouse has

        been clicked (i.e., self.finished istrue), tell the game to

        move to the state represented byself.nextState() (should be

        implemented by subclasses).

        """

        if self.finished:

            game.nextState = self.nextState()

 

   def firstDisplay(self,screen):

        """

        The first time the Paused state isdisplayed, draw the image

        (if any) and render the text.

        """

        #First, clear the screen by filling it with the background color:

        screen.fill(config.background_color)

 

        #Create a Font object with the default appearance, and specified size:

        font = pygame.font.Font(None, config.font_size)

 

        #Get the lines of text in self.text, ignoring empty lines at

        #the top or bottom:

        lines = self.text.strip().splitlines()

 

        #Calculate the height of the text (using font.get_linesize()

        #to get the height of each line of text):

        height = len(lines) *font.get_linesize()

 

        #Calculate the placement of the text (centered on the screen):

        center, top = screen.get_rect().center

        top -= height // 2

 

        #If there is an image to display...

        if self.image:

            #load it:

            image = pygame.image.load(self.image).convert()

            #get its rect:

            r = image.get_rect()

            #move the text down by half the image height:

            top += r.height // 2

            #place the image 20 pixels above the text:

            r.midbottom = center, top - 20

            #blit the image to the screen:

            screen.blit(image, r)

 

        antialias = 1    #Smooth the text

        black = 0, 0, 0  #Render it as black

 

        #Render all the lines, starting at the calculated top, and

        #move down font.get_linesize() pixels for each line:

        for line in lines:

            text = font.render(line.strip(),antialias, black)

            r = text.get_rect()

            r.midtop = center, top

            screen.blit(text, r)

            top += font.get_linesize()

 

        #Display all the changes:

        pygame.display.flip()

 

 

class Info(Paused):

 

   """

    A simple paused state that displays someinformation about the

    game. It is followed by a Level state (thefirst 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):

 

   """

    A paused state that displays a splash imageand a welcome

    message. It is followed by an Info state.

    """

 

   nextState = Info

   image = config.splash_image

   text = '''

    Welcome to Squish,

    the game of Fruit Self-Defense'''

 

 

class LevelCleared(Paused):

 

   """

    A paused state that informs the user thathe or she has cleared a

    given level.  It is followed by the next level state.

    """

 

   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):

 

   """

    A state that informs the user that he orshe has lost the

    game. It is followed by the first level.

    """

 

   nextState = Level

   text = '''

    Game Over

    Click to Restart, Esc to Quit'''

 

 

class Game:

 

   """

    A game object that takes care of the mainevent loop, including

    changing between the different game states.

    """

 

   def __init__(self,*args):

        #Get the directory where the game and the images are located:

        path = os.path.abspath(args[0])

        dir = os.path.split(path)[0]

        #Move to that directory (so that the images files may be

        #opened later on):

        os.chdir(dir)

        #Start with no state:

        self.state = None

        #Move to StartUp in the first event loop iteration:

        self.nextState = StartUp()

 

   def run(self):

        """

        This method sets things in motion. Itperforms some vital

        initialization tasks, and enters themain event loop.

        """

        pygame.init() #This is needed to initialize all the pygame modules

 

        #Decide whether to display the game in a window or to use the

        #full screen:

        flag = 0                  # Default (window) mode

 

        if config.full_screen:

            flag = FULLSCREEN      # Full screenmode

        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)

 

        #The main loop:

        whileTrue:

            #(1) If nextState has been changed, move to the new state, and

            #     display it (for the first time):

            if self.state != self.nextState:

                self.state = self.nextState

                self.state.firstDisplay(screen)

            #(2) Delegate the event handling to the current state:

            for event in pygame.event.get():

                self.state.handle(event)

            #(3) Update the current state:

            self.state.update(self)

            #(4) Display the current state:

            self.state.display(screen)

 

 

if__name__ == '__main__':

   game = Game(*sys.argv)

   game.run()

 

将objects.py,squish.py ,以及banana.png,weight.png放在同一个目录下,执行

Python squish.py即可。

 

                  结束,大家可以对该代码进行扩充学习。

最后告诉大家一个小秘密,大伙和蛤蟆一起学习的其实是《Python编程基础》,是不是很开心,就这样看完了一本书。

祝好运~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值