Проблема управления потоком Java

Я программирую простой двухмерный игровой движок. Я решил, как должен работать движок: он будет состоять из объектов, содержащих "события", которые будут запускаться моим основным игровым циклом, когда это необходимо.

Еще немного о структуре: каждый GameObject имеет updateEvent метод. objectList список всех объектов, которые будут получать события обновления Только объекты в этом списке имеют свой метод updateEvent, вызываемый игровым циклом.

Я пытаюсь реализовать этот метод в классе GameObject (эта спецификация - то, что я хотел бы, чтобы метод достиг):

/**
* This method removes a GameObject from objectList.  The GameObject 
* should immediately stop executing code, that is, absolutely no more
* code inside update events will be executed for the removed game object.
* If necessary, control should transfer to the game loop.
* @param go The GameObject to be removed
*/
public void remove(GameObject go)

Таким образом, если объект пытается удалить себя внутри события обновления, управление должно вернуться обратно к игровому движку:

public void updateEvent() {
    //object's update event
    remove(this);
    System.out.println("Should never reach here!");
}

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

Метод удаления

public void remove(GameObject go) {
    //add to removedList
    //flag as removed
    //throw an exception if removing self from inside an updateEvent
}

Игровой цикл

for(GameObject go : objectList) {
    try {
        if (!go.removed) {
            go.updateEvent();
        } else {
            //object is scheduled to be removed, do nothing
        }
    } catch(ObjectRemovedException e) {
        //control has been transferred back to the game loop
        //no need to do anything here
    }
}
// now remove the objects that are in removedList from objectList

2 вопроса:

  1. Правильно ли я полагаю, что единственный способ реализовать остановленную-правую часть метода удаления, как описано выше, - это создать пользовательское исключение и перехватить его в игровом цикле? (Я знаю, использование исключений для управления потоком похоже на goto, что плохо. Я просто не могу придумать другой способ сделать то, что я хочу!)

  2. Для удаления из самого списка можно удалить один объект, находящийся ниже в списке. В настоящее время я проверяю удаленный флаг перед выполнением любого кода, и в конце каждого прохода удаляю объекты, чтобы избежать одновременной модификации. Есть ли лучший, желательно мгновенный / не опросный способ сделать это?

[Редактировать] Прочитав ваши ответы, я думаю, что я изменю спецификации метода. Поведение мгновенного удаления - это то, к чему я привык работать в другом движке, но вы правы, оно не совсем соответствует тому, как работает Java. Пришло время попытаться обернуть мою голову немного другим способом мышления!

4 ответа

Решение

Почему бы просто не вернуться, то есть

public void updateEvent() { 
    //object's update event 
    remove(this); 
    return;   
    //obviously unreachable 
    System.out.println("Should never reach here!");     }

Я согласен, что исключительный подход - лучший способ реализовать метод удаления в соответствии с вашей спецификацией.

Однако, возможно, вам следует пересмотреть спецификацию. Я бы оставил решение, когда updateEvent заканчивается разработчиком. Завершение с помощью вызова remove() сбивает с толку и требует использования исключений для управления потоком. Я считаю, что вызов remove() должен только изменить состояние флага. И я не вижу реальной проблемы с зацикливанием всех объектов, проверкой удаленного флага для каждого из них.

Почему бы тебе просто:

  • Поддерживать objectList в объекте, который запускает цикл
  • Не позволяйте GameObjects иметь доступ к списку (почему они должны?)
  • Пусть функция updateEvent возвращает логическое значение. Если возвращаемое значение равно false, родительский объект удаляет этот объект из списка событий. Оператор return также служит для прекращения выполнения функции события.

Ответ @jball отличный - +1.

Другой метод, который я использовал, который работает хорошо и может быть немного чище, - это чтобы ваш метод updateEvent() возвращал логическое значение. Всякий раз, когда True возвращается из updateEvent, вы удаляете () объект.

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

Другие вопросы по тегам