admin管理员组文章数量:1621658
代码实现
不得不说python真是太香了,我感觉写起来比C++快,而且代码量更少,还有非常多十分方便的方法可以使用。在pycharm里有非常多的快捷键十分的方便,相较项目使用的visual studio快捷键更多更灵活。
这篇博文我基于上一篇的博文结构进行代码粘贴以及解释。
目录
- 代码实现
- 一、贪吃龙
- 1. 龙的定义
- 2. 食物的定义
- 3. 窗口变量 & 初始化窗口
- 4. 初始化游戏
- 5. 欢迎界面
- 6. 开始游戏
- 7. 子方法
- (1)snakeMove()方法:
- (2)food()方法:
- (3)bodyMove()方法:
- (4)check()方法:
- (5)gameOver
- 8. 事件
- (1) keyPressEvent()方法:
- (2)paintEvent()方法:
一、贪吃龙
1. 龙的定义
(1)head_x,head_y:龙头部的坐标可以用两个变量来定义,一个储存龙头在地图的第几行,另一个储存龙头在地图的第几列。
(2)coordinate[]:整条龙包括龙头的坐标可以放在一个列表里,列表里的每一个元素为字符串类型,方便用于查找判定龙头是否与自身发生碰撞。
(3)direction:龙头部的当前方向。
# 龙变量
# 龙头的坐标
head_x = 0 # 龙头横坐标
head_y = 0 # 龙头纵坐标
direction = 0 # 龙头方向
coordinate = [] # 坐标数组,整条龙每一个结点的坐标(包括龙头)
2. 食物的定义
(1)food_coordinate:用于储存当前食物的坐标。
(2)food_type:食物种类。
# 食物变量
food_coordinate = '' # 食物坐标
food_type = 1 # 食物种类
3. 窗口变量 & 初始化窗口
# 窗口变量
w_width = 1200
w_height = 900
row = 0 # 行数
column = 0 # 列数
information_bar = w_width - w_height # 游戏界面信息窗口宽度
keyboard = 1 # 限制键盘录入
welcome_flag = 1 # 判断是否在欢迎界面
pygame.mixer.init()
music = pygame.mixer.music
(1)__init__方法: 设置窗口大小,窗口图标,以及固定窗口大小。
# 定义构造函数初始化窗口
def __init__(self):
QWidget.__init__(self) # 调用父类的构造函数
self.setWindowTitle('贪吃龙 v1.0') # 设置窗口标题
self.setWindowIcon(QIcon("Logo.jpg"))
self.resize(self.w_width, self.w_height) # 游戏窗口大小
self.setFixedSize(self.width(), self.height()) # 让游戏窗口大小固定
self.timer = QTimer() # 设置计时器
# 音乐模块
self.welcome()
4. 初始化游戏
init()方法:
(1)随机龙头位置、龙头方向、食物位置食物种类;
# 初始化游戏
def init(self):
self.setStyleSheet('background-color:#D9DADF') # 设定游戏背景颜色
self.row = 16 # 行数
self.column = 16 # 列数
# 初始化龙头坐标并避免龙头离地图边缘太近
self.head_x = random.randint(0 + 5, self.column - 1 - 5) # 随机选取列
self.head_y = random.randint(0 + 5, self.row - 1 - 5) # 随机选取行
self.coordinate = [str(self.head_x) + ":" + str(self.head_y)] # 把龙头放进龙数组
self.direction = random.randint(0, 3) # 随机龙头初始方向(randint函数是双闭的)
(2)初始化龙的速度、分数;
# 初始化龙速度
self.speed = self.speed2
self.score = 0
(3)初始化键盘标志、暂停标志、结束标志;
self.keyboard = 1
self.stop_flag = 0
self.game_over = 0
(4)初始化游戏音乐;
self.music.stop()
self.music = pygame.mixer.Sound(r"game_music.mp3")
self.music.play(-1)
5. 欢迎界面
(1)初始化欢迎界面音乐;
(2)根据游戏标志选择进入主游戏界面;
# 欢迎界面
def welcome(self):
if self.welcome_flag == 0:
self.music.stop()
# 初始化
self.init()
# 进入主游戏界面
self.timer.timeout.connect(self.game) # 设置定时器超时后的槽函数
self.timer.start(self.speed) # 设定游戏速度
return
self.music = pygame.mixer.Sound(r"menu_music.mp3")
self.music.play(-1)
6. 开始游戏
(1)snakeMove()方法:龙的自动移动。
(2)check()方法:判断龙是否吃到食物、是否吃到自己、是否撞墙。
(3)update()方法:重新绘制,刷新地图。
# 游戏开始
def game(self):
# 限制一次刷新只能改变一次键盘
self.keyboard = 1
# 自动移动龙
self.snakeMove()
# 判断是否吃到食物
self.check()
# print("dir:" + str(self.direction) + " head: " + str(self.head_x) + " , " + str(
# self.head_y) + " body: " + str(self.coordinate) + " food:" + self.food_coordinate)
# 更新
self.update()
7. 子方法
(1)snakeMove()方法:
根据当前龙的方位,更新龙头坐标。
# 龙的移动
def snakeMove(self):
if self.direction == 0:
self.head_x -= 1
elif self.direction == 1:
self.head_x += 1
elif self.direction == 2:
self.head_y -= 1
elif self.direction == 3:
self.head_y += 1
(2)food()方法:
随机产生食物坐标,且坐标不与整条龙的任意一个结点坐标重合。
# 生成食物的坐标
def food(self):
while True:
food_x = random.randint(0 + 2, self.row - 1 - 2)
food_y = random.randint(0 + 2, self.column - 1 - 2)
temp = str(food_x) + ":" + str(food_y)
# 新生成食物坐标不能与龙重合
if temp not in self.coordinate:
self.food_coordinate = temp
break
(3)bodyMove()方法:
更新龙身和龙头的坐标位置。
# 龙的位置更新
def bodyMove(self):
temp = str(self.head_x) + ':' + str(self.head_y)
# 更新龙身位置
for n in range(len(self.coordinate) - 1, 0, -1):
self.coordinate[n] = self.coordinate[n - 1]
# 更新龙头位置
self.coordinate[0] = temp
(4)check()方法:
①判断龙是否吃到食物,如果吃到,更新速度、分数、各种标记。
# 检查龙是否吃到食物
def check(self):
temp = str(self.head_x) + ':' + str(self.head_y)
# 判断龙是否吃到食物
if self.food_coordinate == temp:
self.coordinate.insert(0, temp)
pygame.mixer.music.load(r"get_point.mp3")
pygame.mixer.music.play(start=0.5)
if self.food_type == 1:
self.score += 30
elif self.food_type == 2:
self.score += 50
elif self.food_type == 3:
self.score += 70
self.speed -= 5
self.timer.start(self.speed) # 更新游戏速度
self.food()
self.food_type = random.randint(1, 3)
if self.score >= self.goal_score:
self.gameOver(False)
return
②判断龙是否触碰到边界,如果碰到就执行结束游戏方法。
else:
# 判断边界
if (self.head_x < 0 or self.head_x >= self.column) or (self.head_y < 0 or self.head_y >= self.row):
self.gameOver(True)
return
③判断龙头是否触碰到自身,如果碰到就执行结束游戏方法。
# 判断龙头是否触碰到龙身
if temp in self.coordinate[1:]: # 龙头碰到龙身
self.gameOver(True)
return
self.bodyMove()
(5)gameOver
①更新最高分。
# 游戏结束,弹出提示框 flag == True(游戏失败);bWin == False(恭喜过关)
def gameOver(self, flag):
self.timer.stop()
if self.score > self.top_score:
self.top_score = self.score # 保存最高分
②根据游戏结束标记判断游戏失败或游戏胜利。
if flag:
self.game_over = 1 # 游戏失败
pygame.mixer.music.load(r"lose_music.mp3")
pygame.mixer.music.play()
③画出胜利标志,播放对应音效。
else:
self.game_over = 2 # 游戏胜利
pygame.mixer.music.load(r"win_music.mp3")
pygame.mixer.music.play()
self.update()
8. 事件
(1) keyPressEvent()方法:
获取键盘按下的按键,通过区分不同按键来做出对应操作。
# 键盘事件
def keyPressEvent(self, event):
QWidget.keyPressEvent(self, event)
key = event.key()
①限制每次刷新按键次数,避免出现bug
# 如果此轮刷新已经按下过按钮则不允许再按下
if self.keyboard == 0:
return
②↑↓←→ 键:改变龙头方向
# 按键模块
if key == Qt.Key_Up and self.direction != 1: # 上
self.direction = 0
self.keyboard = 0
elif key == Qt.Key_Down and self.direction != 0: # 下
self.direction = 1
self.keyboard = 0
elif key == Qt.Key_Left and self.direction != 3: # 左
self.direction = 2
self.keyboard = 0
elif key == Qt.Key_Right and self.direction != 2: # 右
self.direction = 3
self.keyboard = 0
③Space 键:开始游戏 / 暂停游戏 / 重新开始游戏
# 暂停模块
if key == Qt.Key_Space and self.game_over == 0:
pygame.mixer.music.load(r"key_music.mp3")
pygame.mixer.music.play()
self.stop_flag += 1
if self.stop_flag % 2 == 1:
self.timer.stop()
self.update()
else:
self.timer.start(self.speed)
④结束游戏模块:游戏结束后进行相应的键盘处理
# 结束游戏模块
if self.game_over != 0:
# 重新开始游戏
if key == Qt.Key_Space:
pygame.mixer.music.load(r"key_music.mp3")
pygame.mixer.music.play()
self.init()
self.timer.start(self.speed)
self.game()
⑤欢迎界面:在欢迎界面下对按键进行处理
# 欢迎界面
if self.welcome_flag == 1:
if key == Qt.Key_Space:
pygame.mixer.music.load(r"key_music.mp3")
pygame.mixer.music.play()
self.welcome_flag = 0
self.welcome()
⑥Esc 键:退出游戏
# 退出游戏
if key == Qt.Key_Escape:
self.close()
(2)paintEvent()方法:
每次执行update()方法的时候会调用paintEvent方法,通过在类内定义的各种标志来绘制不同的图形。
①创建一个画笔。
# 绘制
def paintEvent(self, event):
QWidget.paintEvent(self, event)
painter = QPainter(self) # 创建一个画笔
②根据欢迎界面标志判断是否要画欢迎界面,如果不是则画主游戏界面。
# 欢迎界面
if self.welcome_flag == 1:
painter.drawImage(QRectF(0, 0, self.width(), self.height() + 50),
QImage('welcome.jpeg'))
painter.setFont(QFont('方正小篆体', 100))
painter.drawText(self.width() - 900, 400, "贪吃龙")
painter.setFont(QFont('汉仪尚巍手书W', 30))
painter.drawText(self.width() - 850, 525, "空格 键:开始游戏")
painter.drawText(self.width() - 825, 600, "Esc 键:退出游戏")
return
③画主界面的背景图、信息栏图、分割线、分数、最高分、提示信息等。
# 主游戏界面
pen = QPen(QColor(200, 200, 200), 1, Qt.DashLine) # 设定画笔的颜色、粗细以及线型
# 反锯齿
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(pen) # 更新画笔参数
painter.drawImage(QRectF(0, 0, self.width() - self.information_bar, self.height()),
QImage('game.jpg'))
painter.drawImage(QRectF(self.width() - self.information_bar, 0, self.information_bar, self.height()),
QImage('information.jpg'))
row_space = self.height() / self.row # 行间距
column_space = (self.width() - self.information_bar) / self.column # 列间距
# 绘制行线和列线
for n in range(self.row + 1):
painter.drawLine(QPointF(0, row_space * n), QPointF(self.width() - self.information_bar, row_space * n))
for n in range(self.column + 1):
painter.drawLine(QPointF(column_space * n, 0), QPointF(column_space * n, self.height()))
pen = QPen(QColor(50, 50, 50), 5, Qt.SolidLine) # 设定画笔的颜色、粗细以及线型
painter.setPen(pen) # 更新画笔参数
painter.drawLine(QPointF(self.width(), 0), QPointF(self.width(), self.height()))
painter.drawLine(QPointF(0, 0), QPointF(self.width(), 0))
painter.drawLine(QPointF(0, 0), QPointF(0, self.height()))
painter.drawLine(QPointF(0, self.height()), QPointF(self.width(), self.height()))
painter.drawLine(QPointF(self.width() - self.information_bar, 0),
QPointF(self.width() - self.information_bar, self.height()))
④龙龙头、龙身、龙尾巴。
cnt = 0
# 画整条龙
for n in self.coordinate:
row = int(n[:n.find(':')])
column = int(n[n.find(':') + 1:])
# 画龙头
if cnt == 0:
if self.direction == 0: # 朝上
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('head_up.png'))
elif self.direction == 1: # 朝下
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('head_down.png'))
elif self.direction == 2: # 朝左
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('head_left.png'))
elif self.direction == 3: # 朝右
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('head_right.png'))
elif cnt == self.coordinate.__len__() - 1:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('tail.png'))
else: # 龙身
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('body.png'))
cnt += 1
⑤根据食物种类标记,画不同的食物。
# 画食物
# 获取方块位置
row = int(self.food_coordinate[:self.food_coordinate.find(':')])
column = int(self.food_coordinate[self.food_coordinate.find(':') + 1:])
if self.food_type == 1:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('dragon_ball_1.png'))
elif self.food_type == 2:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('dragon_ball_2.png'))
elif self.food_type == 3:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('dragon_ball_3.png'))
⑥画信息栏,包括:分数、最高分、按键规则、游戏规则。
# 画信息栏
painter.setPen(QColor(0, 0, 0))
painter.setFont(QFont('汉仪尚巍手书W', 30))
painter.drawText(self.width() - 215, 100, "分 数")
painter.drawText(self.width() - 190, 175, str(self.score))
painter.drawText(self.width() - 215, 275, "最高分")
painter.drawText(self.width() - 190, 350, str(self.top_score))
painter.drawText(self.width() - 250, 450, "按键规则")
painter.setFont(QFont('汉仪尚巍手书W', 20))
painter.drawText(self.width() - 250, 525, "↑↓←→控制")
painter.drawText(self.width() - 250, 575, " 空格 暂停")
painter.setFont(QFont('汉仪尚巍手书W', 30))
painter.drawText(self.width() - 250, 675, "游戏规则")
painter.setFont(QFont('汉仪尚巍手书W', 20))
painter.drawText(self.width() - 235, 750, "不能碰墙壁")
painter.drawText(self.width() - 235, 800, "不能碰身体")
painter.drawText(self.width() - 235, 850, "1000分过关")
⑦根据游戏暂停标记画游戏暂停提示。
# 画游戏暂停
if self.stop_flag % 2 == 1:
painter.setFont(QFont('汉仪尚巍手书W', 100))
painter.drawText(self.width() - 1085, 425, "游戏暂停")
painter.setFont(QFont('汉仪尚巍手书W', 30))
painter.drawText(self.width() - 960, 550, "按 空格 键继续游戏")
painter.drawText(self.width() - 950, 625, "按 Esc 键退出游戏")
⑧根据游戏结束标记绘制游戏胜利 / 游戏失败,显示得分以及提示信息。
# 画游戏结束
painter.setPen(QColor(242, 15, 21))
if self.game_over == 1:
painter.setFont(QFont('汉仪尚巍手书W', 100))
painter.drawText(self.width() - 1085, 400, "游戏失败")
elif self.game_over == 2:
painter.setFont(QFont('汉仪尚巍手书W', 100))
painter.drawText(self.width() - 1085, 400, "恭喜过关")
painter.setPen(QColor(0, 0, 0))
if self.game_over != 0:
painter.setFont(QFont('汉仪尚巍手书W', 50))
painter.drawText(self.width() - 1050, 525, "你的得分为:")
painter.setPen(QColor(245, 126, 13))
painter.drawText(self.width() - 525, 525, str(self.score))
painter.setPen(QColor(0, 0, 0))
painter.setFont(QFont('汉仪尚巍手书W', 30))
painter.drawText(self.width() - 1000, 625, "按 空格 键重新开始游戏")
painter.drawText(self.width() - 950, 700, "按 Esc 键退出游戏")
这一篇是贪吃龙游戏代码的实现,游戏的游玩见下一篇博客。
———2020.12.16(罗涵)
THE END
版权声明:本文标题:计算机软件实习项目二 —— 贪吃蛇游戏 (代码实现) 12-16 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1728850338a1176595.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论