first commit

This commit is contained in:
boybook
2025-03-17 13:24:39 +08:00
commit 9a0334ee84
6410 changed files with 221907 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 MiB

View File

@@ -0,0 +1,464 @@
---
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
hard: 进阶
time: 30分钟
---
# 开始接触新自定义方块
打开MCStudio使用关卡编辑器就可以直接新建一个自定义方块非常的方便但是我们打开文件可以看到方块的行为放在**netease_blocks**文件夹内这里主要存放中国版特色的自定义方块随着版本的更新原版Add-on的自定义方块也可以实现很多有趣的功能所以本章将全面展开介绍新自定义方块的概念的用法并制作地图的农作物、家具。
[认识自定义方块](../../10-addon教程/第09章自定义方块/课程01.认识自定义方块.md)
![1](./images/1.png)
中国版特色的自定义方块存放在netease_blocks文件夹内而1.16+的新自定义方块写法需要放在微软的blocks文件夹内。
<img src="./images/2.png" alt="2" style="zoom:120%;" />
## 什么是方块属性
方块属性是1.16版本后新写法的“特色”之一:**properties**,里面可以存放很多属性,其实属性就是数组,用于引擎判断,利用方块属性可以做的很多有趣的功能,比如将方块做成农作物并判断其生长年龄;图中的**farm:age**和**farm:growth**就是判断农作物的。
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": { //方块属性
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5]
}
},
"permutations": [···],
"events": {···},
"components": {···}
}
}
```
使用**query.block_property**可以获取方块的属性值
```json
"query.block_property('farm:age') == 0"
```
## 什么是方块事件
想要灵活的修改方块的行为,需要事件的配合:**events**。比如当玩家站在方块上的时候,修改方块的掉落物;我们就需要在方块的组件里添加**触发器**并且在events内添加响应的事件。
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:my_block"
},
"components": { //方块组件
"minecraft:on_step_on": { //触发器,当站在方块上的时候
"event": "farm:drop_loot", //触发此事件
"target": "self"
}
},
"events": { //方块事件
"farm:drop_loot": { //上方触发器触发的事件
"spawn_loot": { //添加方块的掉落物
"table": "loot_tables/blocks/my_loot_table.json"
}
}
}
}
}
```
## 什么是方块组合
方块组合可以根据不同的条件应用于具有MoLang表达式的方法可以非常自由的调配方块的各种组件实现很多功能图中的组合分别添加了不同的MoLang表达式条件就是当方块属性的**farm:age**为特定值的时候,将下方**components**里的组件加到这个方块中。
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": {···}
},
"permutations": [ //方块组合
{
"condition": "query.block_property('farm:age') == 0",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 1",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 2",
"components": {···}
}
],
"events":{···},
"components":{···}
}
}
```
## 什么是方块标签
方块标签可以将不同的方块分组归类,并通过标签获取使用;我将**"tag:farm_plant"**这个标签添加到不同的方块上,当我想要在其它文件中使用或查询的时候,就可以应用这个标签。
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5]
}
},
"permutations": [···],
"components": {
"tag:farm_plant":{} //方块标签
},
"events": {···}
}
}
```
可以获取方块标签的表达式:
- query.all_tags
- query.any_tag
- query.block_has_all_tags
- query.block_has_any_tag
- query.relative_block_has_all_tags
- query.relative_block_has_any_tag
## 新增了哪些方块组件
### minecraft:unit_cube
设定方块为普通的立方体
```json
{
"minecraft:unit_cube": {}
}
```
### minecraft:crafting_table
设定方块为工作台
```json
{
"minecraft:crafting_table": {
"custom_description": "Example Crafting Table", // Name shown in GUI
"grid_size": 3, // Currently only supports 3
"crafting_tags": ["crafting_table", "custom_crafting_tag"]
}
}
```
### minecraft:material_instances
方块的材质贴图和渲染方式
```json
{
"minecraft:material_instances": {
"*": {
"texture": "texture_name",
"render_method": "blend",
"face_dimming": true,
"ambient_occlusion": true
}
}
}
```
### minecraft:geometry
方块模型
```json
{
"minecraft:geometry": "geometry.wiki"
}
```
### minecraft:on_step_on
触发器,配合事件使用:站在方块上时
```json
{
"minecraft:on_step_on": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:on_step_off
触发器,配合事件使用:离开方块上时
```json
{
"minecraft:on_step_off": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:on_fall_on
触发器,配合事件使用:方块坠落时
```json
{
"minecraft:on_fall_on": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true",
"min_fall_distance": 5
}
}
```
### minecraft:on_placed
触发器,配合事件使用:方块被放置时
```json
{
"minecraft:on_placed": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:on_player_placing
触发器,配合事件使用:玩家放置方块时
```json
{
"minecraft:on_player_placing": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:on_player_destroyed
触发器,配合事件使用:玩家破坏方块时
```json
{
"minecraft:on_player_destroyed": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:on_interact
触发器,配合事件使用:玩家与方块交互时
```json
{
"minecraft:on_interact": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
```
### minecraft:ticking
触发器,配合事件使用:设置特定值的刻
```json
{
"minecraft:ticking": {
"looping": true,
"range": [4, 4],
"on_tick": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
}
```
### minecraft:random_ticking
触发器,配合事件使用:设置随机刻
```json
{
"minecraft:random_ticking": {
"on_tick": {
"event": "block_event",
"target": "self",
"condition": "query.block_property('wiki:block_property') == true"
}
}
}
```
### minecraft:entity_collision
方块实体的碰撞箱
```json
{
"minecraft:entity_collision": {
"origin": [-8, 0, -8],
"size": [16, 16, 16]
}
}
```
```json
{
"minecraft:entity_collision": false
}
```
### minecraft:pick_collision
选择方块时的碰撞箱
```json
{
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 16, 16]
}
}
```
```json
{
"minecraft:pick_collision": false
}
```
### minecraft:breakonpush
设定被活塞推动时会破碎
```json
{
"minecraft:breakonpush": true
}
```
### minecraft:display_name
设定方块名称
```json
{
"minecraft:display_name": "Name"
}
```
### minecraft:breathability
设定方块的透气性,作为固体或是空气
```json
{
"minecraft:breathability": "solid" // Also accepts 'air'
}
```
### minecraft:immovable
设定能否被活塞推动
```json
{
"minecraft:immovable": true
}
```
### minecraft:onlypistonpush
设定方块是否会跟随粘性活塞移动
```json
{
"minecraft:onlypistonpush": true
}
```
### minecraft:placement_filter
设定方块在什么条件下可以放置
```json
{
"minecraft:placement_filter": {
"conditions": [
{
"block_filter": ["minecraft:dirt"],
"allowed_faces": ["up"]
}
]
}
}
```
### minecraft:preventsjumping
设定踩在方块上时是否可以跳跃
```json
{
"minecraft:preventsjumping": true
}
```
### minecraft:rotation
设定方块的旋转角度
```json
{
"minecraft:rotation": [90, 180, 0]
}
```
### minecraft:unwalkable
设定踩在方块上时是否可以行走
```json
{
"minecraft:unwalkable": true
}
```

View File

@@ -0,0 +1,455 @@
---
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
hard: 进阶
time: 40分钟
---
# 开始添加作物方块
基本了解新的自定义方块写法后,我们开始制作地图中需要的农作物:
- 农作物有多个生长状态,并且模型和贴图会随着成长而变化
- 部分农作物可收获多次
- 特殊农作物需要种植在篱笆上
![7](./images/7.png)
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=6152ba9148e27490891f035c" height="600" width="800" allow="fullscreen" />
## 设定农作物不同阶段的生长状态
首先,我们给自定义方块添加基本的行为组件,使其可以在游戏中正常显示出来;
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true
},
"permutations": [
],
"events": {
},
"components": {
"minecraft:placement_filter": { //可以放在耕地上
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland"]
}
]
},
"minecraft:entity_collision": false, //关闭生物碰撞箱
"minecraft:pick_collision": { //设定选择时的碰撞箱
"origin": [-8, 0, -8],
"size": [16, 5, 16]
},
"minecraft:geometry": "geometry.whiteradish_stage_0", //方块模型
"minecraft:material_instances": { //方块的贴图和渲染方法
"*": {
"texture": "farm:whiteradish_stage_0",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
}
```
![9](./images/9.gif)
接下来,我们为其添加方块属性,并且利用触发器、事件和组合设定在不同属性的情况下,方块也会有明显的变化;
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2] //设定农作物共有三个生长阶段
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 0", //组合的条件表达式当方块属性farm:age等于0时
"components": { //满足上方的条件,将下方组件添加到方块中
"minecraft:loot": "loot_tables/empty.json",
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 5, 16]
},
"minecraft:geometry": "geometry.whiteradish_stage_0",
"minecraft:block_light_absorption": 0,
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_0",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"components": {
"minecraft:placement_filter": {
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland"]
}
]
},
"minecraft:entity_collision": false,
"minecraft:on_player_placing": { //触发器,玩家放置方块时触发事件
"event": "farm:on_player_placing",
"target": "self"
}
},
"events": {
"farm:on_player_placing": { //当玩家放置方块时触发此事件设定方块的生长阶段为0
"set_block_property": {
"farm:age": 0
}
}
}
}
}
```
根据上方图片可以看出,主要分为四个部分,属性、组合、基础组件、事件;这四个部分相互调配,非常灵活;
再添加一个属性,控制农作物的生长刻数,组合中添加随机刻的触发器,使方块可以根据随机刻触发事件,达到农作物生长的目的;
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5] //生长刻数,每次随机刻触发时都会+1
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 0",
"components": {
"minecraft:loot": "loot_tables/empty.json",
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 5, 16]
},
"minecraft:random_ticking": { //添加随机刻的触发器,触发下方事件
"on_tick": {
"target": "self",
"event": "farm:on_age_count_0" //触发的事件
}
},
"minecraft:geometry": "geometry.whiteradish_stage_0",
"minecraft:block_light_absorption": 0,
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_0",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"components": {···},
"events": {
"farm:on_age_count_0": { //上方添加的随机刻触发器触发时,响应此事件
"sequence": [
{
"condition": "query.block_property('farm:growth') < 2", //条件当farm:growth属性小于2时
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1" //设定方块的属性farm:growth加1
}
},
{
"condition": "query.block_property('farm:growth') == 2", //条件当farm:growth属性等于2时
"trigger": {
"event": "farm:on_whiteradish_grow_to_1", //触发新的事件
"target": "self"
}
}
]
},
"farm:on_whiteradish_grow_to_1": { //当farm:growth属性等于2时触发的事件说明此时随机刻已经触发了3次
"set_block_property": {
"farm:age": 1, //设定方块的属性farm:age为1成长到新的阶段
"farm:growth": 0 //设定方块的属性farm:growth为0重置随机刻
}
},
"farm:on_player_placing": {
"set_block_property": {
"farm:age": 0
}
}
}
}
}
```
农作物的生长阶段到1后条件是farm:age等于0的组合就失效了所以我们需要添加新的组合表示农作物的新阶段并且需要在组合中修改模型和贴图使农作物在到达新阶段时有所变化
```json
{
"condition": "query.block_property('farm:age') == 1", //新添加的组合条件是农作物的生长阶段等于1时
"components": {
"minecraft:loot": "loot_tables/empty.json",
"minecraft:geometry": "geometry.whiteradish_stage_0", //若有不同的模型需要修改
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 8, 16]
},
"minecraft:random_ticking": { //因为农作物还没有完全成熟,所以仍需要随机刻的触发器
"on_tick": {
"target": "self",
"event": "farm:on_age_count_1"
}
},
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_1", //若有不同的贴图需要修改
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
```
现在,农作物方块已经可以生长了,我们在编辑器中点击**开发测试**进入到游戏中测试一下。
![14](./images/14.gif)
成长阶段像0到1一样继续添加从1-2的组合和事件这样一个较完整的农作物方块就完成了
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:whiteradish",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5]
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 0",
"components": {
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 5, 16]
},
"minecraft:random_ticking": {
"on_tick": {
"target": "self",
"event": "farm:on_age_count_0"
}
},
"minecraft:geometry": "geometry.whiteradish_stage_0",
"minecraft:block_light_absorption": 0,
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_0",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
},
{
"condition": "query.block_property('farm:age') == 1",
"components": {
"minecraft:geometry": "geometry.whiteradish_stage_0",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 8, 16]
},
"minecraft:random_ticking": {
"on_tick": {
"target": "self",
"event": "farm:on_age_count_1"
}
},
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_1",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
},
{
"condition": "query.block_property('farm:age') == 2",
"components": {
"minecraft:geometry": "geometry.whiteradish_stage_2",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 12, 16]
},
"minecraft:on_player_destroyed": {
"event": "farm:on_destroy_stage_2"
},
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_2",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"events": {
"farm:on_age_count_0": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 2",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 2",
"trigger": {
"event": "farm:on_whiteradish_grow_to_1",
"target": "self"
}
}
]
},
"farm:on_age_count_1": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 5",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 5",
"trigger": {
"event": "farm:on_whiteradish_grow_to_2",
"target": "self"
}
}
]
},
"farm:on_player_placing": {
"set_block_property": {
"farm:age": 0,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_1": {
"set_block_property": {
"farm:age": 1,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_2": {
"set_block_property": {
"farm:age": 2,
"farm:growth": 0
}
}
},
"components": {
"minecraft:placement_filter": {
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland"]
}
]
},
"minecraft:entity_collision": false,
"minecraft:on_player_placing": {
"event": "farm:on_player_placing",
"target": "self"
}
}
}
}
```
![15](./images/15.gif)
## 继续完善农作物方块
现在,我们已经有了农作物方块,不过还不够完整,没有农作物对应的果实和种下农作物需要的种子,我们来添加这些;
首先是种子,创建一个自定义物品,添加一个放置方块的组件即可。
```json
{
"format_version": "1.16.100",
"minecraft:item": {
"description": {
"identifier": "farm:whiteradish_seed",
"category": "items"
},
"components": {
"minecraft:icon": {
"texture": "farm:whiteradish_seed"
},
"minecraft:ignores_permission": true,
"minecraft:block_placer": { //设定此物品可以放置方块
"block": "farm:whiteradish",
"use_block_description": true
}
}
}
}
```
农作物的掉落物也很简单,只需要在农作物成熟的组合中添加一个掉落物表即可!
```json
{
"condition": "query.block_property('farm:age') == 2",
"components": {
"minecraft:loot": "loot_tables/whiteradish.json", //掉落物表路径
"minecraft:geometry": "geometry.whiteradish_stage_2",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 12, 16]
},
"minecraft:on_player_destroyed": {
"event": "farm:on_destroy_stage_2"
},
"minecraft:material_instances": {
"*": {
"texture": "farm:whiteradish_stage_2",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
```
<img src="./images/17.gif" alt="17" style="zoom:115%;" />

View File

@@ -0,0 +1,713 @@
---
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
hard: 进阶
time: 60分钟
---
# 继续添加其它的农作物方块
上一节中,我们已经完整的制作了白萝卜这一种农作物,接下来我们将把剩余的其它农作物也都添加进来;当然,不同的农作物有不同的生长时间和环境,需要在制作的过程中做出不同程度的修改,首先是与白萝卜相似的以下几种农作物,我们只需要在方块属性中修改生长所需的刻数,就能做到农作物生长时间的把不同。
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:eggplant", //茄子
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //为growth属性添加更多的刻数
}
},
"permutations": [···],
"components": {···},
"events": {
"farm:on_age_count_0": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 7", //事件的条件也要修改当farm:growth小于7时
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1" //为farm:growth加1
}
},
{
"condition": "query.block_property('farm:growth') == 7", //当farm:growth等于7时
"trigger": {
"event": "farm:on_whiteradish_grow_to_1", //触发新的事件使其生长
"target": "self"
}
}
]
},
"farm:on_age_count_1": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 9",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 9",
"trigger": {
"event": "farm:on_whiteradish_grow_to_2",
"target": "self"
}
}
]
},
"farm:on_player_placing": {
"set_block_property": {
"farm:age": 0,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_1": {
"set_block_property": {
"farm:age": 1,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_2": {
"set_block_property": {
"farm:age": 2,
"farm:growth": 0
}
}
}
}
}
```
利用这种方法,我们依次将其它农作物也进行修改:
| 农作物名称 | 生长时间 |
| ---------- | -------------------------------------------------- |
| 白萝卜 | 随机刻3次进入发芽阶段 随机刻6次进入成熟阶段 |
| 茼蒿 | 随机刻3次进入发芽阶段 随机刻6次进入成熟阶段 |
| 菠菜 | 随机刻4次进入发芽阶段 随机刻6次进入成熟阶段 |
| 茄子 | 随机刻8次进入发芽阶段 随机刻10次进入成熟阶段 |
| 柠檬 | 随机刻8次进入发芽阶段 随机刻10次进入成熟阶段 |
修改好后,点击编辑器的开发测试进入到游戏中同时种下这些农作物来观察判断一下是否成功;茄子和柠檬设定的随机刻数最多,理应生长的最慢;
![18](./images/18.gif)
## 较为特殊的农作物方块
现在我们已经制作出了五种完整的农作物,它们都有三个成长阶段,并且会随着随机刻的触发而成长,直到最终的成熟;不过这些农作物不能千篇一律,还有其它条件需要遵循,比如下面的两种农作物:
- 竹笋:在生长为成熟竹笋后,如果没有及时采集,最后会长成竹子(不仅可以种植在耕地上,泥土和灰化土也可以)
- 豌豆:需要种植在篱笆方块上(篱笆放在耕地上)
![19](./images/19.png)
竹笋的种植条件只需要在组件中添加灰化土和泥土就可以了:
```json
"minecraft:placement_filter": {
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland","dirt","podzol"] //耕地、泥土、灰化土
}
]
}
```
而最终会长成竹子也只需要添加一个事件,将竹笋转换为竹子即可:
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:bambooshoot",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2],
"farm:growth": [0, 1, 2, 3, 4, 5, 6, 7]
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 2", //当farm:age等于2时说明竹笋已经成熟
"components": {
"minecraft:loot": "loot_tables/bambooshoot.json",
"minecraft:geometry": "geometry.bambooshoot_stage_2",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 12, 16]
},
"minecraft:random_ticking": { //仍然添加随机刻触发器
"on_tick": {
"target": "self",
"event": "farm:on_age_count_2" //触发的事件名
}
},
"minecraft:on_player_destroyed": {
"event": "farm:on_destroy_stage_2"
},
"minecraft:material_instances": {
"*": {
"texture": "farm:bambooshoot_stage_2",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"components": {
},
"events": {
"farm:setblock_bamboo": { //将竹笋改为竹子的事件
"set_block": { //在当前方块位置 放置新的方块
"block_type": "minecraft:bamboo" //放置竹子(将竹笋替换为竹子)
},
"set_block_at_pos": { //位置偏移放置方块
"block_type": "minecraft:dirt", //放置泥土
"block_offset": [0,-1,0] //Y轴偏移-1也就是在竹笋下方放置泥土
}
},
"farm:on_age_count_2": { //上方随机刻触发的事件名
"sequence": [
{
"condition": "query.block_property('farm:growth') < 4",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 4",
"trigger": {
"event": "farm:setblock_bamboo", //当条件符合时触发事件
"target": "self"
}
}
]
}
}
}
}
```
![20](./images/20.gif)
豌豆的篱笆实现方式也较简单给豌豆添加一个组合条件是farm:age的属性为0这个组合设置模型和贴图为篱笆不需要添加随机刻触发器当玩家使用种子的时候变更farm:age为1也就对应豌豆第一个成长阶段的组合
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:peas",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2, 3], //添加一个数0为篱笆所以1、2、3就对应农作物的三个生长阶段
"farm:growth": [0, 1, 2, 3, 4, 5]
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 1",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 2",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 3",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 0", //当farm:age为0时
"components": {
"minecraft:loot": "loot_tables/empty.json",
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 16, 16]
},
"minecraft:geometry": "geometry.bamboo_fence",//模型使用篱笆
"minecraft:block_light_absorption": 0,
"minecraft:material_instances": {
"*": {
"texture": "farm:peas_stage_0", //贴图使用篱笆
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"components": {
"minecraft:placement_filter": {
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland"]
}
]
},
"minecraft:entity_collision": false,
"minecraft:on_player_placing": {
"event": "farm:on_player_placing",
"target": "self"
}
},
"events": {
"farm:on_age_count_1": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 3",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 3",
"trigger": {
"event": "farm:on_whiteradish_grow_to_2",
"target": "self"
}
}
]
},
"farm:on_age_count_2": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 5",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 5",
"trigger": {
"event": "farm:on_whiteradish_grow_to_3",
"target": "self"
}
}
]
},
"farm:on_player_placing": {
"set_block_property": {
"farm:age": 0,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_2": {
"set_block_property": {
"farm:age": 2,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_3": {
"set_block_property": {
"farm:age": 3,
"farm:growth": 0
}
}
}
}
}
```
现在豌豆方块刚放下时是篱笆我们需要继续设定拿种子点击篱笆可以修改豌豆方块的farm:age为1这里需要使用MODSDK打开**blocklistener.py**,监听**ItemUseOnAfterServerEvent**事件,当玩家手持物品点击方块时触发:
```python
class Main(ServerSystem):
def __init__(self, namespace, system_name):
ServerSystem.__init__(self, namespace, system_name)
self.ListenForEvent(namespace, system_name,
'ItemUseOnAfterServerEvent', self, self.using_block) #监听事件
def using_block(self, event):
#从事件中取需要的参数玩家id、方块名称、方块附加值、手持物品的信息字典、方块的坐标
playerid = event['entityId']
blockname = event['blockName']
blockaux = event['blockAuxValue']
itemname = event['itemDict']
x = event['x']
y = event['y']
z = event['z']
#逻辑中需要用到的接口
item_comp = serverApi.GetEngineCompFactory().CreateItem(playerid)
blockstatecomp = serverApi.GetEngineCompFactory().CreateBlockState(serverApi.GetLevelId())
#判断 手持的物品是否是豌豆种子、点击的方块是否是豌豆方块、并且方块的附加值为0farm:age对应的值就代表blockaux
if blockname == 'farm:peas' and itemname['newItemName'] == 'farm:peas_seed' and blockaux == 0:
#获取手持物品的信息
carried_item = item_comp.GetPlayerItem(ItemPosType.CARRIED, 0, True)
#设定手持物品的数量-1
carried_item['count'] -= 1
#将更改数量后的物品信息设置到玩家上
item_comp.SetPlayerAllItems({(ItemPosType.CARRIED,0):carried_item})
#获取对应坐标的方块
state = blockstatecomp.GetBlockStates((x,y,z), 0)
#将方块的farm:age改为1
state['farm:age'] = 1
#将更改后的方块替换到获取的坐标上
blockstatecomp.SetBlockStates((x,y,z), state, 0)
```
![21](./images/21.gif)
## 增加农作物可收获的次数
| 农作物名称 | 生长时间 | 收获期数 |
| ---------- | --------------------------------------------------- | -------- |
| 玉米 | 随机刻8次进入发芽阶段 随机刻12次进入成熟阶段 | 2次 |
| 香蕉 | 随机刻10次进入发芽阶段 随机刻12次进入成熟阶段 | 2次 |
对于香蕉、玉米这种可以收获多次的农作物,我们需要继续添加新功能使其可以在收获完后回到发芽阶段继续生长:
```json
{
"format_version": "1.16.100",
"minecraft:block": {
"description": {
"identifier": "farm:corn",
"register_to_creative_menu": true,
"properties": {
"farm:age": [0, 1, 2, 3, 4], //添加两个阶段
"farm:growth": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
}
},
"permutations": [
{
"condition": "query.block_property('farm:age') == 0",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 1",
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 2", //此阶段农作物成熟
"components": {···}
},
{
"condition": "query.block_property('farm:age') == 3", //收获一次后,进入到新的阶段,而这个阶段的模型和贴图都采用发芽阶段并且继续添加随机刻触发器使其可继续生长
"components": {
"minecraft:geometry": "geometry.corn_stage_0",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 12, 16]
},
"minecraft:random_ticking": {
"on_tick": {
"target": "self",
"event": "farm:on_age_count_3"
}
},
"minecraft:material_instances": {
"*": {
"texture": "farm:corn_stage_1",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
},
{
"condition": "query.block_property('farm:age') == 4", //第二次成熟阶段,添加掉落表,玩家可以打掉农作物以第二次收获
"components": {
"minecraft:loot": "loot_tables/corn.json", //添加掉落物表
"minecraft:geometry": "geometry.corn_stage_2",
"minecraft:block_light_absorption": 0,
"minecraft:pick_collision": {
"origin": [-8, 0, -8],
"size": [16, 12, 16]
},
"minecraft:material_instances": {
"*": {
"texture": "farm:corn_stage_2",
"render_method": "alpha_test",
"ambient_occlusion": false
}
}
}
}
],
"components": {
"minecraft:placement_filter": {
"conditions": [
{
"allowed_faces": ["up"],
"block_filter": ["farmland"]
}
]
},
"minecraft:entity_collision": false,
"minecraft:on_player_placing": {
"event": "farm:on_player_placing",
"target": "self"
}
},
"events": {
"farm:on_whiteradish_grow_to_3":{
"set_block_property": {
"farm:age": 3,
"farm:growth": 0
}
},
"farm:on_age_count_0": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 7",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 7",
"trigger": {
"event": "farm:on_whiteradish_grow_to_1",
"target": "self"
}
}
]
},
"farm:on_age_count_1": {
"sequence": [
{
"condition": "query.block_property('farm:growth') < 11",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 11",
"trigger": {
"event": "farm:on_whiteradish_grow_to_2",
"target": "self"
}
}
]
},
"farm:on_age_count_3": { //第二个发芽阶段的随机刻事件
"sequence": [
{
"condition": "query.block_property('farm:growth') < 11",
"set_block_property": {
"farm:growth": "query.block_property('farm:growth') + 1"
}
},
{
"condition": "query.block_property('farm:growth') == 11",
"trigger": {
"event": "farm:on_whiteradish_grow_to_4", //符合条件触发的事件
"target": "self"
}
}
]
},
"farm:on_player_placing": {
"set_block_property": {
"farm:age": 0,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_1": {
"set_block_property": {
"farm:age": 1,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_2": {
"set_block_property": {
"farm:age": 2,
"farm:growth": 0
}
},
"farm:on_whiteradish_grow_to_4": {
"set_block_property": {
"farm:age": 4,
"farm:growth": 0
}
}
}
}
}
```
现在的已经有了两次成熟的阶段在第一次成熟的时候不能选择直接打掉农作物所以需要玩家点击农作物进行第一次收获仍然需要使用MODSDK监听**ServerBlockUseEvent**事件,当玩家点击第一次成熟的农作物时生成掉落物并将农作物替换到下一生长阶段:
```python
class Main(ServerSystem):
def __init__(self, namespace, system_name):
ServerSystem.__init__(self, namespace, system_name)
self.ListenForEvent(namespace, system_name,
'ServerBlockUseEvent', self, self.using_item)
def using_item(self, event):
# 获取玩家ID
player_id = event['playerId']
# 创建玩家的物品接口
item_comp = serverApi.GetEngineCompFactory().CreateItem(player_id)
# 获取玩家手持物品信息
carried_item = item_comp.GetPlayerItem(ItemPosType.CARRIED, 0, True)
# 获取事件里交互的方块类型
block_name = event['blockName']
#获取交互方块的坐标
x = event['x']
y = event['y']
z = event['z']
#获取交互方块的附加值
block_aux = event['aux']
#玉米物品掉落物的信息字典
corn_item = {
'newItemName': 'farm:corn_item',
'count': 1,
'newAuxValue': 0,
}
#香蕉物品掉落物的信息字典
banana_item = {
'newItemName': 'farm:banana_item',
'count': 1,
'newAuxValue': 0,
}
#如果农作物方块的名称为farm:corn玉米并且方块的附加值为2对应farm:age为2的第一次成熟阶段
if block_name == "farm:corn" and block_aux == 2:
#获取并修改对应坐标方块的farm:age
blockstatecomp = serverApi.GetEngineCompFactory().CreateBlockState(serverApi.GetLevelId())
state = blockstatecomp.GetBlockStates((x,y,z), 0)
state['farm:age'] = 3
blockstatecomp.SetBlockStates((x,y,z), state, 0)
#在交互方块的坐标位置生成掉落物
drop_comp = serverApi.GetEngineCompFactory().CreateItem(serverApi.GetLevelId())
drop_comp.SpawnItemToLevel(corn_item, 0, (x, y, z))
#如果农作物方块的名称为farm:banana香蕉并且方块的附加值为2对应farm:age为2的第一次成熟阶段
elif block_name == "farm:banana" and block_aux == 2:
#下方逻辑与上方玉米一致
blockstatecomp = serverApi.GetEngineCompFactory().CreateBlockState(serverApi.GetLevelId())
state = blockstatecomp.GetBlockStates((x,y,z), 0)
state['farm:age'] = 3
blockstatecomp.SetBlockStates((x,y,z), state, 0)
drop_comp = serverApi.GetEngineCompFactory().CreateItem(serverApi.GetLevelId())
drop_comp.SpawnItemToLevel(banana_item, 0, (x, y, z))
```
<img src="./images/22.gif" alt="22" style="zoom:115%;" />
## 农作物可以被骨粉催熟
使用骨粉催熟农作物的功能与上面种植豌豆在篱笆上是差不多的,代码如下:
```python
class Main(ServerSystem):
def __init__(self, namespace, system_name):
ServerSystem.__init__(self, namespace, system_name)
#时间戳参数
self.interact_cooldown = {}
#监听玩家使用物品与方块交互
self.ListenForEvent(namespace, system_name,'ItemUseOnAfterServerEvent', self, self.using_block)
def using_block(self, event):
#普通农作物列表
normal_plant_list = ['farm:bambooshoot', 'farm:crown_dasiy', 'farm:eggplant', 'farm:lemon', 'farm:spinach',
'farm:whiteradish']
#需收获两次的农作物列表
double_plant_list = ['farm:banana','farm:corn']
#事件获取的方块名称
blockname = event['blockName']
#事件获取的方块附加值
blockaux = event['blockAuxValue']
#事件获取的手持物品信息字典
itemname = event['itemDict']
#如果交互的方块名称在普通农作物列表中并且玩家手持的物品是骨粉且方块的附加值小于2小于2是为了避开已经成熟的农作物
if blockname in normal_plant_list and itemname['newItemName'] == 'minecraft:bone_meal' and blockaux < 2:
#执行函数
self.use_bone_meal(event)
#如果交互的方块名称在需收获两次的农作物列表中并且玩家手持的物品是骨粉且方块的附加值小于4收获两次的农作物的farm:age比普通农作物多
elif blockname in double_plant_list and itemname['newItemName'] == 'minecraft:bone_meal' and blockaux < 4:
#执行函数
self.use_bone_meal(event)
#如果交互的方块是豌豆并且玩家手持的物品是骨粉且方块的附加值等于1或2
elif blockname == "farm:peas" and itemname['newItemName'] == 'minecraft:bone_meal' and (blockaux == 1 or blockaux == 2):
#执行函数
self.use_bone_meal(event)
else:
pass
def use_bone_meal(self, event):
playerid = event['entityId']
x = event['x']
y = event['y']
z = event['z']
item_comp = serverApi.GetEngineCompFactory().CreateItem(playerid)
blockstatecomp = serverApi.GetEngineCompFactory().CreateBlockState(serverApi.GetLevelId())
#利用时间戳避免瞬间使用多次骨粉的情况
#如果玩家id不在这个变量中说明第一次使用骨粉
if playerid not in self.interact_cooldown:
#给这个变量添加一个参数键是玩家id值是当前的时间戳
self.interact_cooldown[playerid] = time.time()
#获取手持物品的字典信息
carried_item = item_comp.GetPlayerItem(ItemPosType.CARRIED, 0, True)
#给获取到的物品数量减1
carried_item['count'] -= 1
#将修改数量后的物品信息设置到玩家手中
item_comp.SetPlayerAllItems({(ItemPosType.CARRIED, 0): carried_item})
#获取交互的方块信息
state = blockstatecomp.GetBlockStates((x, y, z), 0)
#给获取到的方块的farm:age加1增加成长阶段
state['farm:age'] += 1
#在坐标设置增加成长阶段后的方块
blockstatecomp.SetBlockStates((x, y, z), state, 0)
else:
#如果这个变量有内容并且当前时间戳减去变量中的时间戳大于0.5则执行下方逻辑(说明并不是第一次使用骨粉)
if time.time() - self.interact_cooldown[playerid] > 0.5:
#执行下方逻辑,与上方第一次使用骨粉的逻辑一样
carried_item = item_comp.GetPlayerItem(ItemPosType.CARRIED, 0, True)
carried_item['count'] -= 1
item_comp.SetPlayerAllItems({(ItemPosType.CARRIED, 0): carried_item})
state = blockstatecomp.GetBlockStates((x, y, z), 0)
state['farm:age'] += 1
blockstatecomp.SetBlockStates((x, y, z), state, 0)
self.interact_cooldown[playerid] = time.time()
pass
```
![23](./images/23.gif)

View File

@@ -0,0 +1,143 @@
---
front: https://nie.res.netease.com/r/pic/20210730/ee109f39-8987-46e0-9fe7-40ebb23060fa.png
hard: 进阶
time: 25分钟
---
# 通过attchables和自定义物品添加新的装扮
接下来为地图添加多种多样的装饰装备让玩家可以购买并自由搭配装备共分为四个部位头、身、腿、脚中国版的自定义物品和微软1.16+的自定义物品都可以制作,本节会把两种方法都进行演示。
![40](./images/40.png)
## 使用中国版自定义物品制作
在行为包下的**netease_items_beh**中新建一个json文件为自定义物品添加行为组件
```json
{
"format_version": "1.10",
"minecraft:item": {
"description": {
"identifier": "farm:denim",
"register_to_create_menu":true,
"custom_item_type": "armor" //自定义物品类型:盔甲
},
"components": {
"netease:armor":{ //定义物品为盔甲
"defense": 1, //防御值
"enchantment":1, //附魔能力
"armor_slot":2 //盔甲槽位0-头盔,1-胸甲,2-护腿,3-鞋子)
}
}
}
}
```
在资源包下的**netease_items_res**中同样新建一个json文件定义这个自定义物品的图标
```json
{
"format_version": "1.10",
"minecraft:item": {
"description": {
"identifier": "farm:denim",
"category": "Equipment" //在创造栏中的类别:装备
},
"components": {
"minecraft:icon": "farm:denim" //自定义物品的图标对应item_texture文件
}
}
}
```
创建一个自定义物品后,继续在资源包的**attachables**文件中创建json文件定义自定义装备的模型、贴图等
```json
{
"format_version": "1.8.0",
"minecraft:attachable": {
"description": {
"identifier": "farm:denim",
"materials": {
"default": "armor",
"enchanted": "armor_enchanted"
},
"textures": { //贴图
"default": "textures/models/denim", //正常状态时
"enchanted": "textures/misc/enchanted_item_glint" //含有附魔时
},
"geometry": {
"default": "geometry.denim" //模型
},
"scripts": {
"parent_setup": "variable.leg_layer_visible = 0.0;" //定义装备的部位
//variable.helmet_layer_visible 头盔
//variable.chest_layer_visible 胸甲
//variable.leg_layer_visible 护腿
//variable.boot_layer_visible 靴子
},
"render_controllers": [ "controller.render.armor" ] //渲染控制器
}
}
}
```
## 使用微软自定义物品制作
**attachables**内的json文件无需做任何修改和中国版是一样的微软自定义物品的json文件放在**items**里:
```json
{
"format_version": "1.16.100",
"minecraft:item": {
"description": {
"identifier": "farm:denim_new",
"category": "equipment"
},
"components": {
"minecraft:creative_category": { //在创造栏中的类别:装备
"parent": "itemGroup.name.equipment"
},
"minecraft:icon": { //自定义物品的图标同样对应item_texture文件
"texture": "farm:denim"
},
"minecraft:enchantable": { //附魔等级
"value": 1, //值
"slot": "armor_legs" //附魔装备类型(护腿)
},
"minecraft:armor": {
"protection": 1 //防御值
},
"minecraft:wearable": { //定义物品可穿戴
"slot": "slot.armor.legs" //装备在腿部的格子上
}
}
}
}
```
微软自定义物品的创造栏类别和自定义物品图标都放在行为包的文件内,无需在资源包另外添加;
## 装扮装备的模型
装备的模型有一些部分需要特别注意,因为玩家在走动、转视角的时候,各个部位都有不同的动作,身上的装备也需要跟着部位动,所以装备模型的骨骼要设定好,以**blockbench**为例:
![41](./images/41.png)
![42](./images/42.png)
装备模型和原版史蒂夫模型的很多组名Group都一样这个牛仔裤模型的块都在leftLeg和rightLeg下分别对应左腿和右腿这里的组名就是和史蒂夫绑定的骨骼
如果我们把rightleg的组名随意修改会发生什么
![43](./images/43.gif)
左腿的装备是跟随玩家的腿移动的,不过右腿的装备就固定在原地,所以骨骼的绑定是非常重要的,建议装备的模型都严格的命名,更直观、高效。