zoukankan      html  css  js  c++  java
  • Pygame 贪吃蛇

    代码

    #-*-encoding=utf-8-*-
    # Wormy(a Nibbles clone)
    # By Al Sweigart al@inventwithpython.com
    # http://inventwithpython.com/pygame
    # Copied by Lei Song@1743207528@qq.com
    import random,pygame,sys
    from pygame.locals import *
    
    FPS = 15
    WINDOWWIDTH = 640
    WINDOWHEIGHT = 480
    CELLSIZE = 20 # 指一个单独的格子的尺寸
    assert WINDOWWIDTH%CELLSIZE == 0,'Window width must be a multiple of cell size.' # 断言,窗口宽度必须是一个格子尺寸的整数倍
    assert WINDOWHEIGHT%CELLSIZE == 0,'Window height must be a multiple of cell size.' # 断言,窗口高度必须是一个格子尺寸的整数倍
    CELLWIDTH = int(WINDOWWIDTH /CELLSIZE)
    CELLHEIGHT = int (WINDOWHEIGHT/CELLSIZE)
    
    #          R G B
    WHITE = (255,255,255)
    BLACK = (0,0,0)
    RED = (255,0,0)
    GREEN = (0,255,0)
    DARKGREEN = (0,155,0)
    DARKGRAY = (40,40,40)
    BGCOLOR = BLACK
    
    UP = 'up'
    DOWN = 'down'
    LEFT = 'left'
    RIGHT = 'right'
    
    HEAD = 0 # syntactic sugar:index of the worm's head 语法糖,头部为0
    
    def main():
        global FPSCLOCK,DISPLAYSURF,BASICFONT
    
        pygame.init() # 初始化
        FPSCLOCK = pygame.time.Clock()
        DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
        BASICFONT = pygame.font.Font('freesansbold.ttf',18)
        pygame.display.set_caption('Wormy')
    
        showStartScreen()
        while True:
            runGame()
            showGameOverScreen()
    
    
    def runGame():
        # 确定一个随机的开始点
        startx = random.randint(5,CELLWIDTH - 6)
        starty = random.randint(5,CELLHEIGHT - 6)
        wormCoords = [{'x':startx,'y':starty},
                      {'x':startx-1,'y':starty},
                      {'x':startx-2,'y':starty}]#存储了身体,初始长度为3
        direction = RIGHT
    
        # 把苹果置于一个随机处
        apple = getRandomLocation()
    
        while True:# main game loop
            for event in pygame.event.get():# event handling loop
                if event.type==QUIT:
                    terminate()
                elif event.type == KEYDOWN:# 按下键盘,wasd或者箭头
                    if(event.key == K_LEFT or event.key == K_a)and direction != RIGHT:# 不能直接回头撞自己
                        direction = LEFT
                    elif(event.key == K_RIGHT or event.key == K_d)and direction != LEFT:
                        direction = RIGHT
                    elif(event.key == K_UP or event.key == K_w)and direction != DOWN:
                        direction = UP
                    elif(event.key == K_DOWN or event.key == K_s)and direction != UP:
                        direction = DOWN
                    elif event.key == K_ESCAPE:
                        terminate()
    
        # 检查它是否碰到自己或撞墙
            if wormCoords[HEAD]['x']==-1 or wormCoords[HEAD]['x']==CELLWIDTH or wormCoords[HEAD]['y']==-1 or wormCoords[HEAD]['y']==CELLHEIGHT:
                return# game over
            for wormBody in wormCoords[1:]:
                if wormBody['x']==wormCoords[HEAD]['x'] and wormBody['y']==wormCoords[HEAD]['y']:
                    return# game over
    
        # 检查它是否恰到苹果
            if wormCoords[HEAD]['x']==apple['x'] and wormCoords[HEAD]['y']==apple['y']:
                apple = getRandomLocation()
            else:
                del wormCoords[-1]# 删除尾部
    
            # 如何做出移动的动画效果呢?方法是在蛇头前不断添加一个格子
            if direction == UP:
                newHead = {'x':wormCoords[HEAD]['x'],'y':wormCoords[HEAD]['y']-1}# 因为向下为正
            elif direction == DOWN:
                newHead = {'x':wormCoords[HEAD]['x'],'y':wormCoords[HEAD]['y']+1}
            elif direction == LEFT:
                newHead = {'x':wormCoords[HEAD]['x']-1,'y':wormCoords[HEAD]['y']}
            elif direction == RIGHT:
                newHead = {'x':wormCoords[HEAD]['x']+1,'y':wormCoords[HEAD]['y']}
    
            wormCoords.insert(0,newHead)# 加新头
    
    
            # 绘制屏幕Drawing the Screen
            DISPLAYSURF.fill(BGCOLOR)
            drawGrid()
            drawWorm(wormCoords)
            drawApple(apple)
            drawScore(len(wormCoords)-3)
            pygame.display.update()# 这一句draws the display Surface to the actual computer screen
            FPSCLOCK.tick(FPS/4)
    
    # 绘制“Press a key”文本到屏幕上
    def drawPressKeyMsg():
        pressKeySurf = BASICFONT.render('Press a key to play.',True,DARKGRAY)
        pressKeyRect = pressKeySurf.get_rect()
        pressKeyRect.topleft = (WINDOWWIDTH-200,WINDOWHEIGHT-30)
        DISPLAYSURF.blit(pressKeySurf,pressKeyRect)
    #这个函数将被showStartScreen()和showGameOverScreen()两个函数调用
    
    def checkForKeyPress():
        if len(pygame.event.get(QUIT))>0:# 返回一个列表,列表里是在事件队列中所有QUIT的事件,若无QUIT事件则返回空列表[]
            terminate()
    
        keyUpEvents = pygame.event.get(KEYUP)
        if len(keyUpEvents)==0:
            return None
        if keyUpEvents[0].key == K_ESCAPE:# 按了Esc键
            terminate()
        return keyUpEvents[0].key
    
    # 开始屏幕
    def showStartScreen():
        titleFont = pygame.font.Font('freesansbold.ttf',100)
        titleSurf1 = titleFont.render('Wormy!',True,WHITE,DARKGREEN)# 白字,墨绿背景
        titleSurf2 = titleFont.render('Wormy!',True,GREEN)# 绿字,透明背景
    
        degrees1 = 0
        degrees2 = 0
        while True:
            DISPLAYSURF.fill(BGCOLOR)
            rotatedSurf1 = pygame.transform.rotate(titleSurf1,degrees1)# 不会改变titleSurf1,而是返回一个新的Surface,上面画着旋转后的图像
            rotatedRect1 = rotatedSurf1.get_rect()
            rotatedRect1.center = (WINDOWWIDTH/2,WINDOWHEIGHT/2)
            DISPLAYSURF.blit(rotatedSurf1,rotatedRect1)
            # 新的矩形往往比原先的大。旋转的角度逆时针为正,顺时针为负。pygame会把你传的大于等于360°的度数不断减去360°直到其小于360°
            rotatedSurf2 = pygame.transform.rotate(titleSurf2,degrees2)
            rotatedRect2 = rotatedSurf2.get_rect()
            rotatedRect2.center = (WINDOWWIDTH/2,WINDOWHEIGHT/2)
            DISPLAYSURF.blit(rotatedSurf2,rotatedRect2)
            # 我们之所以不直接旋转rotatedSurf1和2是因为:1.旋转后的图形会失真,就像一张照片复印后再复印后不会与原来完全一样。不过如果旋转的角度为90°的倍数则不会出现这个问题。2.旋转后的矩形会变大,最终会超出pygame的承受范围
            drawPressKeyMsg()
    
            if checkForKeyPress():
                pygame.event.get()# 清空事件队列
                return
            pygame.display.update()
            FPSCLOCK.tick(FPS)
            degrees1 += 3# 每帧转3°
            degrees2 += 7# 每帧转7°
    
    
    def terminate():
        pygame.quit()
        sys.exit()
    
    
    def getRandomLocation():
        return {'x':random.randint(0,CELLWIDTH-1),'y':random.randint(0,CELLHEIGHT - 1)}
        # 决定苹果出现的位置
    
    def showGameOverScreen():
        gameOverFont = pygame.font.Font('freesansbold.ttf',150)
        gameSurf = gameOverFont.render('Game',True,WHITE)
        overSurf = gameOverFont.render('Over',True,WHITE)
        gameRect = gameSurf.get_rect()
        overRect = overSurf.get_rect()
        gameRect.midtop = (WINDOWWIDTH/2,10)
        overRect.midtop = (WINDOWWIDTH/2,gameRect.height+10+25)
    
        DISPLAYSURF.blit(gameSurf,gameRect)
        DISPLAYSURF.blit(overSurf,overRect)
        drawPressKeyMsg()
        pygame.display.update()
        pygame.time.wait(500)# 500毫秒,也就是半秒
        checkForKeyPress()# 清空事件队列中的任何按键
    
        while True:
            if checkForKeyPress():
                pygame.event.get()# 清空事件队列
                return
    
    def drawScore(score):
        scoreSurf = BASICFONT.render('Score:%s'%(score),True,WHITE)
        scoreRect = scoreSurf.get_rect()
        scoreRect.topleft = (WINDOWWIDTH-120,10)
        DISPLAYSURF.blit(scoreSurf,scoreRect)
    
    
    def drawWorm(wormCoords):
        for coord in wormCoords:
            x = coord['x']*CELLSIZE
            y = coord['y']*CELLSIZE
            wormSegmentRect = pygame.Rect(x,y,CELLSIZE,CELLSIZE)
            pygame.draw.rect(DISPLAYSURF,DARKGREEN,wormSegmentRect)
            wormInnerSegmentRect = pygame.Rect(x+4,y+4,CELLSIZE-8,CELLSIZE-8)
            pygame.draw.rect(DISPLAYSURF,GREEN,wormInnerSegmentRect)
    
    
    def drawApple(coord):
        x = coord['x']*CELLSIZE
        y = coord['y']*CELLSIZE
        appleRect = pygame.Rect(x,y,CELLSIZE,CELLSIZE)
        pygame.draw.rect(DISPLAYSURF,RED,appleRect)
    
    
    def drawGrid():
        for x in range(0,WINDOWWIDTH,CELLSIZE):# draw vertical lines
            pygame.draw.line(DISPLAYSURF,DARKGRAY,(x,0),(x,WINDOWHEIGHT))
        for y in range(0,WINDOWHEIGHT,CELLSIZE):# draw horizontal lines
            pygame.draw.line(DISPLAYSURF,DARKGRAY,(0,y),(WINDOWWIDTH,y))
    
    
    if __name__=='__main__':
        main()
    

    遇到的问题

    在参考的源代码中,有下面这样一段(apple打错了,打成了apply):

                # check if worm has eaten an apply
            if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
                # don't remove worm's tail segment
                apple = getRandomLocation() # set a new apple somewhere
            else:
                 del wormCoords[-1] # remove worm's tail segment
    
            # move the worm by adding a segment in the direction it is moving
            if direction == UP:
                newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
            elif direction == DOWN:
                newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
            elif direction == LEFT:
                newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
            elif direction == RIGHT:
                newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
            wormCoords.insert(0, newHead)
    
    

    这段代码的第一个 if-else 意思是,如果蛇恰到了苹果,就重新生成一个苹果的位置,否则删去蛇尾的一个方块。下面的四句 if 和 elif 则是根据蛇运动的不同方向为蛇添加一个新的头部方块。
    我一想,这不是多余了吗?为什么每次都要添加头部,在吃不到苹果的时候才删除尾部呢,直接在吃到苹果的时候添加头部不就简单了吗?于是下面是我一开始写的代码:

            # 检查它是否恰到苹果
            if wormCoords[HEAD]['x']==apple['x'] and wormCoords[HEAD]['y']==apple['y']:
                apple = getRandomLocation()
                if direction == UP:
                    newHead = {'x':wormCoords[HEAD]['x'],'y':wormCoords[HEAD]['y']-1}# 因为向下为正
                elif direction == DOWN:
                    newHead = {'x':wormCoords[HEAD]['x'],'y':wormCoords[HEAD]['y']+1}
                elif direction == LEFT:
                    newHead = {'x':wormCoords[HEAD]['x']-1,'y':wormCoords[HEAD]['y']}
                elif direction == RIGHT:
                    newHead = {'x':wormCoords[HEAD]['x']+1,'y':wormCoords[HEAD]['y']}
                wormCoords.insert(0,newHead)# 加新头
    

    没想到,运行后开始游戏后蛇完全不动弹!成了一张静止的图片!这是为什么呢?
    wormy1
    于是我开始思考,那么蛇到底是怎么移动起来的呢?原来,答案就在上面这段源代码中。蛇“移动”的方式是不断向蛇头添加小块同时删除尾部小块,在吃到苹果时才不删除尾部,这样就能做出“移动”的效果啦。

    参考

    inventwithpython

  • 相关阅读:
    HashMap:JDK7 与 JDK8 的实现
    es简单介绍及使用注意事项
    mongo学习使用记录2 spring data
    mongo学习使用记录1
    数据库三范式
    mysql数据库中实现内连接、左连接、右连接
    JDK7与JDK8中HashMap的实现
    字符串按照相似度排序
    Linux shell 脚本小记2
    ReentrantLock源码了解
  • 原文地址:https://www.cnblogs.com/hardcoreYutian/p/11289234.html
Copyright © 2011-2022 走看看