#c# #class
Вопрос:
У меня есть класс покемонов, который является абстрактным классом. Я хочу создать кучу покемонов, которые ведут себя аналогично. В настоящее время в нем есть поля: Имя вида и здоровье. У меня есть несколько классов покемонов, таких как Бульбасавр, Венузавр, Чармелеон и т. Д. Каждый из них имеет разное статическое значение для данного конкретного типа покемонов. Я создаю экземпляры этих покемонов, потому что не все экземпляры одного и того же типа покемонов будут точно одинаковыми. У них будут разные ходы, и я могу добавить функции, такие как псевдонимы или уровни.
abstract class Pokemon
{
string speciesName;
int health;
bool Fainted
{
get
{
if (health == 0)
{
return true;
}
else
{
return false;
}
}
}
public Pokemon(string speciesName, int health)
{
}
public void TakeDamage(int damage)
{
health -= damage;
}
}
class Bublasaur :Pokemon
{
Move[] possibleMoves = {new Tackle() };
static int health = 60;
static string speciesName = "Bublasaur";
Bublasaur() :base(speciesName, health)
{
}
}
Однако у меня также есть класс Move, который является абстрактным и имеет производные классы, которые являются движениями, такими как Огнемет и Водяной пистолет. У них есть только статические поля.
abstract class Move
{
int damage;
string name;
public Move(int damage, string name)
{
this.damage = damage;
this.name = name;
}
}
class Tackle :Move
{
static int damage = 20;
static string name = "Tackle";
public Tackle():base(damage,name)
{
}
}
class Ember: Move
{
static int damage = 30;
static string name = "Ember";
public Ember() : base(damage, name)
{
}
}
Поскольку у меня есть базовый класс ходов, я не могу сделать класс статичным, так как статические классы могут быть производными только от класса объектов. Однако создание экземпляра каждого хода для прикрепления к каждому созданному мной покемону кажется не очень интуитивным. Есть ли способ, которым я могу реализовать это лучше?
Комментарии:
1. Можете ли вы привести пример того, как
Pokemon
происходит вызовMove
класса? Как он функционирует?2. Если бы это был я, я бы, вероятно, создал свойства только для чтения с именем
Damage
иName
вMove
базовом классе. В подклассах (напримерTackle
) я бы сделал это следующим образом:const int damage = 20;
const string name = "Tackle";
и затем использовал бы их при вызове конструктора базового класса. Aconst
-это в основном символическое имя, связанное с неизменяемым значением. Оставив все как есть (с абстрактным базовым классом и подклассами), вы сможете реализовать настраиваемое поведение в подклассах, если вы решите это сделать.3. «Однако создание экземпляра каждого хода для прикрепления к каждому созданному мной покемону кажется не очень интуитивным». Почему ты так думаешь? На самом деле, я бы избавился от всей вашей иерархии наследования для
Move
объектов , которые могут быть доступны через статические свойства в классе, а также иметьTackle
иEmber
бытьMove
объектами, к которым можно получить доступ через статические свойства вMove
классе. напримерMove[] possibleMoves = { Move.Tackle };
4. Возможно, вам захочется прочитать посты Эрика Липперта » Волшебники и воины «, в которых он обсуждает трудности моделирования логики и правил игры на C#.
Ответ №1:
Tackle
и Ember
не расширяйте поведение Move
, поэтому иерархия наследования кажется излишней.
У вас может быть один класс Move
, содержащий статические ссылки на различные экземпляры:
class Move
{
int damage;
string name;
private Move(int damage, string name)
{
this.damage = damage;
this.name = name;
}
public static readonly Move Tackle = new Move(20, "Tackle");
public static readonly Move Ember = new Move(30, "Ember");
// Other moves..
}
Ответ №2:
Перемещение — это действие, которое может выполнять покемон. Поэтому я думаю, что будет лучше, если он будет определен как интерфейс и что они не должны быть статичными.
Затем вы можете создавать такие движения, как Снасть, Уголек и т.д.
публичный интерфейс iMove { публичный ввод { get; } публичное имя строки { get; } }
public class Tackle : IMove
{
public Tackle()
{
}
//You can still set defaults per class
public int Damage { get; } = 30;
public string Name { get; } = "Tackle";
}
Я не использую сеттер, так как предполагаю, что вы на самом деле не хотите, чтобы эти значения менялись после инициализации. если вы это сделаете, вы можете просто добавить его.
Я бы также использовал перечисление для названия хода (и покемона), чтобы у вас не было проблем с прописными/строчными буквами, орфографическими ошибками и т. Д.
Я бы также посмотрел на использование фабрики для создания покемонов и, возможно, даже ходов (если вы еще этого не сделали).
Я признаю, что не знаю об игре и персонажах в Pokemon, так что, возможно, я неправильно понимаю, но я не понимаю, почему в вашем Покемоне это здоровье должно быть статичным, так как это означает, что все экземпляры этого Покемона будут иметь одинаковый уровень здоровья. Может быть, вы имеете в виду, что для самого покемона должен быть Синглтон?