200行Python代码实现躲方块游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rectsuly/article/details/78306692

在这个游戏中,玩家操纵一个小人,躲避从屏幕顶部掉落的一大堆敌人,玩家躲避敌人的时间越久,得到的分数越高。
为了好玩,我们还会为游戏加入一些作弊模式,如果玩家按下“x”键,每一个敌人的速度就会降低到最慢,如果玩家按下“z”键,敌人就会反转方向,沿着屏幕向上移动而不是往下落。

import pygame, random, sys
from pygame.locals import *

WINDOWWIDTH = 600
WINDOWHEIGHT = 600
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 0)
FPS = 40
BADDIEMINSIZE = 10
BADDIEMAXSIZE = 40
BADDIEMINSPEED = 1
BADDIEMAXSPEED = 8
ADDNEWBADDIERATE = 6
PLAYERMOVERATE = 5

def terminate():
    pygame.quit()
    sys.exit()

def waitForPlayerToPressKey():
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE: # pressing escape quits
                    terminate()
                return

def playerHasHitBaddie(playerRect, baddies):
    for b in baddies:
        if playerRect.colliderect(b['rect']):
            return True
    return False

def drawText(text, font, surface, x, y):
    textobj = font.render(text, 1, TEXTCOLOR)
    textrect = textobj.get_rect()
    textrect.topleft = (x, y)
    surface.blit(textobj, textrect)

# set up pygame, the window, and the mouse cursor
pygame.init()
mainClock = pygame.time.Clock()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Dodger')
pygame.mouse.set_visible(False)

# set up fonts
font = pygame.font.SysFont(None, 48)

# set up sounds
gameOverSound = pygame.mixer.Sound('gameover.wav')
pygame.mixer.music.load('background.mid')

# set up images
playerImage = pygame.image.load('player.png')
playerRect = playerImage.get_rect()
baddieImage = pygame.image.load('baddie.png')

