#c# #variables #inheritance #unity3d
#c# #переменные #наследование #unity3d
Вопрос:
Извините, я как бы замалчиваю эту тему. Например, допустим, у меня есть базовый класс Character и два подкласса FriendlyCharacter и EnemyCharacter . Я хочу, чтобы они оба наследовали переменные, такие как health, но я не должен делать переменную health общедоступной, верно? Я бы предположил, что если бы я изменил общедоступную переменную на дружественный характер, это изменило бы все экземпляры работоспособности правильно?
Как мне инициализировать символ, чтобы он содержал переменные, которые будут унаследованы другими классами? После наследования эти классы будут иметь свой собственный экземпляр этой переменной. Я чувствую, что необходимость просто повторно инициализировать переменную в каждом подклассе просто сделает инициализацию в базовом классе бессмысленной.
Я был бы очень признателен за любую помощь.
Ответ №1:
То, что вы ищете, — это интерфейсы или абстрактные / виртуальные функции. Вообще говоря, существует два метода:
public abstract class Character : MonoBehaviour
{
public float m_Health { get; protected set; }
protected abstract float DefaultHealth { get; }
void Awake()
{
m_Health = DefaultHealth;
}
}
public class Enemy : Character
{
protected override float DefaultHealth { get { return 10; } }
}
(Используйте виртуальные функции вместо абстрактных, если должна быть базовая реализация, а переопределение необязательно.) Приведенный выше шаблон используется, когда вся логика является общей, но маленькие биты задаются по-разному в подклассах. Большие функции в базовом классе вызывают маленькие функции, которые могут быть указаны в подклассах.
Второй метод предназначен для случаев, когда классы выглядят одинаково для внешнего мира, но функционируют по-разному на фундаментальном уровне:
public interface ILiving
{
float Health { get; }
}
public class Character : ILiving
{
// implement health as a normal variable
public float Health { get; protected set; }
}
public class OldMan : ILiving
{
// implement health based on time until death at 2020
public float Health { get { return (2020-DateTime.Now.Year)/20; } }
}
В этом случае оба типа имеют работоспособность, но логика, по которой они работают, различна. Для внешнего мира они выглядят одинаково, но они настолько разные, что у них не должно быть общей логики.
Обратите внимание, что в Unity все может запутаться. Поскольку мы вынуждены наследовать от MonoBehaviour
(а в C # отсутствует множественное наследование), мы можем иногда не использовать наследование там, где хотелось бы. В этих случаях мы можем имитировать наследование, используя интерфейсы, явную реализацию интерфейса (разумное факсимиле защищенных функций) и методы расширения. (Класс, который определяет методы расширения, будет играть роль базового класса.) В общем, это возникает, когда классы хотят быть частью двух иерархий классов (на основе двух несовместимых наборов функций). В игре броня, оружие и заклинания могут захотеть участвовать в системе обновления. Броня и оружие являются частью иерархии классов снаряжения, а заклинания — нет. Таким образом, соответствующие данные преобразуются в функции интерфейса, а общий код определяется как методы расширения (поскольку броня и заклинания не имеют общего базового класса, за исключением MonoBehaviour
).
Комментарии:
1. Спасибо за эту деталь!
Ответ №2:
В контексте Unity я не уверен, что то, о чем вы спрашиваете, действительно работает таким образом.
Лучший способ добиться этого — создать игровой объект (персонажа), который вы можете копировать и настраивать по мере необходимости (FriendlyCharacter / EnemyCharacter) и просто изменить теги в Unity, чтобы убедиться, что они взаимодействуют с другими объектами должным образом.
Вообще говоря, в Unity метки «Public» или «Private» просто определяют, можно ли изменять значения вне этого конкретного скрипта (т. Е. В Инспекторе или другими скриптами).).
РЕДАКТИРОВАТЬ: кроме того, в качестве более широкого примечания к наследованию, изменение любой унаследованной переменной внутри объекта класса (или подкласса) никогда не изменит эту переменную для всех объектов, созданных из более высокого класса, и это также не то, что означает «общедоступный» или «Частный».
Комментарии:
1. Спасибо. Я буду иметь это в виду. Я немного устал от этих вещей и относительно новичок в Unity. Итак, я бы создал игровые объекты персонажей, тогда как мне связать уникальный сценарий дружественного / вражеского с этими общими игровыми объектами?
2. Вы можете сделать этот скрипт подклассом вашего символьного скрипта, как вы предлагали ранее. В C # вы делаете это с помощью » : «. В Unity вы можете увидеть, что это обычно отображается как «YourScriptName: MonoBehavior», когда нет родительского класса, который затем вы бы создали «FriendlyCharacterScript : CharacterScript» и т. Д. (т.Е. Подкласс: родительский класс»)
3. почему бы вам не создать getter и setters в базовом классе для получения объектов enemy и character, иначе я не знаю, как это сделать.