Menu
CoddyTech

武器属性

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

剑和锤子做的事情相同:挥动、等待,然后再次挥动。它们的区别在于数值。剑每 0.5 秒挥动一次,每次造成 4 点伤害;锤子每 1.5 秒挥动一次,每次造成 10 点伤害。因此,一个 Weapon 脚本就能用于这两种武器,每种武器的数值都保存在一个资源中:

[CreateAssetMenu(menuName = "Combat/Weapon Data")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public int damage;
    public float swingTime;
    public GameObject hitEffect;
}
public class Weapon : MonoBehaviour
{
    public WeaponData data;
    private float nextSwing;

    public void Swing(Health target)
    {
        if (Time.time < nextSwing) return;
        nextSwing = Time.time + data.swingTime;
        target.TakeDamage(data.damage);
        Instantiate(data.hitEffect, target.transform.position, Quaternion.identity);
    }
}

项目中有一个 Sword 资源(4、0.5、一个火花预制体)和一个 Hammer 资源(10、1.5、一个尘土预制体)。骑士和食人魔都带有 Weapon 脚本;骑士的 data 字段引用 Sword,食人魔的则引用 Hammer。你还可以通过 Create 菜单创建一个长矛资源,无需修改任何脚本。资源可以引用预制体和其他资源,比如 hitEffect,但不能引用场景中的对象:资源存放在项目中,位于所有场景之外。

其他实现不同武器的方法,都会把数值写进代码。if (weaponName == "Sword") damage = 4; else if ... 会随着武器数量增加而变得越来越长;而只设置数值的 Weapon 子类 Sword,则相当于每个资源都要创建一个类。子类适用于行为不同的武器,比如会射出箭的弓。对于只会造成更高伤害或挥动速度更快的武器,只需创建单独的资源,无需编写代码。

challenge icon

挑战

中等

让每把枪都从自己的 GunData 资源中读取数值。

  1. 在 Gun 中添加 public GunData data;。
  2. 发射 data.bulletPrefab,每次射击之间等待 data.fireInterval,并为每颗子弹设置 data.damage。
  3. 删除 gunType、两个子弹字段、三个私有副本和 Start()。

按“开始”并按住 Space:爆能枪也会开火。然后点击“检查”。

亲手试试

using UnityEngine;
using UnityEngine.InputSystem;

public class Gun : MonoBehaviour
{
    public string gunType = "Pistol";
    public GameObject pistolBullet;
    public GameObject rifleBullet;
    private GameObject bulletPrefab;
    private float fireInterval;
    private int damage;
    private float nextShot;

    void Start()
    {
        if (gunType == "Pistol")
        {
            bulletPrefab = pistolBullet;
            fireInterval = 0.25f;
            damage = 1;
        }
        else if (gunType == "Rifle")
        {
            bulletPrefab = rifleBullet;
            fireInterval = 0.6f;
            damage = 4;
        }
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.isPressed && Time.time >= nextShot)
        {
            nextShot = Time.time + fireInterval;
            GameObject bullet = Instantiate(bulletPrefab, transform.position + transform.forward, transform.rotation);
            bullet.GetComponent<Bullet>().damage = damage;
        }
    }
}

Unity 游戏架构中的所有课

自己练习: Unity 在线编辑器