# 让实体在水中悬浮

我们知道,鸭子都喜欢在水面上游动。鸭子在游动的时候,虽然双脚在水中拍打,但是在水面上却极为平稳。成语“鸭子凫水”便意味着暗地使劲,明面上看不出来的行为。而我们目前的水鸭在水中漂浮时却仅仅是像其他生物一样,一上一下。在本节中,我们将我们的鸭子的行为改为在水面上持续悬浮。

# 在原版实体中找到对应的组件

我们在原版实体中回忆哪种实体存在悬浮在液体表面的行为。不难发现,赤足兽便是一种可以在熔岩表面悬浮的实体。因此,赤足兽的行为文件中必定存在一种可以用于悬浮的组件。我们打开赤足兽的行为文件来一探究竟。由于在水面漂浮应该是一种AI意向,我们着重关注带有behavior.前缀的组件。

"minecraft:behavior.rise_to_liquid_level": {
  "priority": 0,
  "liquid_y_offset": 0.25,
  "rise_delta": 0.01,
  "sink_delta": 0.01
},
"minecraft:behavior.move_to_lava": {
  "priority": 7,
  "search_range": 16,
  "search_height": 10,
  "goal_radius": 0.9,
  "search_count": 30
},
"minecraft:behavior.random_stroll": {
  "priority": 8,
  "speed_multiplier": 0.8
},
"minecraft:behavior.look_at_player": {
  "priority": 9,
  "look_distance": 6.0,
  "probability": 0.02
},
"minecraft:behavior.random_look_around": {
  "priority": 10
},
"minecraft:behavior.panic": {
  "priority": 3,
  "speed_multiplier": 1.1,
  "panic_sound": "panic",
  "sound_interval": {
    "range_min": 1.0,
    "range_max": 3.0
  }
},
"minecraft:behavior.tempt": {
  "priority": 5,
  "speed_multiplier": 1.2,
  "items": [
    "warped_fungus",
    "warped_fungus_on_a_stick"
  ],
  "tempt_sound": "tempt",
  "sound_interval": {
    "range_min": 2.0,
    "range_max": 5.0
  }
}

很快,我们便能通过其组件名的字面意思定位到priority优先级为0的那个组件minecraft:behavior.rise_to_liquid_level。事实上,这个确实就是能够使赤足兽悬浮的AI意向。我们将其复制到鸭子中。

# 实现水鸭的行为

我们稍作修改,然后将其复制到水鸭的行为定义文件中。

"minecraft:behavior.rise_to_liquid_level": {
  "priority": 0,
  "liquid_y_offset": -0.5,
  "rise_delta": 0.01,
  "sink_delta": 0.01
}

这并没有结束。因为我们知道,水鸭之所以会在水面上上下浮动是因为另一个AI意向也在起作用,那就是minecraft:behavior.float。我们删除这个AI意向。

最后,我们更改水鸭的导航组件。因为我们删除了minecraft:behavior.float,水鸭的AI便不再要求水鸭持续浮在水面上,所以我们在水鸭的导航组件minecraft:navigation.walk中加入can_sink并设置为false。这样,水鸭在水中便不会下沉。

"minecraft:navigation.walk": {
  "can_path_over_water": true,
  "can_sink": false,
  "avoid_damage_blocks": true
}

至此,我们从理论上边实现了水鸭的行为替换。

