5-1 干就完了!
Hello!各位肝酱们大家好~ 欢迎各位来到MMO贪吃蛇大作战系列教程的最后一课。
那么在最后一课中我们要制作什么呢?那肯定就是各位期待已久的MMO团队大作战模式啦!
在这个模式当中我们可以体验到跟队友来一场完美的无缝配合!一起击败对方 一起合作共赢
就像是这样! 那么首先 我们要匹配到6名以上的玩家,匹配到后我们给玩家进行随机分队 将玩家分成三个队伍,并且制作一下队友的机制 也就是碰到队友不会被击败,然后开始十分钟的倒计时 十分钟一到那我们就统计一下三个队伍的全部玩家总长度 然后根据总长度去排名,最后分出胜负。
好,那让我们来总结一下我们本节课需要做的
以下是对话中的要素总结:
匹配玩家:首先需要匹配到6名以上的玩家。
- 随机分队:匹配成功后,将玩家随机分成三个队伍。
- 队友机制:制作了一种队友机制,即碰到队友不会被击败。
- 倒计时:开始十分钟的倒计时。
- 统计玩家总长度:十分钟结束后,统计三个队伍的全部玩家总长度。
- 根据总长度排名:根据总长度进行排名。
- 分出胜负:根据排名结果
制作匹配界面
首先我们先回到作品中:
打开主界面按钮角色,然后我们在如果里面拖入一个新的判断,如果ID等于团战模式 那么就广播一个新的广播叫做 团战开始匹配:
然后我们创建一个新的角色叫做团战模式匹配:
然后让我们来绘制一下匹配界面所需要用到的造型:
就像这样,接着我们再来绘制一个简易的加载动画造型:
在中心点旁边绘制一个白色的半圆形~ 然后我们等会让他转起来就是加载动画啦!
(这里深色背景只是为了方便演示造型,实际是不需要绘制的~)
然后我们绘制完造型后就要来制作一下匹配角色的代码了,首先我们日常的初始化一下,当绿旗被点击 然后这里我们创建了一个新的变量“团战人数” 方便以后去使用 我们目前暂时将他设置为2就可以了,然后我们移动到屏幕中间 将大小设置为100并且隐藏 再克隆一下自己:
然后我们当作为克隆体启动时,首先这里我们又新建了一个新的变量叫做加载提示 方便我们随时去调用加载动画,那么就是刚开始将加载提示变量设置为0 然后我们将造型设置为造型2 也就是我们刚才绘制的加载动画造型,随后我们将大小设置个150 这里可以根据自己的喜好修改~ 并且我们将虚像设置为100 也就是让他先隐身 并且将造型状态设置为显示:
然后我们重复执行移动到最前面并且向右旋转15度 如果加载提示等于1 那么就代表我们要显示加载动画,所有这个时候我们将虚像持续的-5就可以了 这样他就可以慢慢的显现出来~ 如果不等于1 那么就重复增加 这样他就又会自动隐身起来了~
好!我们加载动画做完之后那么就是要来做匹配界面了,首先我们当接收到团战开始匹配广播时 那我们首先来判断一下执行的人是否是本体 也就是不是克隆体,然后我们将造型设置为1 设置一下隐身 移动到最前面并且显示,然后我们让加载提示显示出来 也就是将变量设为1 最后我们让他重复执行20次将虚像减五 慢慢显示:
好了,那么这样我们的界面就大功告成了 接下来就是真正的技术活了 那就是制作匹配机制!
制作团战匹配机制
首先我们肯定是要再新拖出来一个当接收到团战开始匹配广播的积木啦,然后我们日常判断一下是否是本体执行,如果是的话那么就首先我们将一个新的变量设为0 这个变量就是我们等会要用到返回参数的变量 名为“团战.等待返回参数”,然后我们连入一个MMO房间 服务器名为 团队匹配 然后我们将另外一个新的变量“团战.匹配倒计时”设置为“未知”也就是还不确定要多久才能开始游戏,最后我们等待当前房间的玩家数大于我们的团战.人数-1 我们刚才设置的人数是2:
然后我们等待完成了 也就是匹配到了我们设置人数的人,那么我们就重复执行直到一个团战倒计时等于0 如果等于了那么就相当于是要做开始游戏的处理了嘛,然后回到重复执行这里,我们重复执行调用一个新的自定义积木叫做“倒计时” 并且再次等待房间内的玩家数是否够变量的人数:
然后我们开始撰写这个新的自定义积木的代码。首先,我们将匹配倒计时设定为30,并且重复执行30次:将匹配倒计时减1。然后,我们创建了两个新的私有变量,分别是"团战.人数记录"和"团战.记录时间戳"。我们将"团战.人数记录"设置为当前方向的玩家人数,并将"团战.记录时间戳"设置为计时器的值。
接下来,我们继续重复执行以下循环,直到计时器减去"记录时间戳"的值大于1,也就是执行一秒的循环。在循环中,我们进行以下操作:如果当前房间的玩家数量大于"人数记录"变量或当前房间的玩家数量小于"人数记录",那么停止这个自定义积木。换句话说,如果房间中有新的玩家加入或有玩家退出导致人数不足,则退出倒计时,然后重新调用倒计时积木:
然后我们匹配完成后就要来做匹配后的处理了,首先让我们只做一下分队的机制,这里我们先判断了一下房间里面的第0个玩家ID是不是我(小提示:MMO的第XX个玩家都是从0开始的 第0个玩家也就是房间里面的第一个玩家)
是的没错 我们要把分队工作交给房间里面的第一个玩家去运行分队积木 其他的玩家只需要等待他分完然后接收就可以了。
那么首先如果房间里面的第一个玩家是我 首先我们新建一个列表和变量 分别是“团战.玩家列表”和“私有变量 i”,然后我们将列表清空 将变量i也设为0 然后我们重复执行当前房间玩家数量的次 每次循环我们将房间里面的第( i )个玩家的ID加入列表 然后我们将变量 i 增加 1:
我们遍历完房间里面的玩家ID之后我们就要来给他进行分队了,没错!我们终于要用到我们大名鼎鼎的Python in Gandi了 让我们来到Python的世界
分队机制
首先我们来到Python的代码编辑器然后我们创建一个新的Python文件:
然后我们就来开始写一下代码了~
首先我们导入了一些必须的库用来处理队伍信息~ 然后我们创建了三个积木
这里创建积木的格式我就不多教了!各位可以直接来到这里学习创建语法就可以了~ 非常详细又简单。
那么简单的看完代码之后我们就来挨个讲解一下这三个积木是做什么的是怎么实现的!
divide_teams积木
def divide_teams(members: List[str], num_teams: int) -> str:
total_players = len(members) # 获取成员总数
players_per_team = math.floor(total_players / num_teams) # 计算每个队伍的平均人数,向下取整
remainder = total_players % num_teams # 计算剩余的人数(余数)
teams = {}
for i in range(num_teams):
team_name = f"队伍{i+1}"
if i < remainder: # 分配余数
teams[team_name] = members[i * (players_per_team + 1): (i+1) * (players_per_team + 1)] # 每个余数都分配一个额外的成员
else:
teams[team_name] = members[i * players_per_team: (i+1) * players_per_team] # 每个队伍都有平均数量的成员
return teams
divide_teams函数是一个用于将成员分为多个团队的函数。
它接受一个成员列表和团队数作为参数,然后根据每个团队的平均人数和剩余人数(余数),将成员分配到每个团队中。
实现步骤如下:
获取成员总数:使用len()函数获得成员列表的长度,即总人数。计算每个队伍的平均人数:使用math.floor()函数将总人数除以团队数,取整数部分作为每个团队的平均人数。计算剩余的人数(余数):使用总人数对团队数取模运算,得到剩余的人数。创建一个空字典teams,用于存储团队名称和成员列表。使用for循环遍历每一个团队的编号(从0到num_teams-1):创建一个团队名称,形式为"队伍{i+1}",其中i是当前团队编号。如果当前团队编号小于剩余人数,即当前团队需要分配一个额外的成员:使用切片操作将成员列表中的第i * (players_per_team + 1)到(i+1) * (players_per_team + 1)个成员分配给当前团队。否则,即当前团队不需要分配额外的成员:使用切片操作将成员列表中的第i * players_per_team到(i+1) * players_per_team个成员分配给当前团队。将团队名称和成员列表添加到teams字典中。返回teams字典。
find_team积木
def find_team(team_json_str: str, my_name: str) -> Optional[str]:
# 将 JSON 字符串转换为字典对象
team_json = json.loads(team_json_str)
# 遍历字典team_json的键和值
for team, members in team_json.items():
# 检查my_name是否在成员列表members中
if my_name in members:
# 如果是,则返回对应的团队名称
return team
# 如果my_name不在任何团队的成员列表中,则返回None
return None
find_team函数用于寻找给定成员所在的团队。
它接受一个JSON格式的团队信息字符串和一个成员名字作为参数,然后将字符串转换为字典对象,并遍历字典中的键和值,检查给定成员是否在成员列表中。如果找到了匹配的成员,就返回对应的团队名称;如果没有找到匹配的成员,则返回None。
实现步骤如下:
将JSON字符串team_json_str转换为字典对象team_json,使用json.loads()函数实现。使用for循环遍历team_json字典的键和值:检查给定的my_name是否在成员列表members中。如果存在,说明给定成员所在的团队是当前的团队,就返回当前团队的名称。如果遍历完整个字典后仍然没有找到匹配的成员,则返回None。
countdown积木
def countdown(seconds: int) -> str:
# 将秒数转换为timedelta对象
remaining_time = timedelta(seconds=seconds)
# 获取剩余的分钟和秒数
minutes = remaining_time.seconds // 60
seconds = remaining_time.seconds % 60
# 返回剩余的分钟和秒数
return f"{minutes}:{seconds}"
countdown函数用于将给定的秒数转换为分钟和秒数格式的倒计时。
它接受一个整数型的秒数作为参数,然后将其转换为timedelta对象,用于方便地计算剩余的分钟和秒数。
实现步骤如下:
将seconds转换为timedelta对象remaining_time,使用timedelta()函数,并将参数seconds作为秒数传入。使用整除运算符//计算remaining_time的秒数除以60后的整数部分,得到剩余的分钟数。使用取模运算符%计算remaining_time的秒数除以60后的余数,得到剩余的秒数。返回格式为"分钟数:秒数"的字符串,使用f-string格式化字符串,将分钟数和秒数分别插入到字符串中。
导入所需要的库
我们在文件的最开始进行导入一下Python库
from typing import Dict, List, Optional
import math
import json
from datetime import timedelta
——————————————————
from typing import Dict, List, Optional这行代码导入了Python的typing模块,并从中导入了Dict、List和Optional等类型提示。
- Dict:用于声明键值对类型的字典,泛型参数分别表示键和值的类型。
- List:用于声明元素类型为列表的列表,泛型参数表示列表中元素的类型。
- Optional:用于声明可选类型,表示某个参数或返回值可以是指定类型的值,也可以是None。
import math这行代码导入了Python的math模块,该模块提供了数学运算相关的函数和常量。
- floor()函数:用于将一个浮点数向下取整,返回不大于该浮点数的最大整数。
import json这行代码导入了Python的json模块,该模块提供了处理JSON格式数据的函数和工具。
- loads()函数:用于将一个JSON格式的字符串解析为相应的Python字典或列表对象。
from datetime import timedelta:这行代码从Python的datetime模块中导入了timedelta类,该类用于表示时间间隔。
——————————————————
显式地指定要暴露给 Scratch 的方法
我们最后最重要的一步 将我们编写的积木给整到Scratch中
# 显式地指定要暴露给 Scratch 的方法
__all__ = [
'divide_teams',
'find_team',
'countdown'
]
我们将三个函数的名字输入进去就可以了!
好了!那么这样我们的Python in Gandi的部分就搞定了,怎么样?还是非常简单的吧~
然后让我们回到Scratch编辑器中:
编译生成一下积木~ 这样我们制作的Python积木就成功的出来了!
然后我们分别新建三个新的变量分别是“团战.分队” “团战.队伍” “团战.房间ID”
然后我们将分队变量设置为调用我们刚才写的Python积木对列表进行分队 我们这里为了方便测试先将队伍数量设置为1,然后我们将队伍变量设置为我们使用刚才写的另外一个py积木查询我们被分到了哪个队伍,最后我们就爱那个房间ID设置为我们四次元口袋扩展中的生成8位随时ID积木:
然后我们发起一个MMO广播来通知一下房间里的各位已经分好队了 并且将分队的信息以及房间ID也传输过去:
然后我们写一下接收并处理MMO广播的部分,当接收到新消息我们判断一下消息类型是否是我们需要的分队返回,如果是那么就将分队设置为广播内容json中的team,然后将队伍设置为查询自己ID所在的队伍,最后我们将房间ID设置为json中的roomid 并且将他转换为字符串 也就是去掉""符号,最后我们就爱那个等待返回参数变量设为1 代表我们成功的搞定了可以进入游戏了:
然后我们最后全部准备完后我们将加载提示设置为0 也就是隐藏一下提示 并且我们新建一个变量叫做加入类型 设置为“团战模式” 然后我们广播开始游戏并且隐藏自己:
然后我们来到主界面按钮这里 我们在无尽模式这里也添加一个这个加入类型的变量并且设置为无尽模式
然后我们回到贪吃蛇角色中:
我们来绘制一下其他两种颜色的造型~
然后我们回到贪吃蛇加入MMO房间的代码这里。
我们将代码修改为:
如果是无尽模式的话那么就跟之前一样,否则就是团战嘛 我们就把造型切换成队伍的编号*2,比如我们是“队伍3”那么队伍3按照伍进行分割取得第二项刚好能获取到3这个数字,然后3*2的话就是6了也正好对应我们第三个颜色的头部造型编号,然后就是加入服务器ID为房间ID的游戏室房间了。
不过这里我们要特殊处理一下:
首先因为我们刚匹配完肯定还在匹配房间中 所以我们要先退出一下房间并且等待退出完毕 我们的ID如果等于NaN的话那就证明我们已经退出成功了,然后我们换造型移动到MMO地图的随机位置并且等待1到3秒让玩家之前分开进入 最后我们连接一下MMO服务器就大功告成了~
然后我们要给MMO额外数据新添加一项同步数据 也就是我们的造型数据:
然后我们前往克隆体的代码中也同步更改一下
就像这样!
最后我们为了防止意外我们在这里添加一个判断是否是本体的积木:
这样我们就搞定了。
然后让我们来对排行榜的代码也魔改一下:
首先我们判断了一下 如果是团战模式的话那么就调用新方法 否则就调用之前的老方法。
原理也非常的简单,就是遍历整个MMO房间的玩家 然后根据每个玩家的造型来分辨队伍,然后将分数添加到对应的列表项中,这样就统计完成了~
然后我们顺道修复一下小地图显示其他人位置有概率不显示的BUG:
我们来到隔壁角色小地图 然后我们将G相机的设置文件夹不跟随摄像机的代码拖进当克隆体启动时里面一份这样就搞定了~
接下来我们新建一个新的角色叫做“团战倒计时”:
接下来让我们来编写一下显示时间的代码,首先我们先让他初始化一下 当绿旗被点击移动到x0y158的位置并且隐藏。
然后,当接收到开始游戏广播,并且如果是团战模式的话,我们先将虚像设为20。然后,我们新建了一个变量叫做"团战.时间",并将时间变量设置为时间计算扩展的当前时刻。随后,我们显示并移动到最前面。然后,我们初始化字体颜色和宽度,并设置为靠中心对齐。接下来,我们让它持续执行,直到(当前时间)距离((时间)过10分钟的时刻)的秒数小于1,也就是持续执行直到已经过去十分钟。
然后,我们需要使用我们刚才写的Python程序。我们每次循环都将文字设置为一个countdown((当前时间)距离((时间)过10分钟的时刻))
,让它帮助我们转换成"分钟数:秒数"的字符串供我们显示。最后,如果时间到了,我们将时间设为0:00,并广播一个新的广播,叫做"团战.时间到"。最后,为了方便起见,我直接停止了所有的脚本。各位可以根据自己的场景进行修改:
然后我们来到界面信息这里我们添加一个新的信息,当开始匹配就移动到左下角然后显示一个剩余时间和当前人数,这样我们就可以抛弃变量监视器来显示了:
好了!接下来该我们的重头戏了,那就是区分队友和敌人 都说了团战团战那总不可能碰到队友也会被击败。
那么首先我们来到贪吃蛇角色中的其他玩家身体代码这里,因为我们的击败判定就是在这里去制作的:
然后我们在判断这里添加一个判断,那就是判断一下是否是无尽模式,如果是无尽模式的话那么就执行老代码:
否则的话那么肯定就是要执行团战的判断代码了,那么这个判断其实是非常的简单 我们是不是只需要判断两个玩家额外数据中的造型编号是否相同不就完了?如果相同那么就代表是队友否则那么就是敌人 如果是敌人那么就还是按照之前的逻辑击败就可以了!
就像是这样!然后最后让我们来整一下团战模式的专属地图:
还记得我们第一课开头所讲的使用PS来绘制地图吗?没错!这个图就是用PS去绘制的。
然后我们如果是无尽模式那么就切换成无尽模式的造型 反之就是切换成团战模式就可以了:
最后我们是不是感觉这个地图的氛围好像没有那么的好看?诶这个时候我们就要来整最后一个东西了,那就是!
没错!我们来整一个团战的氛围滤镜来烘托氛围,首先我们创建一个新的角色。
然后我们这里使用了Scratch自带的渐变功能制作了一个透明的渐变效果:
然后我们让他当绿旗被点击移动到00为止并且隐藏 然后当开始团战模式的时候就显示出来:
好!这样我们全部都搞定了,诶等等 我们是不是忘记制作胜负显示了?哈哈哈差点给整忘了
首先我们创建一个新的角色叫做团战显示胜负,然后我们分别绘制一下红黄蓝队胜利的造型:
然后分别将名称也改为红黄蓝队:
然后我们一样的初始化一下,然后当接收到时间到广播后那么就移动到最前面,将造型切换成排行榜第一名名称的造型 最后我们显示就大功告成了!
好!不过我们还有一个小小小的BUG要修复,各位能猜得到是什么吗?
哈哈哈 那就是我们使用右键加速的时候会出现右键菜单非常烦人,那么解决这个的办法也是非常非常的简单
我们只需要刚开始的时候禁用一下鼠标右键菜单就可以了~
好了!那让我们最后完整的看一下效果吧!
终于!我们经过了九九八十一难 想必各位都能从中学到了不少的知识和技巧了~
这里在评论区里面小小的整一个小活动!各位可以将自己从本课程学到的知识点全部总结在评论区中跟大家分享出来!
当然也别忘了把你的作品发布出来!投稿到星球🪐 一起讨论关于 MMO 制作贪吃蛇的更多知识!
那我们下次再见!大家拜拜~
<iframe
width="100%"
height="800px"
scrolling="no"
src="https://www.ccw.site/embed?id=snake/mckuke/Lec5/02&type=comment"
title="贪吃蛇中级教程-第五课-第一节"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
scrolling="0"
></iframe>