如何将我的Nibbles实现类重制?

时间:2016-04-14 00:21:06

标签: python class oop pygame

所以我通过senddex上的newboston youtube频道上的pygame教程制作了Nibbles / Snake重拍。我做了很多微小的审美变化,但总的来说,这是同一个游戏。这是代码:

import pygame
import time
import random

pygame.init()

# A few extra colors just for testing purposes.
WHITE = (pygame.Color("white"))
BLACK = (  0,   0,  0)
RED   = (245,   0,  0)
TURQ  = (pygame.Color("turquoise"))
GREEN = (  0, 155,  0)
GREY  = ( 90,  90, 90)
SCREEN = (800, 600)
gameDisplay = pygame.display.set_mode(SCREEN)
#Set the window title and picture
pygame.display.set_caption('Slither')
ICON = pygame.image.load("apple10pix.png")

pygame.display.set_icon(ICON)
CLOCK = pygame.time.Clock()
FPS = 20
FONT = pygame.font.SysFont("arial", 25)
SNAKE_SIZE = 10 # The width of the snake in pixels, not the length. Start length is defined in the game loop.
APPLE_SIZE = 10
TINY_FONT = pygame.font.SysFont("candara", 15)
SMALL_FONT = pygame.font.SysFont("candara", 25)
MED_FONT = pygame.font.SysFont("candara", 50)
LARGE_FONT = pygame.font.SysFont("krabbypatty", 75)
HUGE_FONT = pygame.font.SysFont("krabbypatty", 150)
IMG = pygame.image.load("snakehead.png")
APPLE_IMG = pygame.image.load("apple10pix.png")
DIRECTION = "up"


def pause():
    paused = True
    message_to_screen("Paused",
                      BLACK,
                      Y_DISPLACE = -100,
                      size = "huge")
    message_to_screen("Press C to continue or Q to quit.",
                      BLACK,
                      Y_DISPLACE = 25)
    pygame.display.update()
    while paused:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_c, pygame.K_p):
                    paused = False
                elif event.key in(pygame.K_q, pygame.K_ESCAPE):
                    pygame.quit()
                    quit()
        CLOCK.tick(5)

def score(score):
    text = SMALL_FONT.render("Score: " + str(score), True, BLACK)
    gameDisplay.blit(text, [0, 0])
    pygame.display.update

def game_intro():
    intro = True
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_c:
                    intro = False
                if event.key in (pygame.K_q, pygame.K_ESCAPE):
                    pygame.quit()
                    quit()
        gameDisplay.fill(WHITE)
        message_to_screen("Welcome to",
                          GREEN,
                          Y_DISPLACE = -170,
                          size = "large")
        message_to_screen("Block Worm",
                          GREEN,
                          Y_DISPLACE = -50,
                          size = "huge")
        message_to_screen("The objective of the game is to eat apples.",
                          BLACK,
                          Y_DISPLACE = 36,
                          size = "tiny")
        message_to_screen("The more apples you eat the longer you get.",
                          BLACK,
                          Y_DISPLACE = 68,
                          size = "tiny")
        message_to_screen("If you run into yourself or the edges, you die.",
                          BLACK,
                          Y_DISPLACE = 100,
                          size = "tiny")
        message_to_screen("Press C to play or Q to quit.",
                          GREY,
                          Y_DISPLACE = 210,)
        pygame.display.update()
        CLOCK.tick(FPS)

def snake(SNAKE_SIZE, SNAKE_LIST):
    if DIRECTION == "right":
        HEAD = pygame.transform.rotate(IMG, 270)
    elif DIRECTION == "left":
        HEAD = pygame.transform.rotate(IMG, 90)
    elif DIRECTION == "down":
        HEAD = pygame.transform.rotate(IMG, 180)
    else:
        DIRECTION == "up"
        HEAD = IMG
    gameDisplay.blit(HEAD, (SNAKE_LIST[-1][0], SNAKE_LIST[-1][1]))
    for XnY in SNAKE_LIST[:-1]:
        pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], SNAKE_SIZE, SNAKE_SIZE])
        pygame.display.update

