Python pygame 贪吃蛇游戏开发实战:面向对象与函数式两种实现

宋时安
宋时安
发布时间:2026-10-14| 2人浏览过
原创

本文详细讲解如何使用 Python 的 pygame 模块开发贪吃蛇游戏。文章通过面向对象和函数式编程两种思路,分别展示了游戏主类、精灵控制及碰撞检测的实现。内容涵盖游戏循环、事件监听及画面更新机制,并附带完整代码示例,适合 Python 初学者参考学习。

Python pygame 贪吃蛇游戏开发实战:面向对象与函数式两种实现

Python

面向对象实现:游戏主类与工具类

利用 pygame 模块,基于面向对象的思想来编写贪吃蛇游戏,核心涉及 pygame.sprite 模块的使用。

游戏主逻辑类

游戏主类代码解析


import pygame,sys
from snake_sprite import Game_sprite,Snake,Food
SCREEN_RECT=pygame.Rect(0,0,828,600)

IMG_URL="./image/bg.jpg"
#主类
class Snakegame(object):
 def __init__(self):
  self.screen=pygame.display.set_mode(SCREEN_RECT.size)
  self.clock=pygame.time.Clock()
  self.__create_sprites()

 def __create_sprites(self):
  bg=Game_sprite(IMG_URL)
  self.snake=Snake()
  for pos in self.snake.snake_point:
   self.screen.blit(self.snake.image,pos)
  food=Food()
  self.bg_group=pygame.sprite.Group(bg)
  self.snake_group=pygame.sprite.Group(self.snake)
  self.food_group = pygame.sprite.Group(food)
 def start_game(self):
  while True:
   #1.时钟设置
   self.clock.tick(30)
   #2.事件监听
   self.__event_handler()
   #3.碰撞检测
   self.__check_collide()
   #4.精灵更新
   self.__update_sprites()
   #5.屏幕更新
   pygame.display.update()
 def __event_handler(self):
  for event in pygame.event.get():
   if event.type==pygame.QUIT:
    Snakegame.__game_over()
   elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT and \
     self.snake.direction !='L':
    self.snake.speedy = 0
    self.snake.speedx = 1
    self.snake.direction = 'R'
   elif event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT and \
     self.snake.direction !='R':
    self.snake.speedy = 0
    self.snake.speedx = -1
    self.snake.direction = 'L'
   elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP and \
     self.snake.direction !='D':
    self.snake.speedx = 0
    self.snake.speedy = -1
    self.snake.direction = 'U'
   elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN and \
     self.snake.direction !='U':
    self.snake.speedx=0
    self.snake.speedy=1
    self.snake.direction='D'
 def __check_collide(self):
  pass
 def __update_sprites(self):
  self.bg_group.update()
  self.bg_group.draw(self.screen)
  self.snake_group.update()
  self.snake_group.draw(self.screen)
  self.food_group.update()
  self.food_group.draw(self.screen)
 @staticmethod
 def __game_over():
  pygame.quit()
  exit()

#游戏启动
if __name__ == '__main__':
 snake=Snakegame()
 snake.start_game()

工具类与精灵定义

辅助工具类

工具类代码解析


import pygame
import random
SNAKE_IMG="./image/snake.png"
FOOD_IMG="./image/food.jpg"
class Game_sprite(pygame.sprite.Sprite):
 def __init__(self,img_name,speedx=1,speedy=0):
  #调用父类的初始化方法
  super(Game_sprite, self).__init__()
  #属性
  self.image=pygame.image.load(img_name)
  self.rect=self.image.get_rect()
  self.speedx=speedx
  self.speedy=speedy
 def update(self):
  pass
#蛇实物
class Snake(Game_sprite):
 def __init__(self,direction='R',snakelist=[[40,40],[80,40]]):
  self.direction=direction
  self.snake_point=snakelist
  super().__init__(SNAKE_IMG)
  self.rect.x=self.snake_point[1][0]
  self.rect.y=self.snake_point[1][1]
 def update(self):
  self.rect.x += self.speedx
  self.rect.y += self.speedy
class Food(Game_sprite):
 def __init__(self):
  super(Food, self).__init__(FOOD_IMG)
  self.rect.x = random.randint(50, 828)
  self.rect.y = random.randint(38, 600)
 def update(self):
  pass

关于本次演示的说明

关于本次演示的说明

在此 demo 中,作者意识到自己对 pygame 的具体画面更新机制以及精灵控制尚不完全理解,贪吃蛇头部与身体的画面渲染尚未完全实现,且对身体与头部的数据结构构建也缺乏深入认识。鉴于这是初次尝试,希望有经验的开发者能对此博客内容提出指导意见。

函数式编程实现

以下是函数式编程版本的代码实现。

函数式代码解析


import pygame
import time
import random
x = pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,155,0)
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Slither')
gameDisplay.fill(white)
pygame.display.update()
block_size = 20
applethickness = 30
FPS = 10
icon = pygame.image.load('appleimage.jpg')
pygame.display.set_icon(icon)
img = pygame.image.load('snakeimage.jpg')
appleimage = pygame.image.load('appleimage.jpg')
clock = pygame.time.Clock()
smallfont = pygame.font.SysFont(None,30)
midfont = pygame.font.SysFont(None,50)
largefont = pygame.font.SysFont("comicsansms",80)
direction = "right"
def pause():
 paused = True
 message_to_screen("暂停",black,-100,"large")
 message_to_screen("空格暂停Q退出",black, 30)
 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 == pygame.K_SPACE:
     paused = False
    elif event.key == pygame.K_q:
     pygame.quit()
     quit()
  #gameDisplay.fill(white)
 clock.tick(5)

