Files
netease-bedrock-wiki/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/课程02.实现资源收集和玩法规则的小游戏.md
2025-08-25 18:36:29 +08:00

232 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
hard: 进阶
time: 50分钟
---
# 在对话聊天过程中添加玩法引导
如果引导只有对话聊天,过程会显得枯燥乏味,而且并不能很好的“引导”玩家,甚至部分玩家根本就不会看对话,所以我们需要在对话中穿插需要去实际操作的玩法,才能让玩家循序渐进,了解地图的内容。
在对话4/6中给予玩家植物的种子并且指定玩家种植在耕地上
```python
leveldatacomp = serverApi.GetEngineCompFactory().CreateExtraData(serverApi.GetLevelId())
class FarmServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
# 监听PlayerAttackEntityEvent事件
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "PlayerAttackEntityEvent",
self, self.PlayerAttack)
# 监听ItemUseOnAfterServerEvent事件
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
"ItemUseOnAfterServerEvent", self, self.Item_Use)
# 提前获取到的NPCid
self.guide_id = "-481036336358"
# 创建一个控制对话阶段的变量
self.guide_dialogue = {}
# 存储物品的变量
self.guide_itemDict = [
{
'name': 'minecraft:farmland',
'aux': 0
},
{
'itemName': 'farm:spinach_seed',
'count': 1,
'enchantData': '',
'auxValue': 0,
'customTips': '',
'extraId': '',
'userData': {},
}
]
# 事件触发的函数
def PlayerAttack(self, args):
# 事件获取的玩家id
self.playername = args["playerId"]
# 创建指令、方块和物品的接口
commandcomp = serverApi.GetEngineCompFactory().CreateCommand(serverApi.GetLevelId())
blockcomp = serverApi.GetEngineCompFactory().CreateBlockInfo(serverApi.GetLevelId())
itemcomp = serverApi.GetEngineCompFactory().CreateItem(self.playername)
# 事件获取的生物id
entityid = args["victimId"]
# 如果事件获取的生物id和提前获取的NPCid一致
if entityid == self.guide_id:
# 获取 player_guide 数据
guide_data = leveldatacomp.GetExtraData('player_guide')
# 如果没有此数据则设置一个
if not guide_data:
leveldatacomp.SetExtraData('player_guide', self.guide_dialogue)
else:
# 如果有就把guide_data传给self.guide_dialogue
self.guide_dialogue = guide_data
# 如果self.guide_dialogue={}说明第一次点击这个NPC
if self.guide_dialogue == {}:
# ···
elif self.guide_dialogue["dialogue"] == 0:
# ···
elif self.guide_dialogue["dialogue"] == 1:
# ···
elif self.guide_dialogue["dialogue"] == 2:
commandcomp.SetCommand(
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f为了让你适应我先带你熟悉一下海滨农场的生活去试试种下植物吧。§6[4/6]\"}]}")
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
self.guide_dialogue["dialogue"] = 3
# 设置坐标处为耕地self.guide_itemDict变量的第一个
blockcomp.SetBlockNew((14, 64, 188), self.guide_itemDict[0], 0, 0)
# 生成粒子在坐标处
commandcomp.SetCommand("particle minecraft:villager_happy 14 66 188")
# 给予玩家物品self.guide_itemDict变量的第二个
itemcomp.SpawnItemToPlayerInv(self.guide_itemDict[1], self.playername, )
# 存储新的player_guide
leveldatacomp.SetExtraData('player_guide', self.guide_dialogue)
# 玩家在对方块使用物品时触发
def Item_Use(self, args):
# 创建指令接口
commandcomp = serverApi.GetEngineCompFactory().CreateCommand(serverApi.GetLevelId())
# 通过事件获取方块的坐标、名称、玩家id和世界id
x = args['x']
y = args['y']
z = args['z']
blockname = args['blockName']
playerid = args['entityId']
worldid = args['dimensionId']
# 创建方块信息、世界接口
blockinfocomp = serverApi.GetEngineCompFactory().CreateBlockInfo(playerid)
gamecomp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
# 如果方块名称是耕地并且坐标在设定的位置(说明玩家完成了种植的引导任务)
if blockname == "minecraft:farmland" and (x, y, z) == (14, 64, 188):
# 卸载监听
self.UnListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
"ItemUseOnAfterServerEvent", self, self.Item_Use)
# 对话
commandcomp.SetCommand(
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f接下来试试改造建筑去旁边的资源处挖一些石头吧。§6[5/6]\"}]}")
# 音效
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
# 给予玩家一把可以破坏石头的石镐(下一个引导任务的道具)
commandcomp.SetCommand("/give @s stone_pickaxe 1 0 {\"minecraft:can_destroy\": {\"blocks\":[\"stone\"]}} ")
# 生成一个结构(下一个引导任务的资源)
gamecomp.PlaceStructure(None, (14, 65, 202), "design:resource", 0)
# 生成一个告示牌
commandcomp.SetCommand("setblock 13 65 186 standing_sign 12")
# 修改告示牌的文字
blockinfocomp.SetSignBlockText((13, 65, 186), " 点击升级小湖泊 圆石x1")
# 生成粒子
commandcomp.SetCommand("particle minecraft:villager_happy 13 67 186")
# 修改变量
self.guide_dialogue["dialogue"] = 4
```
添加引导任务后,玩家在对话的过程中就会接收这个”任务“:
<img src="./images/3.gif" alt="3" style="zoom:115%;" />
继续添加引导任务,让玩家在收集圆石后点击牌子可以改造小池塘并完成引导;
在此之前,我们需要先制作改造后的建筑然后使用结构方块将其保存起来:
![4](./images/4.png)
```python
leveldatacomp = serverApi.GetEngineCompFactory().CreateExtraData(serverApi.GetLevelId())
class FarmServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
# 监听PlayerAttackEntityEvent事件
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "PlayerAttackEntityEvent",
self, self.PlayerAttack)
# 监听ItemUseOnAfterServerEvent事件
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
"ItemUseOnAfterServerEvent", self, self.Item_Use)
# 监听ServerBlockUseEvent事件
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), 'ServerBlockUseEvent',
self, self.Upgrade)
#···
def PlayerAttack(self, args):
#···
def Item_Use(self, args):
#···
# 玩家点击方块触发的函数
def Upgrade(self, args):
# 存储需要的物品的变量
stone_block = {"minecraft:cobblestone": 1}
# 事件获取的方块名称和玩家id
blockname = args['blockName']
playerid = args['playerId']
# 创建逻辑需要用到的相关接口
blockinfocomp = serverApi.GetEngineCompFactory().CreateBlockInfo(playerid)
commandcomp = serverApi.GetEngineCompFactory().CreateCommand(serverApi.GetLevelId())
gamecomp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
# 如果点击的方块是告示牌
if blockname == "minecraft:standing_sign":
# 获取告示牌的文字
text = blockinfocomp.GetSignBlockText((13, 65, 186))
# 如果文字一致
if " 点击升级小湖泊 圆石x1" in text:
# 获取玩家背包物品
item_comp = serverApi.GetEngineCompFactory().CreateItem(playerid)
item_dict_list = item_comp.GetPlayerAllItems(serverApi.GetMinecraftEnum().ItemPosType.INVENTORY)
# 根据槽位依次循坏玩家背包
for index, item_dict in enumerate(item_dict_list):
# 如果是空的就继续下一次循环
if item_dict is None:
continue
# 如果是物品信息字典的物品名在变量中
if item_dict["newItemName"] in stone_block:
# 获取需要的物品数量
item_count = item_dict["count"]
# 将该槽位的物品数量-1
item_comp.SetInvItemNum(index, item_count - 1)
# 替换告示牌为空气
commandcomp.SetCommand("setblock 13 65 186 air")
# 在坐标位置放置结构
gamecomp.PlaceStructure(None, (5, 63, 186), "farm:rockery", 0)
# 对话
commandcomp.SetCommand(
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f很棒接下来乘船去岛上找图书馆管理员吧他会帮你的。§6[6/6]\"}]}")
# 在小岛码头旁生成小船
self.CreateEngineEntityByTypeStr("farm:guide_boat",(35,62,168),(0,0),0)
# 音效
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
# 存储完成引导的玩家id
leveldatacomp.SetExtraData("player_id", playerid)
# 更新控制对话阶段的变量
self.guide_dialogue["dialogue"] = 5
# 卸载本事件的监听
self.UnListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
'ServerBlockUseEvent', self, self.Upgrade)
# 存储新的player_guide
leveldatacomp.SetExtraData('player_guide', self.guide_dialogue)
break
```
至此,较完整的新手引导关卡就制作完成了:
<img src="./images/5.gif" alt="5" style="zoom:115%;" />
完成引导后,现在还无法离开新手岛屿,所以我们需要进一步制作使玩家可以离开这里前往新的小岛。