继承 是面向对象编程(OOP)三大特性之一,在 Unity 开发中核心作用是:提取公共代码→父类 ,子类只写独有逻辑,减少重复代码、方便统一管理。
一、核心概念
父类(基类):存放所有子类共用的变量、方法(比如怪物都有血量、移动,玩家都有受伤、升级)。
子类(派生类):继承父类后,自动拥有父类的所有非私有成员,只需写自己独有的逻辑。
关键字:: 表示继承,base 调用父类成员,override 重写父类方法。
二、基础语法(最简示例)
- 父类(通用脚本,挂载不挂载都行)
cpp
using UnityEngine;
// 父类:所有角色的通用属性和行为
public class Character : MonoBehaviour
{
// 公共变量:子类直接用
public int hp = 100;
public float moveSpeed = 5f;
// 虚方法:允许子类重写(override)
public virtual void TakeDamage(int damage)
{
hp -= damage;
Debug.Log("父类:受到伤害,剩余血量:" + hp);
}
// 普通方法:子类直接调用,不能重写
public void Move()
{
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}
}
- 子类(继承父类,挂载到游戏物体)
cpp
using UnityEngine;
// 子类:玩家,继承 Character
public class Player : Character
{
// 子类独有变量
public int attackPower = 20;
// 重写父类方法(独有逻辑)
public override void TakeDamage(int damage)
{
// 调用父类原本的逻辑(必须写 base.方法名)
base.TakeDamage(damage);
// 子类独有逻辑:玩家受伤后闪红
Debug.Log("子类:玩家受伤特效触发!");
}
// 子类独有方法
public void Attack()
{
Debug.Log("玩家攻击,伤害:" + attackPower);
}
}
三、Unity 中继承的关键规则
-
继承权限(必须记)
父类修饰符 子类能否访问 场景面板显示 用法 public ✅ 能 ✅ 显示 公共属性 / 方法 protected ✅ 能 ❌ 不显示 子类专用(最常用,安全不暴露) private ❌ 不能 ❌ 不显示 父类私有,子类完全无法访问
✅ 最佳实践:父类不想公开、但子类要用的变量 / 方法,用 protected。
-
方法重写(核心)
父类方法加 virtual → 允许子类修改 子类方法加 override → 重写父类逻辑 子类中用 base.方法名() → 调用父类原本逻辑 -
MonoBehaviour 继承规则
只要父类继承了 MonoBehaviour,子类不需要重复写 子类脚本可以直接挂载到 Unity 游戏物体上 父类可以不挂载,子类挂载后自动拥有父类的所有功能
四、实用完整案例(Unity 怪物 / 玩家通用系统)
- 父类:EnemyBase(所有怪物的通用逻辑)
cpp
using UnityEngine;
// 所有怪物的父类
public class EnemyBase : MonoBehaviour
{
[Header("===== 通用属性 =====")]
protected int maxHp = 50;
protected int currentHp;
protected float moveSpeed = 2f;
void Start()
{
// 父类初始化,所有子类自动执行
currentHp = maxHp;
Debug.Log(gameObject.name + " 初始化完成");
}
// 所有怪物通用受伤逻辑
public virtual void TakeDamage(int damage)
{
currentHp -= damage;
Debug.Log("怪物受伤,剩余血量:" + currentHp);
if (currentHp <= 0)
{
Die();
}
}
// 通用死亡逻辑
protected virtual void Die()
{
Debug.Log(gameObject.name + " 死亡");
Destroy(gameObject);
}
// 通用移动
public void MoveToTarget(Transform target)
{
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
moveSpeed * Time.deltaTime
);
}
}
- 子类:SlimeEnemy(史莱姆怪物,独有逻辑)
cpp
using UnityEngine;
// 史莱姆:继承 EnemyBase
public class SlimeEnemy : EnemyBase
{
// 子类独有属性
private float jumpForce = 3f;
// 重写死亡逻辑(史莱姆死亡会分裂)
protected override void Die()
{
// 先执行父类死亡逻辑
base.Die();
// 子类独有:分裂小史莱姆
Debug.Log("史莱姆分裂成2个小史莱姆!");
}
// 子类独有方法
public void Jump()
{
Debug.Log("史莱姆跳跃!");
GetComponent<Rigidbody>().AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
- 子类:BossEnemy(Boss 怪物,独有逻辑)
cpp
using UnityEngine;
// Boss:继承 EnemyBase
public class BossEnemy : EnemyBase
{
// 重写受伤逻辑(Boss受伤会狂暴)
public override void TakeDamage(int damage)
{
base.TakeDamage(damage);
// 独有逻辑:血量低于30% 狂暴
if (currentHp < maxHp * 0.3f)
{
moveSpeed = 5f;
Debug.Log("Boss狂暴!移速提升");
}
}
}
五、Unity 编辑器中的表现
子类脚本挂载到物体后,自动拥有父类的所有组件 / 功能
父类的 public/[SerializeField] 变量会在 Inspector 面板显示
修改父类代码,所有子类自动同步更新(不用逐个改)
六、常见使用场景
UI 面板基类:所有面板共用打开 / 关闭 / 隐藏逻辑
角色系统:玩家、怪物、NPC 共用血量、受伤、移动
技能系统:所有技能共用冷却、释放、伤害计算
武器系统:剑、枪、弓 共用攻击、耐久、切换逻辑
七、避坑指南
不要滥用继承:只有多个类有大量公共代码时才用
private 成员子类无法访问,用 protected
重写方法必须加 override,父类必须加 virtual
子类 Awake/Start 不会自动执行父类的,需要手动写 base.Awake()
一个类只能继承一个父类(C# 不支持多继承)