首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >地牢球,小游戏

地牢球,小游戏
EN

Code Review用户
提问于 2020-08-04 18:10:10
回答 1查看 183关注 0票数 11

我刚刚完成了我在Python上第一个游戏的第一个版本,叫做地下城球。我正在寻找人们测试这个应用程序,并给我一些反馈和建设性的批评。我想用这个项目来提高我的编程技能,并希望学习一些有效的编程实践。

这个游戏叫地下城球。目前这是相当基本的。它非常类似于用球和球拍/桨打破砖块的游戏,但我还没有包括砖块。目前,我们的目标是用桨防止球掉下来。通过击打划桨,你就能得到分数,这会使你的水平上升。水平越高,桨和球的移动速度就越快。

Main.py

代码语言:javascript
复制
import pygame
from pygame.locals import *
import numpy as np 
import math
from sys import exit
pygame.init()

from variables import *

def gameOver():
    pygame.mixer.music.stop()
    sounds['gameOver'].play()
    keyStatus = True
    blinkerCount = 0
    blinkerState = True
    blinkTime = 15
    while keyStatus:
        pygame.draw.rect(DISPLAYSURF, colours['grey'], dimensions['arena'])
        # pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
        if blinkerState:
            textSurfaceObj = fonts['largeFont'].render('GAME OVER!', True, colours['red'])
            textRectObj = textSurfaceObj.get_rect()
            textRectObj.center = (boxSize[0]/2, boxSize[1]/2)
            DISPLAYSURF.blit(textSurfaceObj, textRectObj)

        scoreSurface = fonts['midFont'].render('Score : {}'.format(gameStatus['points']), True, colours['white'])
        scoreSurfaceRect = scoreSurface.get_rect()
        scoreSurfaceRect.center = (boxSize[0]/2, boxSize[1]/2 + 50)
        DISPLAYSURF.blit(scoreSurface, scoreSurfaceRect)

        blinkerCount += 1

        if blinkerCount % blinkTime == 0:
            blinkerCount = 0
            blinkerState = not blinkerState

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    sounds['gameOver'].stop()
                    keyStatus = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    exit()

        pygame.display.update()
        fpsClock.tick(FPS)

        if keyStatus == False:
            break

    main()

def renderFunction():
    global gameStatus
    pygame.draw.rect(DISPLAYSURF, colours['black'], dimensions['arena'])
    pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
    pygame.draw.rect(DISPLAYSURF, colours['red'], dimensions['paddle'])
    pygame.draw.circle(DISPLAYSURF, colours['blue'], (ball['position']['x'], ball['position']['y']), ball['rad'] , 0)
    pointSurface = fonts['tinyFont'].render('Points : ' + str(gameStatus['points']), True, colours['white'])
    pointSurfaceRect = pointSurface.get_rect()
    pointSurfaceRect.center = (40, boxSize[1]-10)
    DISPLAYSURF.blit(pointSurface, pointSurfaceRect)

    levelSurface = fonts['tinyFont'].render('Level : ' + str(gameStatus['level']), True, colours['white'])
    levelSurfaceRect = levelSurface.get_rect()
    levelSurfaceRect.center = (boxSize[0]-40, boxSize[1]-10)
    DISPLAYSURF.blit(levelSurface, levelSurfaceRect)

