Как присвоить переменной тип "Скрипт" с последующим его выбором? Юнити С#
У меня есть 2 скрипта на объекте: 1ый "Enemy" и 2ой например "Goblin", класс Гоблин является наследуемый от Энеми и так как есть разные типы врагов то могут быть и другие скрипты "Golem" "Solder" и тд...
Есть отдельный скрипт, который вызывает void функцию о начале хода врага из наших скриптов Гоблинов и Солдат, которая в них называется одинаково но содержит разный код (например гоблин умеет ходить а голем нет).
Чтобы унифицировать код, я хочу в скрипт "Enemy" добавить переменную которая будет содержать ссылку на скрипт прикрепленный к врагу, определяющий его тип (гоблин, голем, солдат), но переменная требует "ТИП" при объявлении. Например:
public Goblin ScriptEnemyType;
Тем самым я могу прикрепить только определённый скрипт, а я хочу иметь возможность в скрипте "Гоблин" или "Солдат" назначать значение этой переменной скрипта "Enemy", которая будет вызывать одну и ту же функцию, но разную по наполнению.
Как правильно это сделать?
Ответы (1 шт):
То, что вы хотите сделать называется наследование.
Применительно к этой ситуации оно может выглядеть таким образом. Создаем абстрактный класс врага, это своего рода модель описывающая поведение (и иногда состояние) сущности. Суть абстрактного класса состоит в том, что его цель - чтобы от него наследовали. Напрямую от него создать экземпляр невозможно.
using UnityEngine;
public abstract class Enemy : MonoBehaviour
{
protected int Health = 100; //к protected полям мы можем обращаться от наследников класса, но не из вне
abstract public void Hurt(int value); //метод может быть виртуальным и содержать реализацию по умолчанию
}
Соответственно, дальше вы можете создавать не ограниченное кол-во типов врагов, например:
public class Goblin : Enemy
{
public int armor = 1; //у гоблина есть броня, но её нет у абстрактного Enemy
public override void Hurt(int value)
{
int damage = value - armor;
if (damage > 0)
{
Health -= value;
}
}
}
public class Mag : Enemy
{
public int magicAura = 10; // а у мага есть магическая аура, которая ведет себя не как броня
public override void Hurt(int value)
{
if (value > magicAura)
{
Health -= value;
}
}
}
Теперь вы можете в любом месте использовать тип данных Enemy , например:
using UnityEngine;
using Random = UnityEngine.Random;
public class Player : MonoBehaviour
{
private Enemy _enemy;
private void Start()
{
_enemy = FindObjectOfType<Enemy>();
}
private void Update()
{
_enemy.Hurt(Random.Range(0,15));
}
}
Естественно вы можете создавать цепочки наследования, типа Enemy -> Mag -> MagOfWater или интерфейсы выражающие отношение может быть, например:
public interface IVulnerable
{
void Hurt(int value);
}
using UnityEngine;
public class Goblin : MonoBehaviour, IVulnerable
{
public int armor = 1;
private int _health = 100;
public void Hurt(int value)
{
int damage = value - armor;
if (damage > 0)
{
_health -= value;
}
}
}
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
public class Player : MonoBehaviour
{
private IVulnerable _enemy;
private void Start()
{
_enemy = FindObjectsOfType<MonoBehaviour>().OfType<IVulnerable>().First();
}
private void Update()
{
_enemy.Hurt(Random.Range(0,15));
}
}
Вы также можете хранить определенный тип врага при помощи такого типа данных как enum перечисление. Оно создается с помощью ключевого слова enum И может содержать в себе некоторые строковые значения, каждое из которых равняется какому-либо числу. Подробнее можете почитать по ссылке.
public enum EnemyType {
GOBLIN, // = 0 (по умолчанию нумерация с нуля)
ORK, // = 1
JUST_BAD_GUY // = 2
}
После чего вы можете хранить тип врага в одной переменной типа данных названия перечисления:
public EnemyType enemyType = EnemyType.GOBLIN;