Python編寫貪吃蛇小遊戲

2018.3.15 晴 天氣越來越熱 要穿T恤了

今天一天就編了一個小遊戲:貪吃蛇。 

面向對象這個邏輯是必須要學會的,has a , is a, 這些關係要弄明白,封裝,繼承,多態,是面向對象的三個屬性。今天的貪吃蛇代碼基本上是完成了,驗證是否碰壁,是否追尾,添加字體,添加彈窗,開始新的遊戲,這幾個功能基本都是按照自己的邏輯寫的,用了個easygui類來彈窗,我覺得挺有意思的。 還有一個排行榜沒做,我得考慮一下是用存檔的方式還是在遊戲進行的時候用一個列表存數據(重開遊戲就清空了)

 

 

代碼如下:

 

import pygame
from abc import ABCMeta, abstractclassmethod
from random import randint
from pygame.locals import *


import easygui


Black_color = (0, 0, 0)
Food_color = (236, 189, 187)
Green_color = (0, 255, 0)

# 順時針或者逆時針
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3


class GameObject(object, metaclass=ABCMeta):
    def __init__(self, x, y, color):
        self._x = x
        self._y = y
        self._color = color

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    @abstractclassmethod
    def draw(self, screen):
        pass


class Snake(GameObject):
    def __init__(self):
        self._dir = LEFT
        self._nodes = []
        self.has_eat_food = False
        for index in range(5):
            node = SnakeNode(290 + index * 20, 250, 20)
            self._nodes.append(node)

    @property
    def dir(self):
        return self._dir

    def change_dir(self, new_dir):
        if (self._dir + new_dir) % 2 != 0:
            self._dir = new_dir

    def draw(self, screen):
        for node in self._nodes:
            node.draw(screen)

    def move(self):
        head = self._nodes[0]
        sdir = self._dir
        x, y, size = head.x, head.y, head.size
        if sdir == UP:
            y -= size
        elif sdir == RIGHT:
            x += size
        elif sdir == DOWN:
            y += size
        else:
            x -= size
        new_head = SnakeNode(x, y, size)
        self._nodes.insert(0, new_head)
        if self.has_eat_food:
            self.has_eat_food = False
        else:
            self._nodes.pop()

    def is_over(self):
        '''撞牆返回真,否則返回假'''
        head = self._nodes[0]
        x, y, size = head.x, head.y, head.size
        if x > 600 or x < 10 or y > 600 or y < 10:
            return True
        return False

    def eat_food(self, food):
        head = self._nodes[0]
        if food.x == head.x and food.y == head.y:
            self.has_eat_food = True
            return True
        return False

    def eat_me(self):
        for a in range(4, len(self._nodes)):
            if self._nodes[0].x == self._nodes[a].x and self._nodes[0].y == self._nodes[a].y:
                return True
        return False


class SnakeNode(GameObject):
    def __init__(self, x, y, size, color=Green_color):
        super().__init__(x, y, color)
        self._size = size
        self._color = color

    @property
    def size(self):
        return self._size

    def draw(self, screen):
        pygame.draw.rect(screen, self._color,
                         (self._x, self._y, self._size, self._size), 0)
        pygame.draw.rect(screen, Black_color,
                         (self._x, self._y, self._size, self._size), 1)


class Wall(GameObject):
    def __init__(self, x, y, width, height, color=Black_color):
        super().__init__(x, y, color)
        self._width = width
        self._height = height

    @property
    def width(self):
        return self._width

    @property
    def height(self):
        return self._height

    def draw(self, screen):
        pygame.draw.rect(screen, self._color,
                         (self._x, self._y, self._width, self._height), 4)


class Food(GameObject):
    def __init__(self, x, y, size, color=Food_color):
        super().__init__(x, y, color)
        self._size = size
        self._hide = False

    def draw(self, screen):
        if not self._hide:
            pygame.draw.circle(screen, self._color,
                             (self._x + self._size // 2, self._y + self._size // 2),
                              self._size // 2, 0)
        # 處理圓和半徑的中心點 否則無法相遇
        self._hide = not self._hide


def main():
    def refresh():
        '''刷新遊戲窗口'''
        screen.fill((242, 242, 242))
        snake.draw(screen)
        wall.draw(screen)
        food.draw(screen)
        pygame.display.flip()

    def handle_key_event(key_event):
        key = key_event.key
        if key == ord('w'):
            new_dir = UP
        elif key == ord('d'):
            new_dir = RIGHT
        elif key == ord('s'):
            new_dir = DOWN
        elif key == ord('a'):
            new_dir = LEFT
        else:
            new_dir = key
        if new_dir != snake.dir:
            snake.change_dir(new_dir)

    def create_food():
        row = randint(1, 28)
        col = randint(1, 28)
        return Food(10 + 20 * row, 10 + 20 * col, 20)

    def count_txt(snake):
        score = len(snake._nodes) - 5
        my_font = pygame.font.SysFont('楷體', 60)
        game_over = my_font.render('GAME OVER', False, [0, 0, 0])
        score = my_font.render('score:' + str(score), False, [255, 0, 0])
        screen.blit(score, (400, 30))
        screen.blit(game_over, (180, 260))
        pygame.display.flip()

    wall = Wall(10, 10, 600, 600)
    food = create_food()
    snake = Snake()
    pygame.init()
    screen = pygame.display.set_mode((620, 620))
    pygame.display.set_caption('貪吃蛇')
    background = screen.fill((242, 242, 242))
    pygame.display.flip()
    clock = pygame.time.Clock()
    running = True
    over = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                handle_key_event(event)
        if over:
            refresh()
        clock.tick(20)
        if over:
            snake.move()
            if snake.eat_food(food):
                food = create_food()
            if snake.is_over() or snake.eat_me():
                count_txt(snake)
                Yes_or_No = easygui.buttonbox("不好意思,遊戲結束", choices=['我不服我還要玩', '我不玩了886'])
                if Yes_or_No == '我不服我還要玩':
                    snake = Snake()
                    pygame.event.clear()
                else:
                    over = False
    pygame.quit()


if __name__ == '__main__':
    main()

 

 

 

代碼量還是挺大的,邏輯比五子棋好理解一點,五子棋那個判斷勝負確實有點繞,但是貪吃蛇基本把面向對象的東西都用到了,需要細嚼慢嚥地去理解使用。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章