在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()