def score(score):
 text1 = smallfont.render("Score : " + str(score), True, black)
 gameDisplay.blit(text1,(0,0))
def randApplegen():
 randAppleX = round(random.randrange(0,display_width-applethickness))#/10.0)*10.0
 randAppleY = round(random.randrange(0,display_height-applethickness))#/10.0)*10.0
 return randAppleX, randAppleY

def intro():
 intro = True
 message_to_screen("按c开始游戏",red,150)
 pygame.display.update()
 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 == pygame.K_q:
     pygame.quit()
     quit()
  clock.tick(15)
def snake(snakelist):
 for xny in snakelist[:-1]:
  pygame.draw.rect(gameDisplay,green,[xny[0],xny[1],block_size,block_size])
 if(direction == "right"):
  head = pygame.transform.rotate(img,270)
 elif(direction == "left"):
  head = pygame.transform.rotate(img,90)
 elif(direction == "up"):
  head = img
 elif(direction == "down"):
  head = pygame.transform.rotate(img,180)
 gameDisplay.blit(head,(snakelist[-1][0],snakelist[-1][1]))
def text_objects(text,color,size):
 if(size == "small"):
  textsurface = smallfont.render(text,True,color)
 elif(size == "middle"):
  textsurface = midfont.render(text,True,color)
 elif(size == "large"):
  textsurface = largefont.render(text,True,color)
 return textsurface, textsurface.get_rect()
def message_to_screen(msg,color,y_displace=0,size="small"):
 textsurf, textsurf_rect = text_objects(msg,color,size)
 textsurf_rect.center = (display_width/2), (display_height/2) + y_displace
 gameDisplay.blit(textsurf,textsurf_rect)

def gameLoop():
 global direction
 direction = "right"
 gameExit = False
 gameOver = False
 lead_x = display_width/2
 lead_y = display_height/2
 lead_x_change = 10
 lead_y_change = 0
 randAppleX, randAppleY = randApplegen()
 snakelist = []
 snakelength = 1
 while not gameExit:
  if gameOver == True:
   message_to_screen("Game Over",red,-50,"large")
   message_to_screen("Press C to play again or Q to quit the game",black,50,"small")
   pygame.display.update()
  while gameOver == True:
   #gameDisplay.fill(white)
   for event in pygame.event.get():
    if event.type == pygame.KEYDOWN:
     if event.key == pygame.K_q:
      gameExit = True
      gameOver = False
     if event.key == pygame.K_c:
      gameLoop()
      pygame.quit()
      quit()
    if event.type == pygame.QUIT:
     gameExit = True 
     gameOver = False
     # pygame.quit()
     # quit()
  for event in pygame.event.get():
   if event.type == pygame.QUIT:
    gameExit = True 
   if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT and direction != "right":
     direction = "left"
     lead_x_change = -block_size
     lead_y_change = 0
    elif event.key == pygame.K_RIGHT and direction != "left":
     direction = "right"
     lead_x_change = block_size
     lead_y_change = 0
    elif event.key == pygame.K_UP and direction != "down":
     direction = "up"
     lead_y_change = -block_size
     lead_x_change = 0
    elif event.key == pygame.K_DOWN and direction != "up":
     direction = "down"
     lead_y_change = block_size
     lead_x_change = 0
    elif event.key == pygame.K_SPACE:
     pause()
  if lead_x + block_size/2 >= display_width or lead_x < 0 or lead_y + block_size/2 >= display_height or lead_y < 0:
   gameOver = True
  lead_x += lead_x_change
  lead_y += lead_y_change
  gameDisplay.fill(white)
  gameDisplay.blit(appleimage,(randAppleX,randAppleY))
  #pygame.draw.rect(gameDisplay,red,[350,350,100,10])
  # gameDisplay.fill(red, rect=[200,200,50,50])  #good method
  snakehead = []
  snakehead.append(lead_x)
  snakehead.append(lead_y)
  snakelist.append(snakehead)
  if len(snakelist) > snakelength:
   del snakelist[0]
  for each in snakelist[:-1]:
   if each == snakehead:
    gameOver = True
  snake(snakelist)
  score(snakelength-1)
  pygame.display.update()
  if lead_x >= randAppleX and lead_x <= randAppleX + applethickness or lead_x + block_size >= randAppleX and lead_x + block_size <= randAppleX + applethickness:
   if lead_y >= randAppleY and lead_y <= randAppleY + applethickness or lead_y + block_size >= randAppleY and lead_y + block_size <= randAppleY + applethickness:
    randAppleX, randAppleY = randApplegen()
    snakelength += 1;    
  clock.tick(FPS)
intro()
gameLoop()

pygame.quit()
quit()

总结

以上便是使用 pygame 模块编写贪吃蛇游戏的完整实例讲解,希望能为大家提供有价值的参考,也欢迎大家继续支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。