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