Вложены ли if/else, переключатели или что-то более эффективное для RPG-боя?
Я разрабатываю пошаговую ролевую игру в java для телефонов Android, и в настоящее время я пытаюсь выяснить, как справляться с атаками, которые имеют дополнительные переменные, помимо повреждения. Например, я хотел бы, чтобы огненные атаки наносили дополнительно 10% урона, когда у цели был эффект горения. Я немного не уверен, как сделать это эффективным способом, и который позволит мне в будущем дополнить мою систему статуса / атаки.
Итак, вот мои мысли о том, как я могу это сделать:
Серия операторов if / else или переключателей
switch (status) { case burned: if (type == fire) { damage = damage * 1.1; } break; case frozen: if (type == ice) { damage = damage * 2; } break; }
Я также мог бы использовать вложенные переключатели, если у меня есть много возможных результатов для каждого состояния.
Используйте двумерный массив с
x
Значения, являющиеся статусами иy
значения являются атаками или типами. Когда вы проверяете[x][y]
он возвращает числовое значение для изменения, которое произойдет при атаке.Burned Frozen Fire [1.1] [1] Ice [1] [2]
Хотя оба из них пока хороши, я не уверен, что это сработает в будущем. Прямо сейчас я, конечно, могу использовать комбинации, которые изменяют величину урона, но как насчет атак, которые имеют нечисловые эффекты, когда я не могу просто вернуть значение и умножить свой урон на это значение?
Будет ли возможно сгенерировать какой-то код, представляющий ситуацию, подобную:
сгорел = 1 в первой позиции, заморожен = 2 огненная атака = f во 2-й позиции, лед = i мод урона находится в 3-ей позиции
поэтому огненная атака на сожженного врага будет 1-f-1.1
,
3 ответа
Вы должны попытаться использовать полиморфизм.
Для выключателей /if-elses
Создайте интерфейс, который представляет атаки, и позвольте ему объявить единственный метод:
public interface Attack {
double doAttack(double baseDamage);
}
Затем создайте классы, которые реализуют этот интерфейс:
public class FireAttack implements Attack {
double doAttack(double baseDamage){
return 1.1 * baseDamage;
}
}
public class IceAttack implements Attack {
double doAttack(double baseDamage){
return 2 * baseDamage;
}
}
Затем вместо использования операторов switch в вашем коде сделайте что-то вроде этого:
public class Player {
private Attack mAttack;
// Somewhere in your code, you setup something like
void setFireWeapon(){
mAttack = new FireAttack();
}
// This is where the attack is taken care of
double inflictDamage() {
return mAttack.doAttack();
}
}
Это позволяет вам реализовать любой новый тип атаки, который вы можете пожелать в будущем, и просто назначить Attack mAttack
с этой новой реализацией интерфейса Attack
, Это тривиальный пример, вы можете сделать что-то гораздо более мощное, чем baseDamage * aDouble
если хочешь.
Для статуса (сгорел / заморожен)
Есть много способов реализовать состояния, такие как замороженные. Сначала вы можете использовать тот же шаблон, который я объяснил выше.
На вершине наличия Attack mAttack
член, вы также можете добавить аналогичную логику с HealthStatus mHealthStatus
или любое другое имя, которое вы предпочитаете. Тогда призыв к inflictDamage()
перенаправит mAttack
возражать против mHealthStatus
объект.
Тогда HealthStatus
класс снова будет интерфейсом,
public interface HealthStatus {
double considerAttack(Attack anAttack);
}
который будет иметь реализации различных состояний:
public class NormalStatus implements HealthStatus{
double considerAttack(Attack anAttack){
return anAttack.doAttack(); // No change here
}
}
public class FrozenStatus implements HealthStatus{
double considerAttack(Attack anAttack){
return 0; // Can't attack when froxen
}
}
public class BurnedStatus implements HealthStatus{
double considerAttack(Attack anAttack){
return anAttack.doAttack() * 2.0; // Get berserk when on fire!
}
}
Вы также можете использовать другие шаблоны. Я рекомендую вам взглянуть на шаблоны проектирования, которые решают проблемы, подобные той, с которой вы сталкиваетесь.
- См. Шаблон состояния http://en.wikipedia.org/wiki/State_pattern
- См. Шаблон стратегии http://en.wikipedia.org/wiki/Strategy_pattern
- См. Образец посетителя http://en.wikipedia.org/wiki/Visitor_pattern
Просто назвать несколько.
Ваше мышление кажется слишком линейным. Используйте объектно-ориентированные принципы для разработки своей игры. Создайте классы для ваших атак, которые расширяют общую атаку.
public abstract class Attack{
protected String attackName;
protected Double damage;
public Attack(){
attackName = "Standard";
damage = 1.0;
}
public Double getDamage(){
return damage;
}
public String getAttackName(){
return attackName;
}
}
Затем продлите:
public class FireStorm extends Attack{
public FireStorm(String attackName, Double damage){
this.attackName = attackName;
this.damage = damage;
}
@Override
public Double getDamage(Enemy target){
if(target.hasBurnEffect()){
damage *= 2.0;
} else {
damage = super.getDamage();
}
return damage;
}
}
Я не очень много знаю о масштабах вещей в вашей игре, поэтому я не могу сделать ее более наглядной. Но если вы хотите сделать свою игру гибкой и расширяемой, как вы предлагаете, тогда вы захотите использовать наследование и другие принципы объектно-ориентированного программирования.
AntonieG находится на правильном пути. Общее решение этой проблемы заключается в использовании шаблона "Разработка стратегии".
стратегия
мотивация
Есть общие ситуации, когда классы отличаются только своим поведением. Для этих случаев хорошей идеей будет выделить алгоритмы в отдельных классах, чтобы иметь возможность выбирать разные алгоритмы во время выполнения.
умысел
Определите семейство алгоритмов, инкапсулируйте каждый и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.
Реализация
http://www.oodesign.com/strategy-pattern.html
Также взгляните на следующие ссылки.