2.6
This commit is contained in:
0
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/README.md
Normal file
0
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/README.md
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/1.png
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/1.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/2.gif
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/2.gif
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/3.gif
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/3.gif
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/4.png
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/4.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/5.gif
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/5.gif
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/6.gif
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/6.gif
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/7.gif
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/7.gif
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/8.png
LFS
Normal file
BIN
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/images/8.png
LFS
Normal file
Binary file not shown.
@@ -0,0 +1,119 @@
|
||||
---
|
||||
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
|
||||
hard: 进阶
|
||||
time: 30分钟
|
||||
---
|
||||
|
||||
# 使用MODSDK自定义NPC的聊天对话
|
||||
|
||||
新手引导是游戏中非常关键的“关卡”,玩家是否可以顺利上手最大程度的取决于新手引导,所以《海滨小岛》也同样需要制作一个简单的引导关卡;我们在出生的小岛设置一个家人NPC,我们可以与之对话并且完成他指定的任务:
|
||||
|
||||
提前获取到交互NPC的id作为条件并监听**PlayerAttackEntityEvent**事件
|
||||
|
||||
```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)
|
||||
# 提前获取到的NPCid
|
||||
self.guide_id = "-481036336358"
|
||||
# 创建一个控制对话阶段的变量
|
||||
self.guide_dialogue = {}
|
||||
|
||||
# 事件触发的函数
|
||||
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 == {}:
|
||||
# 使用指令的接口,生成对话和音效
|
||||
commandcomp.SetCommand(
|
||||
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f塔塔村落是一个坐落在深山里的村庄, '成为一个更独立的人' 是村子悠久的传承。 §6[1/6]\"}]}")
|
||||
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
|
||||
# 给变量一个新的参数用于控制进入下一个对话阶段
|
||||
self.guide_dialogue["dialogue"] = 0
|
||||
# 存储新的player_guide
|
||||
leveldatacomp.SetExtraData('player_guide', self.guide_dialogue)
|
||||
```
|
||||
|
||||
现在,当我们点击这个NPC的时候就可以触发对话了:
|
||||
|
||||

|
||||
|
||||
接下来把所有的对话补齐,也是利用变量和数据的读写控制对话阶段:
|
||||
|
||||
```python
|
||||
leveldatacomp = serverApi.GetEngineCompFactory().CreateExtraData(serverApi.GetLevelId())
|
||||
class FarmServerSystem(ServerSystem):
|
||||
def __init__(self, namespace, systemName):
|
||||
ServerSystem.__init__(self, namespace, systemName)
|
||||
#···
|
||||
|
||||
def PlayerAttack(self, args):
|
||||
#···
|
||||
# 如果self.guide_dialogue={}(说明第一次点击这个NPC)
|
||||
if self.guide_dialogue == {}:
|
||||
# 使用指令的接口,生成对话和音效
|
||||
commandcomp.SetCommand("execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f塔塔村落是一个坐落在深山里的村庄, '成为一个更独立的人' 是村子悠久的传承。 §6[1/6]\"}]}")
|
||||
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
|
||||
# 给变量一个新的参数用于控制进入下一个对话阶段
|
||||
self.guide_dialogue["dialogue"] = 0
|
||||
|
||||
elif self.guide_dialogue["dialogue"] == 0:
|
||||
commandcomp.SetCommand(
|
||||
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f每年村庄都会为即将成年的年轻人举办一次成年礼考核,今年留给你的考核就是 §6[2/6]\"}]}")
|
||||
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
|
||||
self.guide_dialogue["dialogue"] = 1
|
||||
|
||||
elif self.guide_dialogue["dialogue"] == 1:
|
||||
commandcomp.SetCommand(
|
||||
"execute @a ~ ~ ~ tellraw @a {\"rawtext\":[{\"text\":\" §6§l【家人】 §r§f为村庄在乌龟岛上开辟一个海滨农场,作为之后村民度假的旅游点!§6[3/6]\"}]}")
|
||||
commandcomp.SetCommand("execute @a ~ ~ ~ /playsound random.orb @a ~ ~ ~ 3 1 3")
|
||||
self.guide_dialogue["dialogue"] = 2
|
||||
|
||||
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
|
||||
# 存储新的player_guide
|
||||
leveldatacomp.SetExtraData('player_guide', self.guide_dialogue)
|
||||
```
|
||||
|
||||
<img src="./images/2.gif" alt="2" style="zoom:115%;" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
231
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/课程02.实现资源收集和玩法规则的小游戏.md
Normal file
231
docs/mconline/20-玩法地图教程/第08章:在开头添加引导关卡/课程02.实现资源收集和玩法规则的小游戏.md
Normal file
@@ -0,0 +1,231 @@
|
||||
---
|
||||
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%;" />
|
||||
|
||||
继续添加引导任务,让玩家在收集圆石后点击牌子可以改造小池塘并完成引导;
|
||||
|
||||
在此之前,我们需要先制作改造后的建筑然后使用结构方块将其保存起来:
|
||||
|
||||