def text_objects(text, color, size):
    if size == "tiny":
        TEXT_SURFACE = TINY_FONT.render(text, True, color)
    elif size == "small":
        TEXT_SURFACE = SMALL_FONT.render(text, True, color)
    elif size == "medium":
        TEXT_SURFACE = MED_FONT.render(text, True, color)
    elif size == "large":
        TEXT_SURFACE = LARGE_FONT.render(text, True, color)
    elif size == "huge":
        TEXT_SURFACE = HUGE_FONT.render(text, True, color)
    return TEXT_SURFACE, TEXT_SURFACE.get_rect()

def message_to_screen(msg, color, Y_DISPLACE = 0, size = "small"):
    TEXT_SURF, TEXT_RECT = text_objects(msg, color, size)
    TEXT_RECT.center = (SCREEN[0] / 2), (SCREEN[1] / 2) + Y_DISPLACE
    gameDisplay.blit(TEXT_SURF, TEXT_RECT)

def randAppleGen():
    randAppleX = random.randrange(0, (SCREEN[0] - APPLE_SIZE), APPLE_SIZE)
    randAppleY = random.randrange(0, (SCREEN[1]- APPLE_SIZE), APPLE_SIZE)
    return randAppleX, randAppleY

def gameLoop():
    global DIRECTION
    gameExit = False
    gameOver = False

    SNAKE_LIST = [] # Where the snake head has been.
    SNAKE_LENGTH = 1 #Length that the snake starts.

    lead_x = (SCREEN[0] / 2)
    lead_y = (SCREEN[1] - (SCREEN[1] / 5))
    move_speed = 10
    move_speed_neg = move_speed * -1
    lead_x_change = 0
    lead_y_change = -move_speed

    randAppleX, randAppleY = randAppleGen()

    while not gameExit:
        if gameOver == True:
            message_to_screen("Game over",
                              RED,
                              Y_DISPLACE = -50,
                              size = "huge")
            message_to_screen("Press C to play again or Q to quit.",
                              BLACK,
                              Y_DISPLACE = 50,
                              size = "small")
            pygame.display.update()
        while gameOver == True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    gameExit = True
                    gameOver = False
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        gameOver = False
                        gameExit = True
                    elif event.key == pygame.K_c:
                        gameLoop()

        # Handles arrow key and WASD events.
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameExit = True
            elif event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_LEFT, pygame.K_a):
                    lead_x_change = move_speed_neg
                    lead_y_change = 0
                    DIRECTION = "left"
                elif event.key in (pygame.K_RIGHT, pygame.K_d):
                    lead_x_change = move_speed
                    lead_y_change = 0
                    DIRECTION = "right"
                elif event.key in (pygame.K_UP, pygame.K_w):
                    lead_y_change = move_speed_neg
                    lead_x_change = 0
                    DIRECTION = "up"
                elif event.key in (pygame.K_DOWN, pygame.K_s):
                    lead_y_change = move_speed
                    lead_x_change = 0
                    DIRECTION = "down"
                elif event.key in (pygame.K_p, pygame.K_ESCAPE):
                    pause()

        # If the snake goes beyond the screen borders the game will end.
        if lead_x >= SCREEN[0] or lead_x < 0 or lead_y >= SCREEN[1] or lead_y <0:
            gameOver = True

        lead_x += lead_x_change
        lead_y += lead_y_change

        gameDisplay.fill(WHITE)

        # Draw the apple on screen
        APPLE_RECT = pygame.draw.rect(gameDisplay, RED, [randAppleX, randAppleY, APPLE_SIZE, APPLE_SIZE])
        if APPLE_RECT in SNAKE_LIST:
            APPLE_RECT #If the apple appears anywhere "under" the snake, it will immediately respawn elsewhere.

        # Draw the snake on screen
        SNAKE_HEAD = []
        SNAKE_HEAD.append(lead_x)
        SNAKE_HEAD.append(lead_y)
        SNAKE_LIST.append(SNAKE_HEAD)
        # If you hit yourself, game over.
        if SNAKE_HEAD in SNAKE_LIST[:-1]:
           gameOver = True
        if len(SNAKE_LIST) > SNAKE_LENGTH:
            del SNAKE_LIST[0]
        snake(SNAKE_SIZE, SNAKE_LIST)

        score(SNAKE_LENGTH - 1)

        # If the snake eats the apple
        if APPLE_RECT.collidepoint(lead_x, lead_y) == True:
            randAppleX, randAppleY = randAppleGen()
            SNAKE_LENGTH += 1

        pygame.display.update()
        CLOCK.tick(FPS)
    pygame.quit()
    quit()