def introScreen():
    keyStatus = True
    blinkerCount = 0
    blinkerState = True
    blinkTime = 15
    pygame.mixer.music.load('audio/startScreenMusic.wav')
    pygame.mixer.music.play(-1, 0.0)
    while keyStatus:
        pygame.draw.rect(DISPLAYSURF, colours['grey'], dimensions['arena'])
        # pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
        textSurfaceObj = fonts['largeFont'].render(gameStatus['name'], True, colours['gold'])
        textRectObj = textSurfaceObj.get_rect()
        textRectObj.center = (boxSize[0]/2, boxSize[1]/2)
        DISPLAYSURF.blit(textSurfaceObj, textRectObj)

        if blinkerState:
            spaceSurfaceObj = fonts['midFont'].render('Press Enter to Continue', True, colours['white'])
            spaceRectObj = spaceSurfaceObj.get_rect()
            spaceRectObj.center = (boxSize[0]/2, boxSize[1]/2+50)
            DISPLAYSURF.blit(spaceSurfaceObj, spaceRectObj)

        versionSurface = fonts['tinyFont'].render(gameStatus['version'], True, colours['white'])
        versionSurfaceRect = versionSurface.get_rect()
        versionSurfaceRect.center = (boxSize[0]-20, boxSize[1]-10)
        DISPLAYSURF.blit(versionSurface, versionSurfaceRect)
        blinkerCount += 1

        if blinkerCount % blinkTime == 0:
            blinkerCount = 0
            blinkerState = not blinkerState

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    keyStatus = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    exit()
        pygame.display.update()
        fpsClock.tick(FPS)

    keyStatus=True
    pygame.mixer.music.stop()       

def eventHandler():
    global dimensions
    keys=pygame.key.get_pressed()
    if keys[K_LEFT] and not (dimensions['paddle'].left <= (dimensions['arena'].left+borderWidth)):
        direction = -1*paddle['speed']
        # print('hi left')
        paddle['position']['x'] += direction
    elif keys[K_RIGHT] and not (dimensions['paddle'].right >= (dimensions['arena'].right-borderWidth)):
        direction = paddle['speed']
        # print('hi right')
        paddle['position']['x'] += direction
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            exit()

    dimensions['paddle'] = pygame.Rect(paddle['position']['x'], paddle['position']['y'], paddle['length'], 10)

def ballEngine():
    global gameStatus
    if (ball['position']['x'] <= (dimensions['arena'].left+borderWidth+ball['rad'])):
        # print('LeftSideBounce')
        ball['direction'] = 180 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        sounds['wallHit'].play()

    elif (ball['position']['x'] >= (dimensions['arena'].right-borderWidth-ball['rad'])):
        # print('RightSideBounce')
        ball['direction'] = 180 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        sounds['wallHit'].play()

    elif ball['position']['y'] <= (dimensions['arena'].top+borderWidth+ball['rad']):
        # print('TopBounce')
        ball['direction'] = 360 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])

        if ball['direction'] >= 250 and ball['direction'] <= 290:
            ball['direction'] += np.random.randint(-2*gameStatus['random'],2*gameStatus['random'])

        sounds['wallHit'].play()
    elif ball['position']['y'] >= (dimensions['arena'].bottom - borderWidth - ball['rad']):
        # print('BottomBounce')
        # ball['speed'] = 0
        # gameStatus = True
        gameOver()
    # print(ball['direction'])
    if (ball['position']['y'] >= (paddle['position']['y']-ball['rad']) and ball['position']['y'] <= paddle['position']['y']+dimensions['paddle'].height+ball['rad']) and ball['position']['x'] >= dimensions['paddle'].left and ball['position']['x'] <= dimensions['paddle'].right:
        # print('Paddle hit')
        ball['direction'] = 360 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        gameStatus['points'] = gameStatus['points'] + 1

        sounds['paddleHit'].play()
        print(ball['position'], paddle['position'], ball['direction'])

        gameStatus['paddleHitsPerLevel'] += 1

        if ball['position']['y'] >= dimensions['paddle'].top and ball['position']['y'] <= dimensions['paddle'].bottom:
            ball['position']['y'] = dimensions['paddle'].top - ball['rad']

        if gameStatus['paddleHitsPerLevel'] == (gameStatus['level']*5) and not gameStatus['points']  == 0:
            ball['speed'] += 2
            gameStatus['level'] += 1
            gameStatus['random'] += 2
            gameStatus['paddleHitsPerLevel'] = 0
            sounds['levelUp'].play()

        if gameStatus['points'] % 10 == 0 and not gameStatus['points']  == 0:
            paddle['speed'] += 1

    if (ball['direction']>360 or ball['direction'] < 0):
        ball['direction'] %= 360

    if ball['direction'] % 90 >= 85 and ball['direction'] % 90 <=89 or ball['direction'] % 90 >= 0 and ball['direction'] % 90 <= 5:
        ball['direction'] += np.random.randint(-2*gameStatus['random'],2*gameStatus['random'])


    if ball['position']['y'] < borderWidth+ball['rad']:
        ball['position']['y'] = borderWidth+ball['rad']
    elif ball['position']['x'] < borderWidth+ball['rad']:
        ball['position']['x'] = borderWidth+ball['rad']
    elif ball['position']['x'] > dimensions['arena'].right-borderWidth-ball['rad']:
        ball['position']['x'] = dimensions['arena'].right-borderWidth-ball['rad']

    ball['position']['x'] += int(ball['speed']*math.cos(ball['direction']*math.pi/180))
    ball['position']['y'] += int(ball['speed']*math.sin(ball['direction']*math.pi/180))