{
  "format_version": "1.16.0",
  "minecraft:entity": {
    "description": {
      "identifier": "tutorial_demo:teal",
      "runtime_identifier": "minecraft:chicken",
      "is_spawnable": true,
      "is_summonable": true,
      "is_experimental": false
    },
    "component_groups": {
      "minecraft:teal_baby": {
        "minecraft:is_baby": {},
        "minecraft:scale": {
          "value": 0.5
        },
        "minecraft:ageable": {
          "duration": 1200,
          "feed_items": ["wheat_seeds", "beetroot_seeds", "melon_seeds", "pumpkin_seeds"],
          "grow_up": {
            "event": "minecraft:ageable_grow_up",
            "target": "self"
          }
        },
        "minecraft:behavior.follow_parent": {
          "priority": 5,
          "speed_multiplier": 1.1
        }
      },
      "minecraft:teal_adult": {
        "minecraft:experience_reward": {
          "on_bred": "Math.Random(1,7)",
          "on_death": "query.last_hit_by_player?Math.Random(1,3):0"
        },
        "minecraft:loot": {
          "table": "loot_tables/entities/chicken.json"
        },
        "minecraft:breedable": {
          "require_tame": false,
          "breeds_with": {
            "mate_type": "tutorial_demo:teal",
            "baby_type": "tutorial_demo:teal",
            "breed_event": {
              "event": "minecraft:entity_born",
              "target": "baby"
            }
          },
          "breed_items": ["wheat_seeds", "beetroot_seeds", "melon_seeds", "pumpkin_seeds"]
        },
        "minecraft:behavior.breed": {
          "priority": 3,
          "speed_multiplier": 1
        },
        "minecraft:rideable": {
          "seat_count": 1,
          "family_types": ["zombie"],
          "seats": {
            "position": [0, 0.4, 0]
          }
        },
        "minecraft:spawn_entity": {
          "entities": {
            "min_wait_time": 300,
            "max_wait_time": 600,
            "spawn_sound": "plop",
            "spawn_item": "egg",
            "filters": {
              "test": "rider_count",
              "subject": "self",
              "operator": "==",
              "value": 0
            }
          }
        }
      }
    },
    "components": {
      "minecraft:type_family": {
        "family": ["chicken", "mob"]
      },
      "minecraft:breathable": {
        "total_supply": 15,
        "suffocate_time": 0
      },
      "minecraft:collision_box": {
        "width": 0.6,
        "height": 0.8
      },
      "minecraft:nameable": {},
      "minecraft:health": {
        "value": 4,
        "max": 4
      },
      "minecraft:hurt_on_condition": {
        "damage_conditions": [
          {
            "filters": {
              "test": "in_lava",
              "subject": "self",
              "operator": "==",
              "value": true
            },
            "cause": "lava",
            "damage_per_tick": 4
          }
        ]
      },
      "minecraft:movement": {
        "value": 0.25
      },
      "minecraft:damage_sensor": {
        "triggers": {
          "cause": "fall",
          "deals_damage": false
        }
      },
      "minecraft:leashable": {
        "soft_distance": 4,
        "hard_distance": 6,
        "max_distance": 10
      },
      "minecraft:balloonable": {
        "mass": 0.5
      },
      "minecraft:navigation.walk": {
        "can_path_over_water": true,
        "can_sink": false, // 添加不会下沉
        "avoid_damage_blocks": true
      },
      "minecraft:movement.basic": {},
      "minecraft:jump.static": {},
      "minecraft:can_climb": {},
      "minecraft:despawn": {
        "despawn_from_distance": {}
      },
      "minecraft:behavior.rise_to_liquid_level": {
        "priority": 0,
        "liquid_y_offset": -0.5,
        "rise_delta": 0.01,
        "sink_delta": 0.01
      }, // 添加赤足兽的悬浮行为
      "minecraft:behavior.panic": {
        "priority": 1,
        "speed_multiplier": 1.5
      },
      "minecraft:behavior.mount_pathing": {
        "priority": 2,
        "speed_multiplier": 1.5,
        "target_dist": 0,
        "track_target": true
      },
      "minecraft:behavior.tempt": {
        "priority": 4,
        "speed_multiplier": 1,
        "items": ["wheat_seeds", "beetroot_seeds", "melon_seeds", "pumpkin_seeds"]
      },
      "minecraft:behavior.random_stroll": {
        "priority": 6,
        "speed_multiplier": 1
      },
      "minecraft:behavior.look_at_player": {
        "priority": 7,
        "look_distance": 6,
        "probability": 0.02
      },
      "minecraft:behavior.random_look_around": {
        "priority": 8
      },
      "minecraft:physics": {},
      "minecraft:pushable": {
        "is_pushable": true,
        "is_pushable_by_piston": true
      },
      "minecraft:conditional_bandwidth_optimization": {}
    },
    "events": {
      "from_egg": {
        "add": {
          "component_groups": ["minecraft:teal_baby"]
        }
      },
      "minecraft:entity_spawned": {
        "randomize": [
          {
            "weight": 95,
            "trigger": "minecraft:spawn_adult"
          },
          {
            "weight": 5,
            "add": {
              "component_groups": ["minecraft:teal_baby"]
            }
          }
        ]
      },
      "minecraft:entity_born": {
        "remove": {},
        "add": {
          "component_groups": ["minecraft:teal_baby"]
        }
      },
      "minecraft:ageable_grow_up": {
        "remove": {
          "component_groups": ["minecraft:teal_baby"]
        },
        "add": {
          "component_groups": ["minecraft:teal_adult"]
        }
      },
      "minecraft:spawn_adult": {
        "add": {
          "component_groups": ["minecraft:teal_adult"]
        }
      }
    }
  }
}

但是事实上,由于某些缺陷,我们当前的水鸭在实际游戏中依旧会无视minecraft:behavior.rise_to_liquid_level行为并给自己添加一个minecraft:behavior.float行为。这会导致我们的行为替换失败。这是由于我们的水鸭包是Blockbench生成的,使用了微软最新的清单文件格式版本,我们需要将清单文件中格式版本从2改为1才能消除这一隐患。

同样地,我们在资源包中也需要将清单文件的格式版本从2替换为1,否则将因为格式版本的不对应导致水鸭的贴图无法加载。由于格式版本的改变,这将影响到最低引擎版本,所以我们将资源包中的最低引擎版本删除,否则将导致加载失败。

{
  "format_version": "1.10.0",
  "minecraft:client_entity": {
    "description": {
      "identifier": "tutorial_demo:teal",
      //"min_engine_version": "1.12.0",
      "materials": {
        "default": "chicken",
        "legs": "chicken_legs"
      },
      "textures": {
        "default": "textures/entity/teal"
      },
      "geometry": {
        "default": "geometry.teal"
      },
      "animations": {
        "move": "animation.teal.move",
        //"general": "animation.teal.general",
        "look_at_target": "animation.common.look_at_target",
        "baby_transform": "animation.teal.baby_transform"
      },
      "scripts": {
        "animate": [
          //"general",
          {
            "move": "query.modified_move_speed"
          },
          "look_at_target",
          {
            "baby_transform": "query.is_baby"
          }
        ]
      },
      "render_controllers": ["controller.render.chicken"],
      "spawn_egg": {
        "base_color": "#62c287",
        "overlay_color": "#87692b"
      }
    }
  }
}

同时,我们将general动画删除。general动画是硬编码的翅膀煽动动画,鸭子在水中或空气中都会播放该动画。但是,众所周知,鸭子游泳时翅膀是不煽动的,所以我们直接删除此动画。

我们进入游戏,可以看到我们鸭子确实拥有了悬浮的AI意向!