MC开发者日志#01

  早上起床第一件事马上投入今天的开发时间,今天又是神清气爽的一天呢。又会有什么样的bug等着我呢?让我们公布一下吧,今日最佳:
MVP

今日MVP:耗时超过8小时,至今未解决(#`皿´)

今日整理

  首先是将之前没完成的辉套装的护腿和靴子部分完成了,并且为他们各自提供了合成配方

辉套装背面.jpg辉套装正面.jpg

护腿合成配方的json如下:

{
    "format_version": "1.12",
    "minecraft:recipe_shaped": {
        "description": {
            "identifier": "fantasy_world:splendor_legging"
        },
        "key": {
            "X": {
                "data": -1,
                "item": "fantasy_world:moon_dust"
            },
            "O": {
                "data": -1,
                "item": "fantasy_world:star_ingot"
            }
        },
        "pattern": [
            "OOO",
            "X X",
            "O O"
        ],
        "result": {
            "count": 1,
            "data": 0,
            "item": "fantasy_world:splendor_legging"
        },
        "tags": [
            "crafting_table"
        ]
    }
}

  在编辑配方时需要注意的是“key”值的自定义要与合成配方的”pattern“相对应,最后的”tag“描述的是合成配方支持在何处合成,就算是在背包中的四格合成栏也要把”tag“给写上不然游戏会提示配方没有合成位置并报错,正确的处理方法是写上”tag“但是内容留空,这样就可以使其在背包内合成(其实就算”tag“标记为”crafting_table“也是可以在背包合成的,只要配方的”pattern“在2*2之内

今天的主要任务是创造了一个新的自定义生物——幻鹿

magic_deer.png

利用的是原版牛的模型进行更改,建模过程没有啥技术点好分析的,主要是保证骨骼的绑定,因为没有对原版的骨骼进行修改所以主要的骨骼只有 头部 身体 四条腿。幻鹿的脖子其实是绑在了身体上的,旋转头部时脖子是不会跟着旋转的,所以有时候就会出现一些诡异的动作(比如脖子从头里伸出来)

下面是幻鹿的实体行为json:

{
    "format_version": "1.12.0",
    "minecraft:entity": {
        "component_groups": {
            "minecraft:magic_deer_adult": {
                "minecraft:experience_reward": {
                    "on_death": "query.last_hit_by_player ? 5 + (query.equipment_count * Math.Random(1,3)) : 0"
                }
            },
            "minecraft:magic_deer_angry": {
                "minecraft:angry": {
                    "broadcast_anger": true,
                    "broadcast_range": 20,
                    "calm_event": {
                        "event": "minecraft:on_calm",
                        "target": "self"
                    },
                    "duration": 25
                }
            },
            "minecraft:magic_deer_baby": {
                "minecraft:experience_reward": {
                    "on_death": "query.last_hit_by_player ? 2 + (query.equipment_count * Math.Random(1,3)) : 0"
                },
                "minecraft:is_baby": {
                },
                "minecraft:scale": {
                    "value": 0.5
                }
            },
            "minecraft:magic_deer_calm": {
                "minecraft:on_target_acquired": {
                    "event": "minecraft:become_angry",
                    "target": "self"
                }
            }
        },
        "components": {
            "minecraft:attack": {
                "damage": 3.0
            },
            "minecraft:behavior.look_at_player": {
                "look_distance": 8,
                "priority": 6
            },
            "minecraft:behavior.melee_attack": {
                "priority": 1,
                "reach_multiplier": 2.0,
                "speed_multiplier": 1.0,
                "track_target": true
            },
            "minecraft:behavior.nearest_attackable_target": {
                "attack_interval": 5,
                "entity_types": [
                    {
                        "filters": {
                            "any_of": [
                                {
                                    "subject": "other",
                                    "test": "is_family",
                                    "value": "zombie"
                                }
                            ]
                        },
                        "max_dist": 8
                    }
                ],
                "must_see": true,
                "priority": 0,
                "reselect_targets": true
            },
            "minecraft:behavior.random_stroll": {
                "priority": 8,
                "speed_multiplier": 0.8
            },
            "minecraft:can_climb": {
            },
            "minecraft:collision_box": {
                "height": 1.65,
                "width": 1.0
            },
            "minecraft:health": {
                "max": 30.0,
                "value": 30.0
            },
            "minecraft:jump.static": {
            },
            "minecraft:loot": {
                "table": "loot_tables/netease/kill_magic_deer.json"
            },
            "minecraft:movement": {
                "value": 0.4
            },
            "minecraft:movement.basic": {
                "max_turn": 5
            },
            "minecraft:nameable": {
            },
            "minecraft:navigation.walk": {
                "avoid_water": true,
                "can_open_doors": false,
                "can_pass_doors": true,
                "can_path_over_water": true,
                "can_walk": true,
                "is_amphibious": true
            },
            "minecraft:physics": {
            },
            "minecraft:pushable": {
                "is_pushable": true,
                "is_pushable_by_piston": true
            },
            "minecraft:scale": {
                "value": 1
            },
            "minecraft:storyline": {
                "name": ""
            },
            "minecraft:type_family": {
                "family": [
                    "mob",
                    "deer"
                ]
            },
            "minecraft:underwater_movement": {
                "value": 0.25
            }
        },
        "description": {
            "identifier": "fantasy_world:magic_deer",
            "is_experimental": false,
            "is_spawnable": true,
            "is_summonable": true,
            "runtime_identifier": "fantasy_world:magic_deer"
        },
        "events": {
            "minecraft:become_angry": {
                "add": {
                    "component_groups": [
                        "minecraft:magic_deer_angry"
                    ]
                },
                "remove": {
                    "component_groups": [
                        "minecraft:magic_deer_calm"
                    ]
                }
            },
            "minecraft:entity_spawned": {
                "randomize": [
                    {
                        "add": {
                            "component_groups": [
                                "minecraft:magic_deer_adult",
                                "minecraft:magic_deer_calm"
                            ]
                        },
                        "remove": {
                        },
                        "weight": 95
                    },
                    {
                        "add": {
                            "component_groups": [
                                "minecraft:magic_deer_baby",
                                "minecraft:magic_deer_calm"
                            ]
                        },
                        "remove": {
                        },
                        "weight": 5
                    }
                ]
            },
            "minecraft:entity_transformed": {
                "sequence": [
                    {
                        "add": {
                            "component_groups": [
                                "minecraft:magic_deer_baby",
                                "minecraft:magic_deer_calm"
                            ]
                        },
                        "filters": {
                            "subject": "other",
                            "test": "has_component",
                            "value": "minecraft:is_baby"
                        }
                    },
                    {
                        "add": {
                            "component_groups": [
                                "minecraft:magic_deer_adult",
                                "minecraft:magic_deer_calm"
                            ]
                        },
                        "filters": {
                            "operator": "!=",
                            "subject": "other",
                            "test": "has_component",
                            "value": "minecraft:is_baby"
                        }
                    }
                ]
            },
            "minecraft:on_calm": {
                "add": {
                    "component_groups": [
                        "minecraft:magic_deer_calm"
                    ]
                },
                "remove": {
                    "component_groups": [
                        "minecraft:magic_deer_angry"
                    ]
                }
            }
        }
    }
}

主要需要关注的是”component_groups”的部分以及”event”的部分,幻鹿的设计思路是如同僵尸猪人般的中立性型生物,所以从僵尸猪人的行为json中提取出了包含angry属性的内容

        "minecraft:magic_deer_angry": {
            "minecraft:angry": {
                "broadcast_anger": true,
                "broadcast_range": 20,
                "calm_event": {
                    "event": "minecraft:on_calm",
                    "target": "self"
                },
                "duration": 25
            }
        },

这一部分定义了愤怒的幻鹿这一属性,其中包含一个冷静下来的事件。“broadcast_angry”即传播愤怒,一只幻鹿被激怒后会连同激怒球形半径为20格的幻鹿。

        "minecraft:magic_deer_calm": {
            "minecraft:on_target_acquired": {
                "event": "minecraft:become_angry",
                "target": "self"
            }
        }

这里是定义了幻鹿变愤怒的过程,幻鹿拥有目标后就会进入愤怒状态(“minecraft:on_target_acquired”这个属性没有仔细去wiki上查过,在个人测试的时候幻鹿不能像僵尸猪人一样受到攻击就愤怒,只能当玩家杀死一头幻鹿时,其他幻鹿才会愤怒。但这也是一种新玩法,不是吗?(〃’▽’〃)

接下来就是“became_angry”事件以及“on_clam”事件的分析

        "minecraft:become_angry": {
            "add": {
                "component_groups": [
                    "minecraft:magic_deer_angry"
                ]
            },
            "remove": {
                "component_groups": [
                    "minecraft:magic_deer_calm"
                ]
            }
        }

事件很简单就是触发后在幻鹿的定义组中增加愤怒的属性移除冷静的属性,冷静事件的处理方式同理,不再进行分析。

今天重头戏

今天的重头戏就是自定义生物的动画部分,在建模的时候其实已经把幻鹿的攻击动作做好了,但是在绑定动画的时候出了大问题。

首先还是先分析一下如何给自定义生物绑定上自己的动画

以下是幻鹿的资源文件json

    "format_version": "1.10.0",
    "minecraft:client_entity": {
        "description": {
            "animation_controllers": [
                {
                    "attack_with_head": "controller.animation.magic_deer.attack"
                }
            ],
            "animations": {
                "attack": "animation.magic_deer.attack",
                "baby_transform": "animation.cow.baby_transform",
                "look_at_target": "animation.common.look_at_target",
                "setup": "animation.cow.setup.v1.0",
                "walk": "animation.quadruped.walk"
            },
            "geometry": {
                "default": "geometry.magic_deer"
            },
            "identifier": "fantasy_world:magic_deer",
            "materials": {
                "default": "magic_deer"
            },
            "render_controllers": [
                "controller.render.magic_deer"
            ],
            "scripts": {
                "animate": [
                    "setup",
                    {
                        "walk": "query.modified_move_speed"
                    },
                    "look_at_target",
                    {
                        "baby_transform": "query.is_baby"
                    },
                    "attack"
                ]
            },
            "spawn_egg": {
                "base_color": "#F4A460",
                "overlay_color": "#A0522D"
            },
            "textures": {
                "default": "textures/entity/magic_deer"
            }
        }
    }
}

首先可以看到文件中有出现animation的相关定义

        "animations": {
            "attack": "animation.magic_deer.attack",
            "baby_transform": "animation.cow.baby_transform",
            "look_at_target": "animation.common.look_at_target",
            "setup": "animation.cow.setup.v1.0",
            "walk": "animation.quadruped.walk"
        }

其中前面的字段将会在后面提及的动画控制器中应用到,而后面的字段表示是前面字段的真实资源,也就是动画的真实资源,文件是存放在animation文件夹里的。

        "scripts": {
            "animate": [
                "setup",
                {
                    "walk": "query.modified_move_speed"
                },
                "look_at_target",
                {
                    "baby_transform": "query.is_baby"
                },
                "attack"
            ]
        },

然后这个脚本是显示了将会使用哪些动画,其中的字段就是前面所自定义的缩写字段,其中可以简单的设置某些动画触发的时机,例如baby_transform 利用molang判定生物是baby时才触发。但复杂的触发机制会用到动画控制器,也就是animation_controllers。

        "animation_controllers": [
            {
                "attack_with_head": "controller.animation.magic_deer.attack"
            }
        ],

这段文本就是将动画引用到控制器中进一步控制,控制器的文本存放在animation_controllers文件夹内。下面是幻鹿攻击的动画控制器:

    "format_version": "1.10.0",
    "animation_controllers": {
        "controller.animation.magic_deer.attack": {
            "initial_state": "default",
            "states": {
                "attacking": {
                    "animations": [
                        "attack"
                    ],
                    "transitions": [
                        {
                            "default": "variable.attack_time < 0.0"
                        }
                    ]
                },
                "default": {
                    "transitions": [
                        {
                            "attacking": "variable.attack_time >= 0.0"
                        }
                    ]
                }
            }
        }
    }
}

我们将有用的部分提取出来

"animation_controllers": {
    "controller.animation.magic_deer.attack": {
        "initial_state": "default",
        "states": {
            "attacking": {
                "animations": ["attack"],
                "transitions": [{"default": "variable.attack_time < 0.0"}]
            },
            "default": {
                "transitions": [{"attacking": "variable.attack_time >= 0.0"}]
            }
        }
    }
}

其中”controller.animation.magic_deer.attack”是控制器的唯一标识符,也就是资源文本json中引用的控制器,”initial_state”表示初始状态。”states”用来定义状态,这里定义了两个状态攻击中以及默认状态。攻击状态中带有一个动画,其中的字段就是资源文本json中的动画资源缩写,”transitions”代表转化时机,即动画什么时候播放结束,然后转成什么状态。

variable.attack_time是一个自定义变量,因为找不到相关的定义所以这个动画是不能执行的!!!在官方的文本也找不到攻击时间相关定义。但是即使我把转换条件更换了发现自定义动画还是用不了?!!!

然后就是喜闻乐见的事了,MVP他出现了

经过一整番折磨……我还是搞不懂为啥,经过排查发现是他并没用引用到我放在animation文件夹里的动画,也不知道发生了什么。总之今天的开发过程以及总结就到这了

(看看能不能赶在今天把博客上传完)


初めて会ったの日から 僕の心の全てを奪った