Я создаю видеоигру, и в этой видеоигре есть разные классы. Каждый класс имеет ту же структуру данных, что и любой другой класс, но разные значения. Например, класс имеет 3 элемента: имя класса, начальные очки здоровья и путь к изображению класса.
Как лучше всего делать что-то подобное?
Лучше всего создать класс, а затем создать экземпляр для каждого игрового класса с соответствующим значением.
Пояснительный пример:
public class InGameClass {
public string className;
public int startingHP;
public string picturePath;
public InGameClass(string newClassName, int newStartingHP, string newPicturePath) {
className = newClassName;
startingHP = newStartingHP;
picturePath = newPicturePath;
}
}
И затем я создаю класс, который получает все экземпляры класса
public class InGameClasses {
public InGameClass Mage = new InGameClass("Mage", 90, "Resources/Class/Mage");
public InGameClass Warrior= new InGameClass("Warrior", 100, "Resources/Class/Warrior");
}
Вместо хранения имен классов вы можете создавать классы с этим именем, а затем сравнивать типы классов вместо их имен в виде строк.
public abstract class Character
{
public abstract int StartingHP { get; }
public abstract string PicturePath { get; }
}
public class Mage : Character
{
public override int StartingHP => 90;
public override string PicturePath => "Resources/Class/Mage";
}
public class Warrior : Character
{
public override int StartingHP => 100;
public override string PicturePath => "Resources/Class/Warrior";
public void Attack(Character other); // Method specific to warriors.
{
...
}
}
Обратите внимание, что я создал базовый класс abstract
. Это значит, что писать нельзя new Character()
; однако вы можете, например, создать список персонажей, содержащий магов и воинов.
Производные классы вынуждены переопределить унаследованные абстрактные члены и предоставить конкретную реализацию.
List<Character> characters = new();
characters.Add(new Mage());
characters.Add(new Warrior());
Вы можете проверить тип персонажа следующим образом:
if (character is Warrior warrior) {
warrior.Attack(someCharacter);
}
Поместите в базовый класс методы для того, что могут делать все персонажи. Например, public virtual void Walk() { ... }
. Сделав его виртуальным, вы сможете переопределить его в классе-потомке, например. если персонаж ходит не так, как другие. Разные персонажи автоматически будут вести себя по-разному (см.: Полиморфизм).
Преимущество этого подхода (иерархии классов) заключается в том, что вы можете очень легко реализовать различное поведение для разных персонажей.
См. также:
Альтернативы (в ответ на комментарий):
Вы можете использовать константы , которые по умолчанию являются статическими, статические поля только для чтения или свойства только для получения. Проблема, однако, в том, что статические члены не могут быть унаследованы. Вы также можете использовать Singleton, который сочетает в себе статический доступ с возможностью определения иерархии классов.
Вы также можете использовать свойства только для получения, реализующие Статический абстрактный интерфейс. Это самая продвинутая техника. Он позволяет вам добавлять «константы» (реализованные как статические свойства, предназначенные только для получения) к каждому конкретному классу символов структурированным способом, т. е. путем применения определенного и четко определенного набора свойств.
Вы также можете сохранить структуру констант в словаре по типу символов.
Шаблон Абстрактная фабрика также может оказаться полезным.
Спасибо за ваш ответ. Дочерние элементы класса Персонаж должны представлять собой структуру данных, содержащую постоянные значения, поскольку это неизменяемые значения, которые применяются к каждому персонажу, например Магу или Воину. Есть ли способ сделать эти классы неизменяемыми или постоянными? Чтобы объяснить это лучше: могу ли я сделать что-то похожее на JSON, доступный только для чтения, который содержит всю общую информацию для игрового класса?
Поэтому я могу просто получить информацию, не создавая экземпляр нового объекта для каждого нового персонажа.
Хороший способ сделать это — использовать частный конструктор и статические значения в качестве «констант».
public class InGameClass
{
public string ClassName {get; private set; }
public int StartingHP {get; private set; }
public string PicturePath {get; private set; }
private InGameClass(string newClassName, int newStartingHP, string newPicturePath) {
ClassName = newClassName;
StartingHP = newStartingHP;
PicturePath = newPicturePath;
}
public static readonly InGameClass Mage;
public static readonly InGameClass Warrior;
static InGameClass()
{
Mage = new InGameClass("Mage", 90, "Resources/Class/Mage");
Warrior= new InGameClass("Warrior", 100, "Resources/Class/Warrior");
}
}
Здесь мы оставляем конструктор private
, чтобы больше нельзя было создавать объекты, и используем статический конструктор для создания необходимых значений и сохранения их в полях static readonly
.
Теперь вы можете использовать в своем коде InGameClass.Mage
или InGameClass.Warrior
.
Этот шаблон обычно называется типобезопасными перечислениями.
Во-первых, я бы рекомендовал не называть какую-либо концептуальную сущность в вашем проекте «классом». «Класс» в C# имеет очень конкретное значение, и его переопределение чем-либо еще никогда не может привести к путанице.