|
||||
|
||||
```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%;" />
|
||||
|
||||
完成引导后,现在还无法离开新手岛屿,所以我们需要进一步制作使玩家可以离开这里前往新的小岛。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
---
|
||||
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
|
||||
hard: 进阶
|
||||
time: 40分钟
|
||||
---
|
||||
|
||||
# 制作小船带玩家离开新手岛
|
||||
|
||||
完成新手引导后,玩家需要乘船离开岛屿,先制作一个小船使其可以漂浮在水上并且具有寻路的组件:
|
||||
|
||||
```json
|
||||
{
|
||||
"format_version":"1.16.0",
|
||||
"minecraft:entity":{
|
||||
"description":{
|
||||
"identifier":"farm:guide_boat",
|
||||
"is_spawnable":true,
|
||||
"is_summonable":true,
|
||||
"is_experimental":false
|
||||
},
|
||||
"components": {
|
||||
"minecraft:buoyant": { //使实体可以像船一样漂浮在水面上
|
||||
"apply_gravity": true,
|
||||
"base_buoyancy": 1.0,
|
||||
"simulate_waves": true,
|
||||
"big_wave_probability": 0.03,
|
||||
"big_wave_speed": 10.0,
|
||||
"drag_down_on_buoyancy_removed": 0,
|
||||
"liquid_blocks": ["water"]
|
||||
},
|
||||
|
||||
"minecraft:underwater_movement": { //水中的移动速度
|
||||
"value": 0.25
|
||||
},
|
||||
"minecraft:navigation.walk": { //寻路组件(不会沉底)
|
||||
"can_sink": false
|
||||
},
|
||||
"minecraft:rideable": { //玩家可以骑乘实体
|
||||
"seat_count": 1,
|
||||
"family_types": ["player"],
|
||||
"interact_text": "action.interact.enter_boat",
|
||||
"seats": {
|
||||
"position": [0, 0.5, 0]
|
||||
}
|
||||
},
|
||||
|
||||
"minecraft:follow_range": {
|
||||
"value": 64,
|
||||
"max": 64
|
||||
},
|
||||
"minecraft:health": {
|
||||
"value": 10,
|
||||
"max": 10
|
||||
},
|
||||
"minecraft:movement": {
|
||||
"value": 0.25
|
||||
},
|
||||
"minecraft:movement.basic": {},
|
||||
"minecraft:collision_box": {
|
||||
"width": 1,
|
||||
"height": 1
|
||||
},
|
||||
"minecraft:physics": {}
|
||||
},
|
||||
"component_groups":{
|
||||
"boat_finding":{ //通过py添加的组件组,使船可以寻找特定的方块并移动至方块位置
|
||||
"minecraft:behavior.move_to_block": {
|
||||
"priority": 0,
|
||||
"tick_interval": 1,
|
||||
"start_chance": 1.0,
|
||||
"search_range": 64,
|
||||
"search_height": 10,
|
||||
"goal_radius": 1.0,
|
||||
"stay_duration": 999.0,
|
||||
"target_selection_method": "nearest",
|
||||
"target_offset": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"target_blocks": [ //寻找的方块
|
||||
"minecraft:double_wooden_slab:1"
|
||||
],
|
||||
"on_reach": [ //到达附近触发的事件
|
||||
{
|
||||
"event": "reach_boat",
|
||||
"target": "self"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
"events":{
|
||||
"start_boat":{ //添加组件组的事件
|
||||
"add":{
|
||||
"component_groups":["boat_finding"]
|
||||
}
|
||||
},
|
||||
"reach_boat":{ //船到达目的地触发的事件,py将监听此事件
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在"minecraft:behavior.move_to_block"中,设置小船寻找的方块为**"minecraft:double_wooden_slab:1"**,这个方块是双层的云杉木半砖,所以我们需要对地图做一些简单的修改,将码头最外侧的一个云杉木板改为双层云杉木半砖,外观上完全一致,并且可以让小船寻找这个方块前往码头:
|
||||
|
||||
<img src="./images/6.gif" alt="6" style="zoom:115%;" />
|
||||
|
||||
玩家完成引导任务后会创建船的实体,需要使用py检测玩家坐上船后触发船的组件并且监听船到达目的地的事件:
|
||||
|
||||
```python
|
||||
leveldatacomp = serverApi.GetEngineCompFactory().CreateExtraData(serverApi.GetLevelId())
|
||||
timecomp = serverApi.GetEngineCompFactory().CreateTime(serverApi.GetLevelId())
|
||||
class FarmServerSystem(ServerSystem):
|
||||
def __init__(self, namespace, systemName):
|
||||
ServerSystem.__init__(self, namespace, systemName)
|
||||
# 监听EntityStartRidingEvent事件
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
|
||||
"EntityStartRidingEvent", self, self.Start_Gam
|
||||
)
|
||||
# 监听EntityDefinitionsEventServerEvent事件
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(),
|
||||
'EntityDefinitionsEventServerEvent',
|
||||
self, self.EntityEvent)
|
||||
# ···
|
||||
|
||||
def Start_Game(self, args):
|
||||
# 通过事件获取玩家id和船的id
|
||||
self.start_playerid = args["id"]
|
||||
boatid = args["rideId"]
|
||||
# 获取数据player_guide
|
||||
self.guide_dialogue = leveldatacomp.GetExtraData("player_guide")
|
||||
# 如果guide_dialogue的dialogue值等于5(说明玩家已经完成新手引导)
|
||||
if self.guide_dialogue等于5["dialogue"] == 5:
|
||||
# 创建触发实体事件的组件
|
||||
entityeventcomp = serverApi.GetEngineCompFactory().CreateEntityEvent(boatid)
|
||||
# 触发小船的"start_boat"事件
|
||||
result = entityeventcomp.TriggerCustomEvent(boatid, "start_boat")
|
||||
|
||||
def EntityEvent(self,args):
|
||||
# 获取的实体触发的事件名
|
||||
eventname = args['eventName']
|
||||
# 如果事件名不是"reach_boat"就返回
|
||||
if eventname != "reach_boat":
|
||||
return
|
||||
# 获取被骑乘者(船)的id
|
||||
entityid = args['entityId']
|
||||
# 获取乘船玩家的id
|
||||
rider_id = serverApi.GetEngineCompFactory().CreateRide(entityid).GetEntityRider()
|
||||
# 执行创建数据的函数,并将玩家id作为参数
|
||||
self.start_game_data(rider_id)
|
||||
# 创建传送玩家的接口
|
||||
playertpcomp = serverApi.GetEngineCompFactory().CreatePos(self.start_playerid)
|
||||
# 传送玩家到坐标位置
|
||||
playertpcomp.SetPos((55, 63, 131))
|
||||
# 销毁船
|
||||
self.DestroyEntity(entityid)
|
||||
# 重置世界时间为0
|
||||
timecomp.SetTime(0)
|
||||
|
||||
# 新手引导结束,开始游戏触发的函数
|
||||
def start_game_data(self, playerid):
|
||||
# 设置初始数据:玩家钱数为100
|
||||
leveldatacomp.SetExtraData("player_coin", 100)
|
||||
# 设置初始数据:玩家家具为0
|
||||
leveldatacomp.SetExtraData("player_furniture", 0)
|
||||
# 将初始数据存放在event变量中并发送事件到客户端创建数据ui
|
||||
event = {"playerid": playerid, "player_data_coin": leveldatacomp.GetExtraData("player_coin"),
|
||||
"player_data_furniture": leveldatacomp.GetExtraData("player_furniture")}
|
||||
self.NotifyToClient(self.playername, "create_data_ui", event)
|
||||
|
||||
```
|
||||
|
||||
<img src="./images/7.gif" alt="7" style="zoom:115%;" />
|
||||
|
||||
现在,《海滨小岛》已经有了一个完整的新手引导,玩家在乘船登上新岛屿后就可以开始正常的游戏了,当然我们也可以继续添加引导使玩家对玩法更加清晰,比如在图书馆里放置一个指引书供玩家阅览。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user