game_intro()
gameLoop()

这是一个相当稳固的小游戏。但是我想把蛇和苹果分成几类,这样我以后可以产生其他类型的蛇(也许是基本的AI?)和其他类型的苹果(也许是绿色的,可以让你的蛇变成3+)。我试图用蛇类来做这件事:

import pygame
import time
import random

pygame.init()

WHITE = (pygame.Color("white"))
BLACK = (  0,   0,  0)
RED   = (245,   0,  0)
TURQ  = (pygame.Color("turquoise"))
GREEN = (  0, 155,  0)
GREY  = ( 90,  90, 90)
SCREEN = (800, 600)
gameDisplay = pygame.display.set_mode(SCREEN)
#Set the window title and picture
pygame.display.set_caption('Block Worm')
ICON = pygame.image.load("apple10pix.png")

pygame.display.set_icon(ICON)
CLOCK = pygame.time.Clock()
FPS = 20
FONT = pygame.font.SysFont("arial", 25)
APPLE_SIZE = 10
TINY_FONT = pygame.font.SysFont("candara", 15)
SMALL_FONT = pygame.font.SysFont("candara", 25)
MED_FONT = pygame.font.SysFont("candara", 50)
LARGE_FONT = pygame.font.SysFont("krabbypatty", 75)
HUGE_FONT = pygame.font.SysFont("krabbypatty", 150)
IMG = pygame.image.load("snakehead.png")
APPLE_IMG = pygame.image.load("apple10pix.png")


def pause():
    paused = True
    message_to_screen("Paused",
                      BLACK,
                      Y_DISPLACE = -100,
                      size = "huge")
    message_to_screen("Press C to continue or Q to quit.",
                      BLACK,
                      Y_DISPLACE = 25)
    pygame.display.update()
    while paused:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_c, pygame.K_p):
                    paused = False
                elif event.key in(pygame.K_q, pygame.K_ESCAPE):
                    pygame.quit()
                    quit()
        CLOCK.tick(5)

def score(score):
    text = SMALL_FONT.render("Score: " + str(score), True, BLACK)
    gameDisplay.blit(text, [5, 5])
    pygame.display.update

def game_intro():
    intro = True
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_c:
                    intro = False
                if event.key in (pygame.K_q, pygame.K_ESCAPE):
                    pygame.quit()
                    quit()
        gameDisplay.fill(WHITE)
        message_to_screen("Welcome to",
                          GREEN,
                          Y_DISPLACE = -170,
                          size = "large")
        message_to_screen("Block Worm",
                          GREEN,
                          Y_DISPLACE = -50,
                          size = "huge")
        message_to_screen("The objective of the game is to eat apples.",
                          BLACK,
                          Y_DISPLACE = 36,
                          size = "tiny")
        message_to_screen("The more apples you eat the longer you get.",
                          BLACK,
                          Y_DISPLACE = 68,
                          size = "tiny")
        message_to_screen("If you run into yourself or the edges, you die.",
                          BLACK,
                          Y_DISPLACE = 100,
                          size = "tiny")
        message_to_screen("Press C to play or Q to quit.",
                          GREY,
                          Y_DISPLACE = 210,)
        pygame.display.update()
        CLOCK.tick(FPS)

