在python中通过面向对象设计模式来实现一个贪吃蛇小游戏
源码在最下方,上传的资源包内也包括代码源文件以及所需素材等,源文件在game文件夹内,exe文件可直接运行,pygame模块需要自行下载
先来看运行效果图:
开始界面,点击按钮开始游戏
游戏内界面,吃掉食物增加长度,蛇头出界或撞到身体部分则游戏失败
结算界面,显示当前成绩和历史最高分,点击按钮重来
测试功能:游戏内按下空格键强制死亡
然后说我的设计思路,主要依靠的是pygame的精灵以及精灵组碰撞,我这里总共创建了十个类
BaseSprite类 基本精灵类,用作玩家类,食物类等的父类
Food 食物类
FoodManage 食物管理类,用于管理食物类
PlayerSprite 玩家类
PlayerManage 玩家管理类,分为蛇身和蛇头,实现移动,吃食物等方法
UISprite UI类
UIMange UI管理类,有三个UI界面,开始前,游戏中,结束
AudioManage 声音管理类,按钮点击,背景音乐,死亡音效,吃掉食物音效
Util 鼠标点击检测,用于检测用户是否点击了开始或重来按钮
GameManage 总管理类
下面是源代码部分
import random
import time
import pygame
import sys
class Util:
"""
鼠标点击碰撞检测
"""
@staticmethod
def click_check(sprite):
if pygame.mouse.get_pressed()[0]:
if sprite.rect.collidepoint(pygame.mouse.get_pos()):
return True
return False
class AudioManage:
"""
声音管理类
"""
@staticmethod
def play_bg_music():
"""
背景音乐
"""
pygame.mixer.music.load("../sound/bgm.wav")
pygame.mixer.music.play(True)
@staticmethod
def play_sound(name):
sound = pygame.mixer.Sound(name)
sound.play()
class BaseSprite(pygame.sprite.Sprite):
"""
基本精灵类, 有name属性, 就是精灵的图片路径
"""
def __init__(self, name):
super().__init__()
self.image = pygame.image.load(name)
self.rect = self.image.get_rect()
class Food(BaseSprite):
"""
食物类
"""
def __init__(self, name, center):
super().__init__(name)
self.rect.center = center
class PlayerSprite(Food):
"""
玩家类(蛇头, 蛇身)
"""
def __init__(self, name, center):
super().__init__(name, center)
class UISprite(Food):
"""
ui类
"""
def __init__(self, name, center):
super().__init__(name, center)
class FoodManage:
"""
食物管理类
"""
def __init__(self, gm):
self.gm = gm
self.food_groups = pygame.sprite.Group()
def update(self):
self.food_groups.update()
self.food_groups.draw(self.gm.screen)
def clear(self):
self.food_groups.empty()
def add_food(self):
self.food = Food("../image/food.png", (random.randrange(25, 575, 25), random.randrange(25, 575, 25)))
self.food.add(self.food_groups)
class PlayerManage:
"""
玩家管理类
"""
def __init__(self, gm):
self.gm = gm
self.player_groups = pygame.sprite.Group()
self.body_groups = pygame.sprite.Group()
AudioManage.play_bg_music()
def born(self):
self.mk_dir = "left"
self.player = PlayerSprite("../image/left.png", (500, 500))
self.player.add(self.player_groups)
for i in range(3):
self.body = PlayerSprite("../image/body.png", (500 + 25 * (i + 1), 500))
self.body.add(self.body_groups)
for i in range(3):
self.food = Food("../image/food.png", (random.randrange(25, 575, 25), random.randrange(25, 575, 25)))
self.food.add(self.gm.food_manage.food_groups)
pygame.time.set_timer(6666, 100)
def update(self):
self.player_groups.update()
self.body_groups.update()
self.player_groups.draw(self.gm.screen)
self.body_groups.draw(self.gm.screen)
def clear(self):
self.player_groups.empty()
self.body_groups.empty()
def move(self, dir):
first = self.player.rect.center
last = self.body.rect.center
for i in range(len(self.body_groups.sprites()) - 1, 0, -1):
self.body_groups.sprites()[i].rect.center = self.body_groups.sprites()[i - 1].rect.center
self.body_groups.sprites()[0].rect.center = first
self.mk_dir = dir
if self.mk_dir == "up":
self.player.image = pygame.image.load("../image/up.png")
self.player.rect.centery -= 25
elif self.mk_dir == "down":
self.player.image = pygame.image.load("../image/down.png")
self.player.rect.centery += 25
elif self.mk_dir == "left":
self.player.image = pygame.image.load("../image/left.png")
self.player.rect.centerx -= 25
elif self.mk_dir == "right":
self.player.image = pygame.image.load("../image/right.png")
self.player.rect.centerx += 25
if pygame.sprite.spritecollide(self.player, self.gm.food_manage.food_groups, True):
AudioManage.play_sound("../sound/eat.mp3")
self.eat(last)
self.gm.food_manage.add_food()
if pygame.sprite.spritecollide(self.player, self.body_groups, False):
AudioManage.play_sound("../sound/die.wav")
self.gm.state = "end"
pygame.time.set_timer(6666, 0)
if self.player.rect.left < 0 or self.player.rect.right > 600 or self.player.rect.top < 0 or self.player.rect.bottom > 600:
AudioManage.play_sound("../sound/die.wav")
self.gm.state = "end"
pygame.time.set_timer(6666, 0)
def eat(self, center):
self.body = PlayerSprite("../image/body.png", center)
self.body.add(self.body_groups)
self.gm.ui_manage.score += 5
if self.gm.ui_manage.score > self.gm.ui_manage.max_score:
self.gm.ui_manage.max_score = self.gm.ui_manage.score
self.gm.ui_manage.gaming_surface = self.gm.ui_manage.font.render(f"得分:{self.gm.ui_manage.score}", True,
(0, 0, 0))
class UIMange:
"""
ui管理类
"""
def __init__(self, gm):
self.gm = gm
self.max_score = 0
self.score = 0
self.font = pygame.font.Font(r"../font/simkai.ttf", 32)
# 开始前
self.start_groups = pygame.sprite.Group()
self.start_btn = UISprite("../image/begin_btn.png", (300, 300))
self.start_btn.add(self.start_groups)
# 游戏中
self.gaming_surface = self.font.render(f"得分:{self.score}", True, (0, 0, 0))
# 结束
self.end_groups = pygame.sprite.Group()
self.end_btn = UISprite("../image/replay_btn.png", (300, 300))
self.end_btn.add(self.end_groups)
def update(self):
if self.gm.state == "ready":
self.start_groups.draw(self.gm.screen)
if Util.click_check(self.start_btn):
AudioManage.play_sound("../sound/click.mp3")
self.gm.state = "gaming"
self.gm.player_manage.born()
if self.gm.state == "gaming":
self.gm.screen.blit(self.gaming_surface, (400, 20))
if self.gm.state == "end":
self.final_score = self.font.render(f"最终得分:{self.score}", True, (0, 0, 0))
self.final_max_score = self.font.render(f"最高分:{self.max_score}", True, (0, 0, 0))
self.gm.screen.blit(self.final_score, (200, 150))
self.gm.screen.blit(self.final_max_score, (200, 100))
self.gm.player_manage.clear()
self.gm.food_manage.clear()
self.end_groups.draw(self.gm.screen)
if Util.click_check(self.end_btn):
self.gm.dir = "left"
AudioManage.play_sound("../sound/click.mp3")
self.gm.player_manage.born()
self.gm.state = "gaming"
self.score = 0
self.gaming_surface = self.font.render(f"得分:{self.score}", True, (0, 0, 0))
class GameManage:
"""
游戏管理类(总管理类)
"""
def __init__(self, name):
pygame.init()
self.screen = pygame.display.set_mode((600, 600))
self.clock = pygame.time.Clock()
self.state = "ready"
self.ui_manage = UIMange(self)
self.player_manage = PlayerManage(self)
self.food_manage = FoodManage(self)
self.dir = "left"
pygame.display.set_caption(name)
def check_move(self):
if self.player_manage.mk_dir == "left" and self.dir == "right" or self.player_manage.mk_dir == "right" and self.dir == "left" or self.player_manage.mk_dir == "up" and self.dir == "down" or self.player_manage.mk_dir == "down" and self.dir == "up":
return False
else:
return True
def check_event(self):
for event in pygame.event.get():
if event.type == 256:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
self.state = "end"
# 键盘控制移动
if self.state == "gaming":
if event.type == 6666:
if self.check_move():
self.player_manage.move(self.dir)
else:
self.player_manage.move(self.player_manage.mk_dir)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and self.dir != "up":
self.dir = "up"
elif event.key == pygame.K_DOWN and self.dir != "down":
self.dir = "down"
elif event.key == pygame.K_LEFT and self.dir != "left":
self.dir = "left"
elif event.key == pygame.K_RIGHT and self.dir != "right":
self.dir = "right"
time.sleep(0.05)
def run(self):
while True:
if pygame.mixer.music.get_busy() == False:
AudioManage.play_bg_music()
self.clock.tick(50)
self.check_event()
self.screen.fill("#FFFACD")
self.ui_manage.update()
self.player_manage.update()
self.food_manage.update()
pygame.display.flip()
gm = GameManage("贪吃蛇大作战")
if __name__ == '__main__':
gm.run()