當你學會python,興趣正濃的時候,是不是迫不及待的想實現些什麼,實現什麼好呢,好難受,快讓我實現些什麼。實現個貪吃蛇吧,反正也沒啥技術含量(狗頭)
實現貪吃蛇的博客真的好多啊,一開始我想複製一個下來,然後看一看,改一改,我就想找一個直接全部複製到pycharm,然後運行就可以的,哎,怎麼找了幾個都不行…後來去pygame官網看看,隨手找到一個貪吃蛇實現,github把代碼複製下來,哎,好像就是我想要的東西了。原版的是這個樣子的
我們可以修改成這個樣子,看起來會不會好一點
是的上面的其實就是改顏色,不過還添加一個有趣地方,當蛇靠近邊緣時,會開啓“慢動作”比如下面這個
來一起看看是如何實現的,然後我們再給他修改修改,嘿嘿嘿
先來了解下思路,整個遊戲過程中,我們應該是不停的在循環檢查,每次循環檢查蛇是否碰到牆壁,是否碰到自己,是否吃到食物,然後每個結果都執行對應操作,最後更新一下畫面,繼續循環。蛇如何存呢,程序採用一個列表來存,把蛇的每一節都存在這個列表裏,然後蛇的移動,我們只需要把最後一節蛇刪除,然後計算出新的蛇頭位置,把蛇頭更新,說起來可能不太好理解,一看代碼就明白了,下面分步來看看(原始的版本),說明全部在代碼註釋中啦
1、初始化
def __init__(self, windowSizeX=500, windowSizeY=500):
#窗口大小
self.windowSizeX = windowSizeX
self.windowSizeY = windowSizeY
#食物和蛇的單位大小
self.gameUnitSize = 16
#讓屏幕和單位大小適配
if (self.windowSizeX % self.gameUnitSize != 0):
self.windowSizeX += self.gameUnitSize - self.windowSizeX % self.gameUnitSize
if (self.windowSizeY % self.gameUnitSize != 0):
self.windowSizeY += self.gameUnitSize - self.windowSizeY % self.gameUnitSize
self.window = pygame.display.set_mode(
[self.windowSizeX, self.windowSizeY])
#標題
pygame.display.set_caption("Snake!")
#填充色
self.window.fill((255, 255, 255))
#初始化字體
pygame.font.init()
#設置字體
self.font = pygame.font.SysFont("bahnschrift", 20)
#設置畫面顯示的內容
self.text = self.font.render(
"Press Direction key to begin", True, (0, 0, 0))
self.startTextRect = self.text.get_rect(
center=(windowSizeX/2, windowSizeY/2))
#這個就是我們的蛇了
self.snake = [self.startSnake()]
#這是我們的食物
self.food = self.createFood()
#速度
self.speed = self.gameUnitSize
#得分
self.score = 0
#得分顯示
self.scoreText = self.font.render(
f"Score: {self.score}", True, (0, 0, 0), None)
#蛇的方向控制
self.snakeDirections = {
'left': (-1, 0), 'right': (1, 0), 'up': (0, -1), 'down': (0, 1)}
#上一次的執行動作,初始化隨便給一個
self.previousDirection = self.snakeDirections.get('left')
#循環內容
self.readyScreen()
self.gameLoop()
2、循環部分
#檢測鍵盤事件,當有鍵盤按鍵按下時,pygame可以幫我們檢測到是什麼按鍵被按下了
def readyScreen(self):
while True:
self.window.blit(self.text, self.startTextRect)
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
keys = pygame.key.get_pressed()
if (keys[K_LEFT]):
self.previousDirection = self.snakeDirections.get('left')
break
if (keys[K_RIGHT]):
self.previousDirection = self.snakeDirections.get('right')
break
if (keys[K_UP]):
self.previousDirection = self.snakeDirections.get('up')
break
if (keys[K_DOWN]):
self.previousDirection = self.snakeDirections.get('down')
break
pygame.display.update()
#循環開始
def gameLoop(self):
while True:
pygame.time.delay(100)
self._input()
self._update()
#方向鍵被按下時,修改組成蛇的列表
def _input(self):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
keys = pygame.key.get_pressed()
if (keys[K_LEFT] and self.previousDirection != self.snakeDirections.get('right')):
self.moveSnake(self.snakeDirections.get('left'))
elif (keys[K_RIGHT] and self.previousDirection != self.snakeDirections.get('left')):
self.moveSnake(self.snakeDirections.get('right'))
elif (keys[K_UP] and self.previousDirection != self.snakeDirections.get('down')):
self.moveSnake(self.snakeDirections.get('up'))
elif (keys[K_DOWN] and self.previousDirection != self.snakeDirections.get('up')):
self.moveSnake(self.snakeDirections.get('down'))
else:
self.moveSnake(self.previousDirection)
#更新畫面的地方
def _update(self):
self.window.fill((0,0,0))
if (self.intersect() == True):
self.appendSnake()
self.moveFood()
self.score += 1
elif (self.snakeCollidingWithWall() == True or self.snakeCollidingWithSelf() == True):
return self.killSnake()
for link in self.snake:
pygame.draw.rect(self.window, (255,255,255), link)
pygame.draw.rect(self.window, (102, 255, 51), self.food)
self.scoreText = self.font.render(
f"Score: {self.score}", True, (255, 255, 255))
self.scoreTextRect = self.scoreText.get_rect(center=(40, 10))
self.window.blit(self.scoreText, self.scoreTextRect)
#不要忘了這個updata
pygame.display.update()
源碼代碼彙總如下:
class Game_snake_ex:
def __init__(self, windowsize_x=500, windowsize_y=500):
self.windowsize_x = windowsize_x
self.windowsize_y = windowsize_y
self.gameUnitsize = 16
if (self.windowsize_x % self.gameUnitsize != 0):
self.windowsize_x += self.gameUnitsize - self.windowsize_x % self.gameUnitsize
if (self.windowsize_y % self.gameUnitsize != 0):
self.windowsize_y += self.gameUnitsize - self.windowsize_y % self.gameUnitsize
self.window = pygame.display.set_mode(
[self.windowsize_x, self.windowsize_y])
pygame.display.set_caption("Snake!")
self.window.fill((0, 0, 0))
pygame.font.init()
self.font = pygame.font.SysFont("bahnschrift", 20)
self.text = self.font.render(
"Press Direction key to begin", True, (255, 255, 255))
self.startTextRect = self.text.get_rect(
center=(windowsize_x/2, windowsize_y/2))
self.snake = [self.startSnake()]
self.food = self.createFood()
self.speed = self.gameUnitsize
self.score = 0
self.scoreText = self.font.render(
f"Score: {self.score}", True, (255, 255, 255), None)
self.snakeDirections = {
'left': (-1, 0), 'right': (1, 0), 'up': (0, -1), 'down': (0, 1)}
self.previousDirection = self.snakeDirections.get('left')
self.readyScreen()
self.gameLoop()
def startSnake(self):
snakeNodeX = self.window.get_width() / 2 - self.gameUnitsize
if (snakeNodeX % self.gameUnitsize != 0):
snakeNodeX -= snakeNodeX % self.gameUnitsize
snakeNodeY = self.window.get_height() / 2 - self.gameUnitsize
if (snakeNodeY % self.gameUnitsize != 0):
snakeNodeY -= snakeNodeY % self.gameUnitsize
snakeNodeRectangle = Rect(
(snakeNodeX, snakeNodeY), (self.gameUnitsize, self.gameUnitsize))
return snakeNodeRectangle
def createFood(self):
foodX = randint(0, self.window.get_width() - self.gameUnitsize)
if (foodX % self.gameUnitsize != 0):
foodX -= foodX % self.gameUnitsize
foodY = randint(0, self.window.get_height() - self.gameUnitsize)
if (foodY % self.gameUnitsize != 0):
foodY -= foodY % self.gameUnitsize
foodRectangle = Rect(
(foodX, foodY), (self.gameUnitsize, self.gameUnitsize))
return foodRectangle
def moveFood(self):
self.food.x = randint(0, self.window.get_width() - self.gameUnitsize)
if (self.food.x % self.gameUnitsize != 0):
self.food.x -= self.food.x % self.gameUnitsize
self.food.y = randint(0, self.window.get_height() - self.gameUnitsize)
if (self.food.y % self.gameUnitsize != 0):
self.food.y -= self.food.y % self.gameUnitsize
def createSnake(self):
snakeNodeX = randint(0, self.window.get_width())
if (snakeNodeX % self.gameUnitsize != 0):
snakeNodeX -= snakeNodeX % self.gameUnitsize
snakeNodeY = randint(0, self.window.get_height())
if (snakeNodeY % self.gameUnitsize != 0):
snakeNodeY -= snakeNodeY % self.gameUnitsize
snakeNodeRectangle = Rect(
(snakeNodeX, snakeNodeY), (self.gameUnitsize, self.gameUnitsize))
return snakeNodeRectangle
def appendSnake(self):
# add node to tail
newSnakeLink = Rect((self.snake[len(self.snake) - 1].x, self.snake[len(
self.snake) - 1].y), (self.gameUnitsize, self.gameUnitsize))
self.snake.append(newSnakeLink)
def moveSnake(self, direction):
#蛇尾刪掉,更新蛇頭,其他不變
x = 0
y = 1
self.snake[len(self.snake) - 1].x = self.snake[0].x + \
direction[x] * self.speed
self.snake[len(self.snake) - 1].y = self.snake[0].y + \
direction[y] * self.speed
self.snake.insert(0, self.snake.pop())
self.previousDirection = direction
def intersect(self):
if self.snake[0].x == self.food.x and self.snake[0].y == self.food.y:
return True
return False
def snakeCollidingWithWall(self):
if self.snake[0].x >= self.windowsize_x or self.snake[0].x < 0 or self.snake[0].y >= self.windowsize_y or self.snake[0].y < 0:
return True
return False
def snakeCollidingWithSelf(self):
for link in self.snake:
if (self.snake[0] is not link):
if self.snake[0].x == link.x and self.snake[0].y == link.y:
return True
return False
def killSnake(self):
return self._gameOverScreen()
def _update(self):
self.window.fill((0,0,0))
if (self.intersect() == True):
self.appendSnake()
self.moveFood()
self.score += 1
elif (self.snakeCollidingWithWall() == True or self.snakeCollidingWithSelf() == True):
return self.killSnake()
for link in self.snake:
pygame.draw.rect(self.window, (255,255,255), link)
pygame.draw.rect(self.window, (102, 255, 51), self.food)
self.scoreText = self.font.render(
f"Score: {self.score}", True, (255, 255, 255))
self.scoreTextRect = self.scoreText.get_rect(center=(40, 10))
self.window.blit(self.scoreText, self.scoreTextRect)
pygame.display.update()
def _input(self):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
keys = pygame.key.get_pressed()
if (keys[K_LEFT] and self.previousDirection != self.snakeDirections.get('right')):
self.moveSnake(self.snakeDirections.get('left'))
elif (keys[K_RIGHT] and self.previousDirection != self.snakeDirections.get('left')):
self.moveSnake(self.snakeDirections.get('right'))
elif (keys[K_UP] and self.previousDirection != self.snakeDirections.get('down')):
self.moveSnake(self.snakeDirections.get('up'))
elif (keys[K_DOWN] and self.previousDirection != self.snakeDirections.get('up')):
self.moveSnake(self.snakeDirections.get('down'))
else:
self.moveSnake(self.previousDirection)
def readyScreen(self):
while True:
self.window.blit(self.text, self.startTextRect)
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
keys = pygame.key.get_pressed()
if (keys[K_LEFT]):
self.previousDirection = self.snakeDirections.get('left')
break
if (keys[K_RIGHT]):
self.previousDirection = self.snakeDirections.get('right')
break
if (keys[K_UP]):
self.previousDirection = self.snakeDirections.get('up')
break
if (keys[K_DOWN]):
self.previousDirection = self.snakeDirections.get('down')
break
pygame.display.update()
def _gameOverScreen(self):
while True:
self.window.fill((0, 0, 0))
self.text = self.font.render(
f"Game Over, Score: {self.score}", True, (255, 255, 255))
self.startTextRect = self.text.get_rect(
center=(self.windowsize_x/2, self.windowsize_y/2))
self.window.blit(self.text, self.startTextRect)
keys = pygame.key.get_pressed()
if (keys[K_r]):
break
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
pygame.display.update()
return 1
def gameLoop(self):
while True:
pygame.time.delay(100)
self._input()
self._update()
上面那個是原版,實現方法明白了以後,就可以自己動手來修改修改啦
這個是我添加 顏色變化 和“慢動作” 的版本
下載地址gitbub