def text_objects(text, color, size):
    if size == "tiny":
        TEXT_SURFACE = TINY_FONT.render(text, True, color)
    elif size == "small":
        TEXT_SURFACE = SMALL_FONT.render(text, True, color)
    elif size == "medium":
        TEXT_SURFACE = MED_FONT.render(text, True, color)
    elif size == "large":
        TEXT_SURFACE = LARGE_FONT.render(text, True, color)
    elif size == "huge":
        TEXT_SURFACE = HUGE_FONT.render(text, True, color)
    return TEXT_SURFACE, TEXT_SURFACE.get_rect()

def message_to_screen(msg, color, Y_DISPLACE = 0, size = "small"):
    TEXT_SURF, TEXT_RECT = text_objects(msg, color, size)
    TEXT_RECT.center = (SCREEN[0] / 2), (SCREEN[1] / 2) + Y_DISPLACE
    gameDisplay.blit(TEXT_SURF, TEXT_RECT)

def randAppleGen():
    randAppleX = random.randrange(0, (SCREEN[0] - APPLE_SIZE), APPLE_SIZE)
    randAppleY = random.randrange(0, (SCREEN[1]- APPLE_SIZE), APPLE_SIZE)
    return randAppleX, randAppleY

class Snake:
    def __init__(self, image, x, y, direction, speed):
        self.image = image
        self.rect = self.image.get_rect()
        self.width = self.rect.width
        self.rect.x = x
        self.rect.y = y
        self.direction = direction
        self.speed = speed
        self.trail = [] # Where the snake head has been.
        self.length = 1 # Length that the snake starts.
    def snake_direction_change(direction):
        if direction == "right":
            self.image = pygame.transform.rotate(self.image, 270)
        elif direction == "left":
            self.image = pygame.transform.rotate(self.image, 90)
        elif direction == "down":
            self.image = pygame.transform.rotate(self.image, 180)
        else:
            direction == "up"
        pygame.display.update
    def snake_grow(x, y, z):
        gameDisplay.blit(self.image, (self.trail[-1][0], self.trail[-1][1]))
        for XnY in snake.trail[:-1]:
            pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], self.width, self.width])
            pygame.display.update


def gameLoop():
    gameExit = False
    gameOver = False

    lead_x_change = 0
    lead_y_change = -snake.speed

    randAppleX, randAppleY = randAppleGen()

    gameDisplay.fill(WHITE)

    snake = Snake(IMG,
                  x = (SCREEN[0] / 2),
                  y =(SCREEN[1] - (SCREEN[1] / 5)),
                  direction = "up",
                  speed = 10,)

    while not gameExit:
        if gameOver == True:
            message_to_screen("Game over",
                              RED,
                              Y_DISPLACE = -50,
                              size = "huge")
            message_to_screen("Press C to play again or Q to quit.",
                              BLACK,
                              Y_DISPLACE = 50,
                              size = "small")
            pygame.display.update()
        while gameOver == True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    gameExit = True
                    gameOver = False
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        gameOver = False
                        gameExit = True
                    elif event.key == pygame.K_c:
                        gameLoop()

        # Handles arrow key and WASD events.
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameExit = True
            elif event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_LEFT, pygame.K_a):
                    lead_x_change = snake.speed * -1
                    lead_y_change = 0
                    snake.snake_direction_change("left")
                elif event.key in (pygame.K_RIGHT, pygame.K_d):
                    lead_x_change = snake.speed
                    lead_y_change = 0
                    snake.snake_direction_change("right")
                elif event.key in (pygame.K_UP, pygame.K_w):
                    lead_y_change = snake.speed * -1
                    lead_x_change = 0
                    snake.snake_direction_change("up")
                elif event.key in (pygame.K_DOWN, pygame.K_s):
                    lead_y_change = snake.speed
                    lead_x_change = 0
                    snake.snake_direction_change("down")
                elif event.key in (pygame.K_p, pygame.K_ESCAPE):
                    pause()

        # If the snake goes beyond the screen borders the game will end.
        if snake.rect.x >= SCREEN[0] or snake.rect.x < 0 or snake.rect.y >= SCREEN[1] or snake.rect.y <0:
            gameOver = True

        snake.rect.x += lead_x_change
        snake.rect.y += lead_y_change

        gameDisplay.fill(WHITE)

        # Draw the apple on screen
        APPLE_RECT = pygame.draw.rect(gameDisplay, RED, [randAppleX, randAppleY, APPLE_SIZE, APPLE_SIZE])
        if APPLE_RECT in snake.trail:
            APPLE_RECT #If the apple appears anywhere "under" the snake, it will immediately respawn elsewhere.

        # Draw the snake on screen
        SNAKE_HEAD = []
        SNAKE_HEAD.append(snake.rect.x)
        SNAKE_HEAD.append(snake.rect.y)
        snake.trail.append(SNAKE_HEAD)
        # If you hit yourself, game over.
        if SNAKE_HEAD in snake.trail[:-1]:
            gameOver = True
        if len(snake.trail) > snake.length:
            del snake.trail[0]
        snake.snake_grow(snake.width, snake.trail)

        score(snake.length - 1)

        # If the snake eats the apple
        if APPLE_RECT.collidepoint(snake.rect.x, snake.rect.y) == True:
            randAppleX, randAppleY = randAppleGen()
            snake.length += 1

        pygame.display.update()
        CLOCK.tick(FPS)
    pygame.quit()
    quit()