def init():
    global ball, paddle, gameStatus
    ball['position']['x']=boxSize[0]/2
    ball['position']['y']=int(boxSize[1]/3)
    ball['direction']=np.random.randint(295, 325)
    ball['speed']=5
    ball['rad']=5

    paddle['position']['x']=boxSize[0]/2
    paddle['position']['y']=boxSize[1]-50
    paddle['length']=100
    paddle['speed']=5

    gameStatus['points']=0
    gameStatus['level']=1
    gameStatus['random']=5

def main():
    introScreen()
    init()
    pygame.mixer.music.load('audio/gamePlayMusic.wav')
    pygame.mixer.music.play(-1, 0.0)

    while True:
        eventHandler()
        ballEngine()
        renderFunction()
        pygame.display.update()
        fpsClock.tick(FPS)

if __name__ == '__main__':
    fpsClock = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode(boxSize, 0, 32)
    pygame.display.set_caption(gameStatus['name'])
    main()

Variables.py

代码语言:javascript
复制
import numpy as np
import pygame
pygame.init()
from pygame.locals import *
import os

FPS = 30
borderWidth = 5

boxSize = (700, 400)

colours = {'black':(0, 0, 0),
           'red': (255, 0, 0),
           'blue':(0, 0, 255),
           'brown':(210, 105, 30),
           'green':(0, 255, 0),
           'white':(255, 255, 255),
           'gold':(255, 215, 0),
           'silver':(192, 192, 192),
           'grey':(128, 128, 128)}

ball = {'position':{'x':boxSize[0]/2, 'y':boxSize[1]/3}, 'direction':np.random.randint(295, 325), 'speed':5, 'rad':5}

paddle = {'position':{'x':boxSize[0]/2, 'y':boxSize[1]-50}, 'length':100, 'speed':5}

dimensions = {
              'arena': pygame.Rect(0, 0, boxSize[0], boxSize[1]+10), 
              'paddle': pygame.Rect(paddle['position']['x'], paddle['position']['y'], paddle['length'], 10)
             }

gameStatus = {'points': 0, 'level': 1, 'random': 5, 'paddleHitsPerLevel':0, 'name': 'Dungeon Ball', 'version': 'v1.0'}


fonts = {
         'largeFont':pygame.font.Font(os.path.join(os.getcwd(),'fonts','Ancient_Modern_Tales_Regular.ttf'), 64),
         'midFont':pygame.font.Font(os.path.join(os.getcwd(),'fonts', 'Old_School_Adventures_Regular.ttf'), 12),
         'tinyFont': pygame.font.Font(os.path.join(os.getcwd(),'fonts', 'Old_School_Adventures_Regular.ttf'), 8)
        }

sounds = {
            'paddleHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'paddle_hit.wav')), 
            'wallHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'wall_hit.wav')), 
            'gameOver':pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'game_over.wav')),
            'levelUp': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'level_up.wav'))
        }

