Java Inheritance / OOP - вызов метода, специфичного для дочернего типа, с указателем на родительский элемент - PullRequest
0 голосов
/ 20 ноября 2011

Я пишу игровой движок на Java для игр для Android, и мой движок обрабатывает обнаружение столкновений для разных форм.Каждая фигура является собственным классом (квадрат, круг и т. Д.) И происходит от общего абстрактного родительского элемента Collidable.У меня есть класс менеджера физики, который в основном проверяет, сталкивается ли какой-либо из существующих в игре объектов с другим, а затем выполняет соответствующие действия при обнаружении столкновения.Проверка на столкновение реализована внутри каждого дочернего класса физической формы, как показано в коде ниже.

public abstract class Collidable
{
}

public class Square extends Collidable
{
    public boolean Collides(Square) {...}
    public boolean Collides(Circle) {...}
    public boolean Collides(Triangle) {...}
}

public class Circle extends Collidable
{
    public boolean Collides(Square) {...}
    public boolean Collides(Circle) {...}
    public boolean Collides(Triangle) {...}
}

public class Triangle extends Collidable
{
    public boolean Collides(Square) {...}
    public boolean Collides(Circle) {...}
    public boolean Collides(Triangle) {...}
}

public class PhysicsMgr
{
    public boolean Collides(Collidable p1, Collidable p2)
    {
        return p1.Collides(p2);
        // This obviously won't work because there is no Collides
        // method in Collidable. I want it to somehow call the child's
        // method and pass in p2 as its child type rather than as
        // a parent. Or somehow do this:
        return (p1.child()).Collides(p2.child());
            // I know that obviously nothing like this exists.
    }
}

Мне известно об "instanceof", и я действительно не хочу проверять дочерний тип p1 и p2 по сравнению скаждая форма столкновения у меня есть.Должен быть лучший способ.Я ищу или обходной путь для моей текущей проблемы, или предпочтительно перепроектирование моей текущей системы обнаружения столкновений, чтобы полностью избежать этой проблемы.

Спасибо!

Ответы [ 3 ]

3 голосов
/ 20 ноября 2011

Вы должны прочитать о шаблоне посетителей

1 голос
/ 20 ноября 2011

Для начала я бы не сделал Collidable абстрактным классом.Хотя для этого есть, вероятно, веские аргументы;мне просто кажется, что это ситуация, когда многие объекты могут сталкиваться друг с другом.

Итак, я бы порекомендовал вот что:

// Assuming you're working in 2 dimensions
public class Coordinates {

  public Coordinates(float x, float y) {
     // etc etc etc
  }
}

public interface ICollidable {

  // Using unusually long name to illustrate point,
  // but feel free to rename.
  public int getMaxDistanceFromCenterOfMass(Coordinates unitVector);
  public Coordinates getCenterOfMass();
}

И затем, для Square, Triangle и Circle, я бы реализовал интерфейс.

public class Square implements ICollidable {

  @Override
  public int getMaxDistanceFromCenterOfMass(Coordinates unitVector) {
    // Must declare and initialize
    return this.lengthOfSide;
  }

  @Override
  public Coordinates getCenterOfMass() {
    return this.centerOfMass;
  }
}

public class Circle implements ICollidable {

  @Override
  public int getMaxDistanceFromCenterOfMass(Coordinates unitVector) {
    // Must declare and initialize
    return this.radius;
  }

  @Override
  public Coordinates getCenterOfMass() {
    return this.centerOfMass;
  }
}

public class Triangle implements ICollidable {

  @Override
  public int getMaxDistanceFromCenterOfMass(Coordinates unitVector) {
    // Must declare and initialize
    return this.lengthOfSide;
  }

  @Override
  public Coordinates getCenterOfMass() {
    return this.centerOfMass;
  }
}

Затем в вашей PhysicsMgr ...

public class PhysicsMgr {

  public boolean Collides(ICollidable p1, ICollidable p2) {
    Coordinates cm1 = p1.getCenterOfMass();
    Coordinates cm2 = p2.getCenterOfMass();

    int length = Math.sqrt(Math.pow(cm1.x - cm2.x, 2) + Math.pow(cm1.y - cm2.y, 2))

    // It is a misnomer to use coordinates as a unit vector, but if I defined a 
    // UnitVector class, it would be exactly the same with the exception of
    // the class name for this situation.
    Coordinates unitVector = new Coordinates((cm1.x - cm2.x)/length, (cm1.y - cm2.y)/length);

    int collisionDistance1 = p1.getMaxDistanceFromCenterOfMass(unitVector);
    int collisionDistance2 = p2.getMaxDistanceFromCenterOfMass(unitVector);

    return (length - collisionDistance1 - collisionDistance2) <= 0;
  }
}

Единственное важное замечание здесьчто использование maxDistance от центра масс в буквальном смысле даст вам только приближение для квадрата и треугольника.Точнее, вам придется объявить некоторую ориентацию, тета и вычислить расстояние от центра масс объекта до края вдоль единичного вектора (что будет сложно, но точно).

Другойчто приятно, так это то, что он позволяет вам легко добавлять другие объекты, которые могут встречаться, когда ваш движок становится более сложным.Это также делает так, что ни один из объектов не должен знать друг о друге.

Я был физическим ТА в течение 3 лет, и именно так я получил свое первое знакомство с программированием.Если вы заинтересованы в дополнительной работе, вот ссылка на книгу, которую мы использовали: http://matterandinteractions.org/ Это здорово для программистов, потому что она учит физике, используя примеры кодирования на python (в частности, vpython http://vpython.org/)Так что это было бы очень хорошим справочником для программирования по физике.

0 голосов
/ 20 ноября 2011
public boolean Collides(Square) {...}
public boolean Collides(Circle) {...}
public boolean Collides(Triangle) {...}

Вам потребуются отдельные реализации для различных комбинаций фигур (я думаю, что общего алгоритма нет). Так что в какой-то момент будет необходимость позвонить instanceof. Я боюсь, что использование абстрактного метода или метода интерфейса public boolean Collides(Collidable) здесь не поможет, и то, что вы сейчас имеете, не может быть значительно улучшено. Это учебный случай ограничений ООП, потому что эти методы обнаружения столкновений не могут быть аккуратно привязаны ни к одному из классов фигур, они живут где-то посередине, в чем-то вроде вашего менеджера по физике.

...