game_intro()
gameLoop()

这个版本不是那么可爱。事实上,它根本不起作用。我对课程和职能的理解充其量只是基础。在我的试错过程中,更改或完全删除了原始代码中的大量代码。我花了几个小时试图让这项工作无济于事。我的主要目标是制作一个Snake和Apple类,可以重复用于以后的两种变体。

所以,我来找你们好帮助我!我有两个主要问题:

1)我需要做些什么才能使其正常工作?

2)如何清理我的代码以使其更易于阅读并且整体效率更高?

1 个答案:

答案 0 :(得分:0)

&#34;我的试错过程中更改或完全删除了原始代码中的许多代码&#34;

Bingo。您刚刚找到了问题的症结所在。软件开发应该是一个受控制的,深思熟虑的过程 - 而不是试验和错误。你需要有意识地,有目的地进行。

在介绍课程时,您尝试做(或应该尝试做)的是refactoring您的代码。

您应该重新使用原始的工作副本,并在引入Snake类时尽可能少地进行更改。第一步是简单地将snake函数转换为类,并将其替换为。下面是您可以开始的地方:将此snake方法替换为此Snake类,然后更改您使用它的行

class Snake:
    def __init__(self, SNAKE_SIZE, SNAKE_LIST):
        if DIRECTION == "right":
            HEAD = pygame.transform.rotate(IMG, 270)
        elif DIRECTION == "left":
            HEAD = pygame.transform.rotate(IMG, 90)
        elif DIRECTION == "down":
            HEAD = pygame.transform.rotate(IMG, 180)
        else:
            DIRECTION == "up"  # note: this line does nothing
            HEAD = IMG
        gameDisplay.blit(HEAD, (SNAKE_LIST[-1][0], SNAKE_LIST[-1][1]))
        for XnY in SNAKE_LIST[:-1]:
            pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], SNAKE_SIZE, SNAKE_SIZE])
            pygame.display.update  # note: this likely does nothing - I think you want to call it (pygame.display.update())

并改变这一点:

snake(SNAKE_SIZE, SNAKE_LIST)

成:

snake = Snake(SNAKE_SIZE, SNAKE_LIST)

现在,在这一点上,如果您的代码之前有效,它应该仍然有效(假设我没有做任何愚蠢的事情)。这是一个很好的班级例子吗?没有。 My Snake课很糟糕。你对蛇类的尝试远远好得多。以这种方式做事给你一个起点。然后,您可以继续执行以下操作:

  • 将参数分配给实例变量
  • 将所有代码移动到另一种方法
  • 开始删除它有权访问的模块级变量,并传入其他参数

重构此模块的另一种方法可能是更改每个函数,以便它们都不依赖于模块级变量。将每个函数所需的每个变量传递给该函数。

我想告诉您的重点是,通过一次编写/更改一下,制作工作软件要容易得多。在更改其他内容之前确保它仍然有效。研究一小部分代码&amp;测试每个更改,以便您确切知道您的程序在何处以及如何破坏。