目前,发布只适用于Linux和Windows。Mac用户可以尝试构建环境并直接运行程序。第一步,您需要下载特定于操作系统的版本并解压缩它。输入提取的目录。Windows用户只需双击即可运行。Linux用户需要在终端中打开目录并运行./main。

EN

回答 1

Code Review用户

发布于 2020-08-10 19:28:56

我没有尝试玩这个游戏,但是看了一下代码,我有一些建议。

代码可读性建议

boxSize[0]boxSize[1]在您的代码中都被使用,而且可读性不强。只有一个地方实际使用没有索引的变量boxSize,所以我会相反,定义width = 700height=400,以便您可以在需要的地方引用它们,然后在使用boxSize的一行中将其更改为

ISPLAYSURF = pygame.display.set_mode((width, height), 0, 32)

可读性2

ball['direction']=np.random.randint(295, 325),我认为数字295和325指的是角度,但它们可以被命名,以使这更清楚。

可读性3

ball['rad']

我认为radradius的缩写,但它不是一个好名字。一般避免使用短文。尤其是在数学中常用的测量角度的弧度,这使我在思考球的方向时感到困惑。

可读性4

代码语言:javascript
复制
if keys[K_LEFT] and not (dimensions['paddle'].left <= (dimensions['arena'].left+borderWidth)):

not <=对于>来说是必需的,所以更容易阅读。

代码语言:javascript
复制
if keys[K_LEFT] and (dimensions['paddle'].left > (dimensions['arena'].left+borderWidth)):

逻辑1

代码语言:javascript
复制
    if blinkerCount % blinkTime == 0:
        blinkerCount = 0
        blinkerState = not blinkerState

由于每次都要将blinkerCount重置为0,所以不需要模块操作,所以只需将if-子句更改为if blinkerCount == blinkTime即可。如果您不重置为0,那么模块化操作将是有意义的。

逻辑2

代码语言:javascript
复制
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN:
                sounds['gameOver'].stop()
                keyStatus = False
            elif event.key == pygame.K_ESCAPE:
                pygame.quit()
                exit()

这里的两个elif都是冗余的,可以用if代替。由于pygame.QUITpygame.KEYDOWN是不同的东西,因此根据定义,事件不能等于两者,因此不需要elif中的“event”。

避免重复1

您正在对pygame.draw.rect(DISPLAYSURF进行多次调用,我将为此创建一个新函数,这样您就不必一遍又一遍地重复这一点。

就像

代码语言:javascript
复制
def rectangle(color, _dimensions):
    pygame.draw.rect(DISPLAYSURF, colors[color], _dimensions)

然后,在代码的其他地方,您可以替换如下

pygame.draw.rect(DISPLAYSURF, colours['grey'], dimensions['arena'])

带着

rectangle('grey', dimensions['arena'])

避免重复2

代码语言:javascript
复制
sounds = {
        'paddleHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'paddle_hit.wav')), 
        'wallHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'wall_hit.wav')), 
        'gameOver':pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'game_over.wav')),
        'levelUp': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'level_up.wav'))
    }

看到这里每一行的70%是如何与另一行相同的吗?这就是您想要为此创建一个函数的地方,如

代码语言:javascript
复制
def get_sound(filename):
    return pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', filename))

以便您可以将上面的内容替换为

代码语言:javascript
复制
sounds = {
        'paddleHit': get_sound('paddle_hit.wav'), 
        'wallHit': get_sound('wall_hit.wav'), 
        'gameOver':get_sound('game_over.wav'),
        'levelUp': get_sound('level_up.wav')
    }

(如果将密钥命名为与文件相同,则可以使其更短)

代码质量与可读性

代码语言:javascript
复制
if ball['position']['y'] < borderWidth+ball['rad']:

这类代码很难阅读,当然也浪费了空间和编写时间。我建议您查找基本对象/类,以便可以定义类ball并设置其属性,从而可以编写

if ball.y < borderWidth+ball.radius:

看看这有多简单?

票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/247482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档