Непреднамеренная репликация поведения другого объекта

1

У меня есть небольшой интересный персональный проект, в котором я перемещаю "робота" на арене коробки, если он ударяет по стене, игра окончена. Он имеет автоматический режим ходьбы, где он перемещается по арене, не нажимая стены, используя конечный автомат. Арена печатается с использованием Strings и Java Swing UI, и все контролируется событиями качания.

Я пытаюсь заставить его стрелять. Поскольку поведение пули довольно похоже на поведение робота, я создал объект класса Super Class с похожими методами и атрибутами (например, координаты местоположения и направление), а затем расширил класс робота и пули.

Проблема в том, что когда я перемещаюсь (изменяю атрибут позиции робота), позиция маркера тоже изменяется. Мой пользовательский интерфейс показывает текущую позицию обоих объектов, и когда я перемещаю робота, пуля перемещается. Положение пули предназначалось для установки только при нажатии кнопки съемки. Кнопка съемки устанавливает положение пули роботу, а затем перемещает пулю в том же направлении, пока она не попадет в рамки.

То, что происходит, когда я стреляю, - это то же самое, что и движение робота: когда пуля перемещается, робот перемещается, суицируя в стене пулю.

Это похоже на тот же объект, но я уверен, что я вызываю метод move, используя правильный объект.

Как я уже сказал, я сделал версию MCVE ниже:

Суперкласс класса Entity

public abstract class Entity {
    protected int[] position = new int[2];
    protected char direction;

    public int getPosI() {
        // System.out.println("i: " + position[0]);
        return position[0];
    }

    public int getPosJ() {
        // System.out.println("j: " + position[1]);
        return position[1];
    }

    public int[] getPosition() {
        return position;
    }

    public void setPosition(int[] position) {
        this.position = position;
    }

    public char getDirection() {
        return direction;
    }

    public void setDirection(char direction) {
        this.direction = direction;
    }

    public boolean move() {

        switch (direction) {
        case 'u':
            if (this.position[0] != 0) {
                this.position[0]--;
                return true;
            } else
                return false;

        case 'r':
            if (this.position[1] != 3) {
                this.position[1]++;
                return true;
            } else
                return false;

        case 'd':
            if (this.position[0] != 3) {
                this.position[0]++;
                return true;
            } else
                return false;

        case 'l':
            if (this.position[1] != 0) {
                this.position[1]--;
                return true;
            } else
                return false;

        default:
            return false;
        }
    }
}

Класс робота

public class Robot extends Entity {


    public Robot(int[] position) {
        super();
        this.position = position;
        this.direction = 'u';

    }

    public void resetPos() {
        this.position[0] = this.position[1] = 1;
    }

}

Класс пули

public class Bala extends Entity{


    public Bala(int[] position, char direction) {
        this.position = position;
        this.direction = direction;
    }
}

Основной класс

public class Main {
    private static final int[] start = new int[] { 1, 1 };

    public static void main(String[] args) {
        Robot robot = new Robot(start);
        robot.setDirection('d');
        Bala bala = new Bala(robot.getPosition(), robot.getDirection());

        for (int i = 0; i < 3; i++) {
            System.out.println("MOVING ONLY THE ROBOT...");
            robot.move();

            System.out.println("Robot position: "
                    + String.valueOf(robot.getPosI()) + ", "
                    + String.valueOf(robot.getPosJ()));
            System.out.println("Bullet position: "
                    + String.valueOf(bala.getPosI()) + ", "
                    + String.valueOf(bala.getPosJ()));


        }

        System.out.println("but the bullet moves to!!!");

        System.out.println("reseting position of robot and lets see what happens to bullet...");

        robot.resetPos();

        System.out.println("Robot position: "
                + String.valueOf(robot.getPosI()) + ", "
                + String.valueOf(robot.getPosJ()));
        System.out.println("Bullet position: "
                + String.valueOf(bala.getPosI()) + ", "
                + String.valueOf(bala.getPosJ()));

        System.out.println("bullet moves too...");
    }
}

ВАЖНОЕ ВЕЩАНИЕ: Когда я перемещаю робота с помощью кнопки R (сброс), он также перемещает пулю. Это означает, что пуля движется, даже если она не использует метод перемещения !!!