# show the "Start" screen
drawText('Dodger', font, windowSurface, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start.', font, windowSurface, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
waitForPlayerToPressKey()


topScore = 0
while True:
    # set up the start of the game
    baddies = []
    score = 0
    playerRect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
    moveLeft = moveRight = moveUp = moveDown = False
    reverseCheat = slowCheat = False
    baddieAddCounter = 0
    pygame.mixer.music.play(-1, 0.0)

    while True: # the game loop runs while the game part is playing
        score += 1 # increase score

        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()

            if event.type == KEYDOWN:
                if event.key == ord('z'):
                    reverseCheat = True
                if event.key == ord('x'):
                    slowCheat = True
                if event.key == K_LEFT or event.key == ord('a'):
                    moveRight = False
                    moveLeft = True
                if event.key == K_RIGHT or event.key == ord('d'):
                    moveLeft = False
                    moveRight = True
                if event.key == K_UP or event.key == ord('w'):
                    moveDown = False
                    moveUp = True
                if event.key == K_DOWN or event.key == ord('s'):
                    moveUp = False
                    moveDown = True

            if event.type == KEYUP:
                if event.key == ord('z'):
                    reverseCheat = False
                    score = 0
                if event.key == ord('x'):
                    slowCheat = False
                    score = 0
                if event.key == K_ESCAPE:
                        terminate()

                if event.key == K_LEFT or event.key == ord('a'):
                    moveLeft = False
                if event.key == K_RIGHT or event.key == ord('d'):
                    moveRight = False
                if event.key == K_UP or event.key == ord('w'):
                    moveUp = False
                if event.key == K_DOWN or event.key == ord('s'):
                    moveDown = False

            if event.type == MOUSEMOTION:
                # If the mouse moves, move the player where the cursor is.
                playerRect.move_ip(event.pos[0] - playerRect.centerx, event.pos[1] - playerRect.centery)

        # Add new baddies at the top of the screen, if needed.
        if not reverseCheat and not slowCheat:
            baddieAddCounter += 1
        if baddieAddCounter == ADDNEWBADDIERATE:
            baddieAddCounter = 0
            baddieSize = random.randint(BADDIEMINSIZE, BADDIEMAXSIZE)
            newBaddie = {'rect': pygame.Rect(random.randint(0, WINDOWWIDTH-baddieSize), 0 - baddieSize, baddieSize, baddieSize),
                        'speed': random.randint(BADDIEMINSPEED, BADDIEMAXSPEED),
                        'surface':pygame.transform.scale(baddieImage, (baddieSize, baddieSize)),
                        }

            baddies.append(newBaddie)

        # Move the player around.
        if moveLeft and playerRect.left > 0:
            playerRect.move_ip(-1 * PLAYERMOVERATE, 0)
        if moveRight and playerRect.right < WINDOWWIDTH:
            playerRect.move_ip(PLAYERMOVERATE, 0)
        if moveUp and playerRect.top > 0:
            playerRect.move_ip(0, -1 * PLAYERMOVERATE)
        if moveDown and playerRect.bottom < WINDOWHEIGHT:
            playerRect.move_ip(0, PLAYERMOVERATE)

        # Move the mouse cursor to match the player.
        pygame.mouse.set_pos(playerRect.centerx, playerRect.centery)

        # Move the baddies down.
        for b in baddies:
            if not reverseCheat and not slowCheat:
                b['rect'].move_ip(0, b['speed'])
            elif reverseCheat:
                b['rect'].move_ip(0, -5)
            elif slowCheat:
                b['rect'].move_ip(0, 1)

         # Delete baddies that have fallen past the bottom.
        for b in baddies[:]:
            if b['rect'].top > WINDOWHEIGHT:
                baddies.remove(b)

        # Draw the game world on the window.
        windowSurface.fill(BACKGROUNDCOLOR)

        # Draw the score and top score.
        drawText('Score: %s' % (score), font, windowSurface, 10, 0)
        drawText('Top Score: %s' % (topScore), font, windowSurface, 10, 40)

        # Draw the player's rectangle
        windowSurface.blit(playerImage, playerRect)

        # Draw each baddie
        for b in baddies:
            windowSurface.blit(b['surface'], b['rect'])

        pygame.display.update()

        # Check if any of the baddies have hit the player.
        if playerHasHitBaddie(playerRect, baddies):
            if score > topScore:
                topScore = score # set new top score
            break

        mainClock.tick(FPS)

    # Stop the game and show the "Game Over" screen.
    pygame.mixer.music.stop()
    gameOverSound.play()

    drawText('GAME OVER', font, windowSurface, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
    drawText('Press a key to play again.', font, windowSurface, (WINDOWWIDTH / 3) - 80, (WINDOWHEIGHT / 3) + 50)
    pygame.display.update()
    waitForPlayerToPressKey()

    gameOverSound.stop()

运行程序后,游戏界面如下图:
1

游戏导入的模块有pygame,random,sys和pygame.locals。pygame.locals模块包含了几个供Pygame使用的常量,如事件型(QUIT和KEYDOWN等)和键盘按键(K_ESCAPE和K_LEFT)等。

创建常量包含了窗口的宽和高、字体颜色和背景颜色,程序后面调用了mainClock.tick(FPS)则是设置了游戏每秒钟运行的帧数。敌人的宽度和高度均在BADDIEMINSIZE和BADDIEMAXSIZE之间。在游戏循环的每次迭代中,敌人从屏幕上落下的速率在每秒钟BADDIEMINSPEED到BADDIEMINSPEED多个像素之间。游戏循环的每经过ADDNEWBADDIERATE次迭代之后,将在窗口的顶部增加一个新的敌人。如果玩家的角色是移动的,在游戏循环的每次迭代中,PLAYERMOVERATE将保存玩家的角色在窗口中移动的像素数。

我们为游戏创建了几个函数。terminate()函数使游戏退出,waitForPlayerToPressKey()函数有一个无限循环,只有当接收到一个KEYDOWN或QUIT事件时,才会跳出该循环。在循环开始处,pygame.event.get()返回了要检查的事件对象的一个列表。

当程序等待玩家按键的时候,如果玩家关闭了这个窗口,Pygame将生成一个QUIT事件。在这种情况下,调用了terminate()函数。如果接收到一个KEYDOWN事件,那么应该先判断是否按下了ESC键。如果没有生成一个QUIT或KEYDOWN事件,那么代码将保持循环。由于循环什么都没有做,这使得游戏看上去像是已经冻结了,直到玩家按下一个键。

如果玩家的角色和一个敌人碰撞,playerHasHitBaddie()函数将返回True。在Pygame中显示文本,要比直接调用print()函数多花一些步骤,但是,如果把这些代码放入到一个名为drawText()的函数中,那么要在屏幕上显示文本,只需要调用drawText()函数即可。

完成常量和函数的编写之后,下面开始调用创建窗口和时钟的Pygame函数。pygame.init()函数创建了Pygame。pygame.time.Clock()对象保存在mainClock变量中,帮助我们防止程序运行得太快。pygame.display.set_mode()函数创建了一个新的Surface对象,用于在屏幕上显示窗口。pygame.display.set_caption()函数设置了窗口的标题,pygame.mouse.set_visible(False)告诉Pygame上光标不可见,这是因为我们只想要鼠标能够移动屏幕上的角色,而不想让鼠标的光标妨碍到屏幕上的角色的图像。

接下来,创建Sound对象,并且设置背景音乐,背景音乐将在游戏期间持续播放,但是只有当玩家输掉了游戏,才会播放Sound对象。pygame.mixer.music.load()函数加载了一个声音文件以播放背景音乐。这个函数没有返回任何对象,并且每次只能加载一个背景音乐文件。然后加载图像文件用于屏幕上的玩家和角色敌人。玩家角色的图像存储在player.png中,敌人的角色图像存储在baddie.png中。所有敌人角色看上去都是一样的,所以只要为它们准备一个图像文件就可以了。

当游戏第一次启动时,在屏幕上显示“Dodger”名称,然后按下任意键可以开始游戏。当程序开始运行时,topScore变量中的值最初为0。任何时候,当玩家输掉游戏并且得分大于当前的topScore,就用这个更高的分数来替换topScore。

游戏循环的代码通过修改玩家和敌人的位置、处理Pygame生成的事件以及在屏幕上绘制游戏世界,来不断地更新游戏世界的状态。所有这些事件会在1秒钟内发生很多次,这使得游戏“实时”地运行。

有4种不同类型的事件要处理:QUIT、KEYDOWN、KEYUP和MOUSEMOTION。如果Event对象的type属性等于QUIT,则用户关闭了程序;如果事件的类型是KEYDOWN,那么玩家按下了一个按键,当玩家停止按键并且释放该键时,会产生KEYUP事件;在游戏运行中的任何时候,玩家都可以按下键盘上的Esc键来退出游戏。

对于鼠标事件,如果玩家点击鼠标按键,游戏不会做任何事情,但是当玩家移动鼠标的时候,游戏会作出相应。这就使得玩家在游戏中可以有两种方法来控制玩家角色:键盘和鼠标。当鼠标移动时,会产生MOUSEMOTION事件。MOUSEMOTION类型的Event对象,也有一个名为pos的属性,表示鼠标事件的位置。pos属性保存了一个元组,是鼠标光标在窗口中移动到的位置的X坐标和Y坐标。如果事件类型是MOUSEMOTION,玩家的角色将移动到鼠标光标的位置。

把所有数据结构都修改完之后,使用Pygame的图像函数来绘制游戏世界。由于每秒钟会执行多次游戏循环,在新的位置绘制敌人和玩家,会使得它们的移动看上去更平滑自然。

当玩家输掉游戏时,游戏停止播放背景音乐,并且播放“游戏结束”的声音效果。

代码资源:
https://github.com/rectsuly/Python_Dodger_Game

猜你喜欢

转载自blog.csdn.net/rectsuly/article/details/78306692
今日推荐