刚结束期末考试,闲来无事,便尝试着做个贪吃蛇玩玩。
起初尚是不明所以,但在看了另一个老哥的文章用python写一个简单的贪吃蛇游戏(附代码)之后,豁然开朗。
我的代码大体采用了这位老哥的框架,但采取了与之不同的面向对象的实现方式。并且我的代码实现了贪吃蛇穿墙移动(从一头进,在另一头出)的操作。
但是写完之后实际看看还是有比较大的上升空间的,例如可以把蛇和苹果的绘制放到”蛇“类和”苹果“类当中去。只是练习作,如果有更好的意见欢迎畅所欲言。
代码实现“蛇”类:用于实现蛇对象(本质为队列)
class Snake:
def __init__(self) -> None:
self._sn = deque()
self._sn.append([2, 2])
self._sn.append([1, 2])
self._sn.append([0, 2])
self.directionX = 1
self.directionY = 0
def pushBack(self, nextStep : list) -> None:
self._sn.appendleft(nextStep)
def pop(self) -> None:
self._sn.pop()
def __len__(self) -> int:
return len(self._sn)
def getSn(self) -> deque:
return self._sn
”苹果“类: 用于实现苹果对象
class Apple:
def __init__(self, snake : Snake):
self._x = random.randint(0, screenWidth // 20 - 1)
self._y = random.randint(2, screenHeight // 20 - 1)
while [self._x, self._y] in snake.getSn():
self._x = random.randint(0, screenWidth // 20 - 1)
self._y = random.randint(2, screenHeight // 20 - 1)
def getX(self) -> int:
return self._x
def getY(self) -> int:
return self._y
”计数“类:用于计量游戏数值(得分,速度)
class ScoreAndSpeed:
def __init__(self):
self._score = 0
self._oriSpeed = 0.5
self._speed = self._oriSpeed
def getScore(self) -> int:
return self._score
def setScore(self, score : int):
self._score = score
def getOriSpeed(self) -> float:
return self._oriSpeed
def getSpeed(self) -> float:
return self._speed
def setSpeed(self, speed : float):
self._speed = speed
”游戏“类:用于实现游戏画面和相关功能
class Game:
def __init__(self):
pygame.init()
self.myWindow = pygame.display.set_mode((screenWidth, screenHeight), 0, 32)
pygame.display.set_caption("Snake")
self.myWindow.fill((0, 0, 0))
pygame.display.update()
self.font_score = pygame.font.SysFont('SimHei', 24)
self.font_Length = pygame.font.SysFont('SimHei', 24)
self.font_GameOver = pygame.font.SysFont(None, 72)
self.font_Beginning = pygame.font.SysFont(None, 48)
self.color_GameOver = (255, 255, 255)
# self.directionX = 1
# self.directionY = 0
self.directionLimit = True
self.isGameOver = True
self.isStart = False
# self.score = 0
# self.oriSpeed = 0.5
self.lastMove = time.time()
self.isPause = False
self.snake = Snake()
self.apple = Apple(self.snake)
self.scoreAndSpeed = ScoreAndSpeed()
self.speed = self.scoreAndSpeed.getOriSpeed()
def fontPrinter(self, font, x, y, text, fcolor = (255, 255, 255)):
Textimg = font.render(text, True, fcolor)
self.myWindow.blit(Textimg, (x, y))
def runing(self):
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_RETURN:
# restart game
if self.isGameOver:
self.isGameOver = False
self.isStart = True
self.directionLimit = True
self.snake = Snake()
self.apple = Apple(self.snake)
self.scoreAndSpeed = ScoreAndSpeed()
self.lastMove = time.time()
elif event.key == K_SPACE:
if not self.isGameOver:
self.isPause = not self.isPause
elif event.key in (K_UP, K_w):
if self.directionLimit and self.snake.directionY == 0:
self.snake.directionY = -1
self.snake.directionX = 0
self.directionLimit = False
elif event.key in (K_DOWN, K_s):
if self.directionLimit and self.snake.directionY == 0:
self.snake.directionY = 1
self.snake.directionX = 0
self.directionLimit = False
elif event.key in (K_RIGHT, K_d):
if self.directionLimit and self.snake.directionX == 0:
self.snake.directionY = 0
self.snake.directionX = 1
self.directionLimit = False
elif event.key in (K_LEFT, K_a):
if self.directionLimit and self.snake.directionX == 0:
self.snake.directionY = 0
self.snake.directionX = -1
self.directionLimit = False
self.myWindow.fill((0, 0, 0))
for x in range(stepWidth, screenWidth, stepWidth):
pygame.draw.line(self.myWindow, (255, 255, 255), (x, 2 * stepWidth), (x, screenHeight), lineWidth)
for y in range(2 * stepWidth, screenHeight, stepWidth):
pygame.draw.line(self.myWindow, (255, 255, 255), (0, y), (screenWidth, y), lineWidth)
if self.isGameOver:
if not self.isStart:
self.fontPrinter(self.font_Beginning, screenWidth // 2, screenHeight // 2, 'Enter to start',
self.color_GameOver)
if self.isGameOver:
if self.isStart:
self.fontPrinter(self.font_GameOver, screenWidth // 2, screenHeight // 2, 'Game Over',
self.color_GameOver)
else:
now = time.time()
if now - self.lastMove > self.scoreAndSpeed.getSpeed():
if not self.isPause:
self.directionLimit = True
self.lastMove = now
nextStepX, nextStepY = (self.snake.getSn()[0][0] + self.snake.directionX) % (screenWidth // stepWidth),
(self.snake.getSn()[0][1] + self.snake.directionY)
if nextStepY >= (screenHeight // stepWidth) or nextStepY < 2:
if nextStepY >= (screenHeight // stepWidth):
nextStepY = 2
elif nextStepY < 2:
nextStepY = screenHeight // stepWidth - 1
else:
nextStepY = nextStepY % (screenHeight // stepWidth)
if nextStepX == self.apple.getX() and nextStepY == self.apple.getY():
self.apple = Apple(self.snake)
self.snake.pushBack([nextStepX, nextStepY])
self.scoreAndSpeed.setScore(self.scoreAndSpeed.getScore() + 10)
self.scoreAndSpeed.setSpeed(self.scoreAndSpeed.getOriSpeed() - 0.03 * (self.scoreAndSpeed.getScore() // 100))
else:
if [nextStepX, nextStepY] not in self.snake.getSn():
self.snake.pushBack([nextStepX, nextStepY])
self.snake.pop()
else:
self.isGameOver = True
else:
self.fontPrinter(self.font_Beginning, screenWidth // 2, screenHeight // 2, 'space to continue',
self.color_GameOver)
if not self.isGameOver:
pygame.draw.rect(self.myWindow, (255, 0, 0), (self.apple.getX() * stepWidth + 1, self.apple.getY() * stepWidth + 1,
stepWidth - 2, stepWidth - 2), 0)
for snake in self.snake.getSn():
pygame.draw.rect(self.myWindow, (200, 200, 200), (snake[0] * stepWidth + 1, snake[1] * stepWidth + 1, stepWidth - 2, stepWidth - 2), 0)
self.fontPrinter(self.font_Length, 30, 7, f'length:{len(self.snake)}', (255, 255, 255))
self.fontPrinter(self.font_score, 450, 7, f'score:{self.scoreAndSpeed.getScore()}', (255, 255, 255))
pygame.display.update()
全部代码
# Snake by myself
'''
About Variables:
// directionX: the direction on x-axis, '1' is to right, '-1' is to left, else '0'
// directionY: the direction on y-axis, '-1' is to up, '1' is to down, else '0'
// isGameOver: if 'isGameOver' and 'isStart' are all true, the game will over
'''
import queue
import random
import sys
import pygame
import time
from pygame.locals import *
from collections import deque
# the bound of game screen
screenWidth = 600
screenHeight = 480
stepWidth = 20
lineWidth = 1
class Snake:
def __init__(self) -> None:
self._sn = deque()
self._sn.append([2, 2])
self._sn.append([1, 2])
self._sn.append([0, 2])
self.directionX = 1
self.directionY = 0
def pushBack(self, nextStep : list) -> None:
self._sn.appendleft(nextStep)
def pop(self) -> None:
self._sn.pop()
def __len__(self) -> int:
return len(self._sn)
def getSn(self) -> deque:
return self._sn
class Apple:
def __init__(self, snake : Snake):
self._x = random.randint(0, screenWidth // 20 - 1)
self._y = random.randint(2, screenHeight // 20 - 1)
while [self._x, self._y] in snake.getSn():
self._x = random.randint(0, screenWidth // 20 - 1)
self._y = random.randint(2, screenHeight // 20 - 1)
def getX(self) -> int:
return self._x
def getY(self) -> int:
return self._y
class ScoreAndSpeed:
def __init__(self):
self._score = 0
self._oriSpeed = 0.5
self._speed = self._oriSpeed
def getScore(self) -> int:
return self._score
def setScore(self, score : int):
self._score = score
def getOriSpeed(self) -> float:
return self._oriSpeed
def getSpeed(self) -> float:
return self._speed
def setSpeed(self, speed : float):
self._speed = speed
class Game:
def __init__(self):
pygame.init()
self.myWindow = pygame.display.set_mode((screenWidth, screenHeight), 0, 32)
pygame.display.set_caption("Snake")
self.myWindow.fill((0, 0, 0))
pygame.display.update()
self.font_score = pygame.font.SysFont('SimHei', 24)
self.font_Length = pygame.font.SysFont('SimHei', 24)
self.font_GameOver = pygame.font.SysFont(None, 72)
self.font_Beginning = pygame.font.SysFont(None, 48)
self.color_GameOver = (255, 255, 255)
# self.directionX = 1
# self.directionY = 0
self.directionLimit = True
self.isGameOver = True
self.isStart = False
# self.score = 0
# self.oriSpeed = 0.5
self.lastMove = time.time()
self.isPause = False
self.snake = Snake()
self.apple = Apple(self.snake)
self.scoreAndSpeed = ScoreAndSpeed()
self.speed = self.scoreAndSpeed.getOriSpeed()
def fontPrinter(self, font, x, y, text, fcolor = (255, 255, 255)):
Textimg = font.render(text, True, fcolor)
self.myWindow.blit(Textimg, (x, y))
def runing(self):
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_RETURN:
# restart game
if self.isGameOver:
self.isGameOver = False
self.isStart = True
self.directionLimit = True
self.snake = Snake()
self.apple = Apple(self.snake)
self.scoreAndSpeed = ScoreAndSpeed()
self.lastMove = time.time()
elif event.key == K_SPACE:
if not self.isGameOver:
self.isPause = not self.isPause
elif event.key in (K_UP, K_w):
if self.directionLimit and self.snake.directionY == 0:
self.snake.directionY = -1
self.snake.directionX = 0
self.directionLimit = False
elif event.key in (K_DOWN, K_s):
if self.directionLimit and self.snake.directionY == 0:
self.snake.directionY = 1
self.snake.directionX = 0
self.directionLimit = False
elif event.key in (K_RIGHT, K_d):
if self.directionLimit and self.snake.directionX == 0:
self.snake.directionY = 0
self.snake.directionX = 1
self.directionLimit = False
elif event.key in (K_LEFT, K_a):
if self.directionLimit and self.snake.directionX == 0:
self.snake.directionY = 0
self.snake.directionX = -1
self.directionLimit = False
self.myWindow.fill((0, 0, 0))
for x in range(stepWidth, screenWidth, stepWidth):
pygame.draw.line(self.myWindow, (255, 255, 255), (x, 2 * stepWidth), (x, screenHeight), lineWidth)
for y in range(2 * stepWidth, screenHeight, stepWidth):
pygame.draw.line(self.myWindow, (255, 255, 255), (0, y), (screenWidth, y), lineWidth)
if self.isGameOver:
if not self.isStart:
self.fontPrinter(self.font_Beginning, screenWidth // 2, screenHeight // 2, 'Enter to start',
self.color_GameOver)
if self.isGameOver:
if self.isStart:
self.fontPrinter(self.font_GameOver, screenWidth // 2, screenHeight // 2, 'Game Over',
self.color_GameOver)
else:
now = time.time()
if now - self.lastMove > self.scoreAndSpeed.getSpeed():
if not self.isPause:
self.directionLimit = True
self.lastMove = now
nextStepX, nextStepY = (self.snake.getSn()[0][0] + self.snake.directionX) % (screenWidth // stepWidth),
(self.snake.getSn()[0][1] + self.snake.directionY)
if nextStepY >= (screenHeight // stepWidth) or nextStepY < 2:
if nextStepY >= (screenHeight // stepWidth):
nextStepY = 2
elif nextStepY < 2:
nextStepY = screenHeight // stepWidth - 1
else:
nextStepY = nextStepY % (screenHeight // stepWidth)
if nextStepX == self.apple.getX() and nextStepY == self.apple.getY():
self.apple = Apple(self.snake)
self.snake.pushBack([nextStepX, nextStepY])
self.scoreAndSpeed.setScore(self.scoreAndSpeed.getScore() + 10)
self.scoreAndSpeed.setSpeed(self.scoreAndSpeed.getOriSpeed() - 0.03 * (self.scoreAndSpeed.getScore() // 100))
else:
if [nextStepX, nextStepY] not in self.snake.getSn():
self.snake.pushBack([nextStepX, nextStepY])
self.snake.pop()
else:
self.isGameOver = True
else:
self.fontPrinter(self.font_Beginning, screenWidth // 2, screenHeight // 2, 'space to continue',
self.color_GameOver)
if not self.isGameOver:
pygame.draw.rect(self.myWindow, (255, 0, 0), (self.apple.getX() * stepWidth + 1, self.apple.getY() * stepWidth + 1,
stepWidth - 2, stepWidth - 2), 0)
for snake in self.snake.getSn():
pygame.draw.rect(self.myWindow, (200, 200, 200), (snake[0] * stepWidth + 1, snake[1] * stepWidth + 1, stepWidth - 2, stepWidth - 2), 0)
self.fontPrinter(self.font_Length, 30, 7, f'length:{len(self.snake)}', (255, 255, 255))
self.fontPrinter(self.font_score, 450, 7, f'score:{self.scoreAndSpeed.getScore()}', (255, 255, 255))
pygame.display.update()
if __name__ == '__main__':
game = Game()
game.runing()