Итак, в качестве прямого вопроса по запросу: "Объект робота реплицирует изменения своего атрибута положения на позицию пули и наоборот, как остановить это поведение?"

  • 0
    Чтобы быстрее получить помощь, опубликуйте MCVE ( пример минимальной полной проверки).
  • 0
    Кстати - вау! 4 некомпилируемых фрагмента кода, 3 !!! и множество слов, а не один «?». У вас есть вопрос?
Показать ещё 5 комментариев
Теги:
object
attributes
swing

1 ответ

1
Лучший ответ

Оба робота и Балы разделяют один и тот же массив int, и в этом и заключается ваша проблема: здесь присутствует код вины:

Bala bala = new Bala(robot.getPosition(), robot.getDirection());

Одно из возможных решений: getPosition() возвращает копию массива, или другое - создать новый массив в конструкторе, который копирует значения в параметре.


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

public class Main {
   private static final int[] start = new int[] { 1, 1 };

   public static void main(String[] args) {
      Robot robot = new Robot(start);
      robot.setDirection('d');
      Bala bala = new Bala(robot.getPosition(), robot.getDirection());

      for (int i = 0; i < 3; i++) {
         System.out.println("MOVING ONLY THE ROBOT...");
         robot.move();

         System.out.println("Robot position: "
               + String.valueOf(robot.getPosI()) + ", "
               + String.valueOf(robot.getPosJ()));
         System.out.println("Bullet position: "
               + String.valueOf(bala.getPosI()) + ", "
               + String.valueOf(bala.getPosJ()));

      }

      System.out.println("but the bullet moves to!!!");

      System.out.println("reseting position of robot and lets see what happens to bullet...");

      robot.resetPos();

      System.out.println("Robot position: " + String.valueOf(robot.getPosI())
            + ", " + String.valueOf(robot.getPosJ()));
      System.out.println("Bullet position: " + String.valueOf(bala.getPosI())
            + ", " + String.valueOf(bala.getPosJ()));

      System.out.println("bullet moves too...");
   }
}

abstract class Entity {
   protected int[] position = new int[2];
   protected char direction;

   public Entity(int[] position) {
      System.arraycopy(position, 0, this.position, 0, position.length);
   }

   public Entity(int[] position, char direction) {
      this(position);
      this.direction = direction;
   }

   public int getPosI() {
      // System.out.println("i: " + position[0]);
      return position[0];
   }

   public int getPosJ() {
      // System.out.println("j: " + position[1]);
      return position[1];
   }

   public int[] getPosition() {
      return position;
   }

   public void setPosition(int[] position) {
      this.position = position;
   }

   public char getDirection() {
      return direction;
   }

   public void setDirection(char direction) {
      this.direction = direction;
   }

   public boolean move() {

      switch (direction) {
      case 'u':
         if (this.position[0] != 0) {
            this.position[0]--;
            return true;
         } else
            return false;

      case 'r':
         if (this.position[1] != 3) {
            this.position[1]++;
            return true;
         } else
            return false;

      case 'd':
         if (this.position[0] != 3) {
            this.position[0]++;
            return true;
         } else
            return false;

      case 'l':
         if (this.position[1] != 0) {
            this.position[1]--;
            return true;
         } else
            return false;

      default:
         return false;
      }
   }
}

class Robot extends Entity {

   public Robot(int[] position) {
      super(position, 'u');

   }

   public void resetPos() {
      this.position[0] = this.position[1] = 1;
   }

}

class Bala extends Entity {

   public Bala(int[] position, char direction) {
      super(position, direction);
   }
}

В стороне, вы, вероятно, не захотите использовать символы для представления направления, а скорее перечисления Direction, так как это добавит безопасность типа компиляции в вашу программу.

  • 0
    Я использовал метод copy () для этого, это лучший способ? Кроме того, я не понимаю, почему это произошло, у каждого объекта должны быть свои атрибуты, если это не разрушает святую цель Суперкласса ... Это происходит только с массивами?
  • 0
    @Diedre: Нет, в массивах нет ничего волшебного, но это происходит потому, что вы передаете ссылочный тип в качестве параметра, и вам захочется изучить, что это значит. Хотя у каждого объекта будет своя собственная переменная массива, обе эти переменные будут ссылаться на один и тот же объект массива. Эта концепция очень важна и лежит в основе программирования на Java.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню