Menu
CoddyTech

Boss 战

本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 64 课,共 64 课。

一只石头魔像守着竞技场出口的大门。它朝你跺步而来,靠近时会短暂举起拳头,然后猛砸地面,如果你还在附近,就会受伤。砸击后它会休息,只有这时你的剑才能伤到它:它行走或蓄力时,石质皮肤能挡住所有攻击。它的颜色表示当前状态:行走时是灰色,蓄力时是红色,休息时是青色。把它的生命值降到 0,大门就会打开。屏幕顶部的血条会随每次攻击变化。

用状态机编写魔像的 AI,为每种状态创建一个类:Boss,以及 BossStates.cs 中的 ChaseState、WindupState 和 RestState。玩家、血条、大门、IState、StateMachine 和 IDamageable 都已准备好,Boss 也已经创建了各个状态,并会逐帧更新状态机。

challenge icon

挑战

困难

在 BossStates.cs 中编写魔像的状态。

  1. ChaseState:调用 Tint(Color.gray);以 speed 的速度朝玩家移动;进入 slamRange 范围后,开始蓄力。
  2. WindupState:调用 Tint(Color.red);经过 windupTime 后,记录 Slam!,对范围内的玩家造成 slamDamage 点伤害,然后休息。
  3. RestState:调用 Tint(Color.cyan);经过 restTime 后,开始追击。
  4. Boss.TakeDamage 只在 rest 状态下生效:扣除相应数值,提高 HealthChanged 事件;生命值降至 0 时调用 Fall()。

按下“开始”,趁它休息时攻击。然后按“检查”。

亲手试试

using System;
using UnityEngine;
using UnityEngine.Events;

public class Boss : MonoBehaviour, IDamageable
{
    public Transform player;
    public float speed = 2f;
    public float slamRange = 2.5f;
    public float windupTime = 1f;
    public float restTime = 2f;
    public int slamDamage = 2;
    public int maxHealth = 6;

    public event Action<int, int> HealthChanged;
    public UnityEvent onDefeated;

    public StateMachine machine;
    public IState chase;
    public IState windup;
    public IState rest;

    private int health;

    void Awake()
    {
        health = maxHealth;
        machine = new StateMachine();
        chase = new ChaseState(this);
        windup = new WindupState(this);
        rest = new RestState(this);
    }

    void Start()
    {
        HealthChanged?.Invoke(health, maxHealth);
        machine.ChangeState(chase);
    }

    void Update()
    {
        machine.Tick();
    }

    public void TakeDamage(int amount)
    {
        // 只有它休息时受到的攻击才算数:扣除 amount 点生命值,触发 HealthChanged,生命值降到 0 时调用 Fall()。
    }

    // 已完成:石魔倒下,大门打开,石魔离开竞技场。
    void Fall()
    {
        Debug.Log("The golem falls");
        onDefeated.Invoke();
        gameObject.SetActive(false);
    }

    // 玩家在地面方向上的距离。
    public float PlayerDistance()
    {
        Vector3 d = player.position - transform.position;
        d.y = 0f;
        return d.magnitude;
    }

    // 行走时显示灰色,蓄力时显示红色,休息时显示青色。
    public void Tint(Color color)
    {
        GetComponent<Renderer>().material.color = color;
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

Unity 游戏架构中的所有课

自己练习: Unity 在线编辑器