Возникли проблемы с правильным дизайном шаблона - PullRequest
0 голосов
/ 06 января 2020

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

Существует структура World, которая владеет коллекцией Object объектов-черт. Мы можем думать о них как о движущихся физических объектах в игровом движке. World отвечает за вызов update и draw для каждого из них во время каждого игрового тика.

Структуре World также принадлежит коллекция объектов Event trait. Каждое из этих событий инкапсулирует произвольный фрагмент кода, который изменяет objects во время игровых тиков.

В идеале, объект черты Event имеет единственный метод do_event, который не принимает аргументов, которые можно вызвать на World во время каждого игрового тика. Проблема в том, что конкретный Event должен иметь изменяемые ссылки на объекты, которые он изменяет, но эти объекты принадлежат World. Мы могли бы World передавать изменяемые ссылки на необходимые объекты, когда он вызывает do_event для каждого события, но как узнать, какие объекты следует передавать каждому объекту события?

Если бы это было C ++ или Python, при создании конкретного Event, я передаю цель события конструктору, где оно будет сохранено и затем использовано во время do_event. Очевидно, что это не работает в Rust, потому что все цели принадлежат World, поэтому мы не можем хранить изменяемые ссылки в другом месте.

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

Набросок моего кода:

trait Object {
    fn update(&mut self);
    fn draw(&self);
}

trait Event {
    fn do_event(&mut self);
}

struct World {
    objects: Vec<Box<dyn Object + 'a>>,
    events: Vec<Box<dyn Event + 'a>>,
}

impl World {
    fn update(&mut self) {
        for obj in self.objects.iter_mut() {
            obj.update();
        }
        for evt in self.events.iter_mut() {
            evt.do_event();
        }
    }
    fn draw(&mut self) { /*...*/ }
}

struct SomeEvent<'a, T: Object> {
    target: &'a mut T,
}

impl<'a, T: Object> Event for SomeEvent<'a, T> {
    fn update(&self) {
        self.target.do_shrink(); // need mutable reference here
    }
}

Я знаю, что RefCell позволяет несколько объекты для получения изменяемых ссылок. Возможно, это то направление, в котором я должен go. Однако, основываясь на том, что я узнал из книги Rust , я понял, что RefCell нарушает некоторые основные идеи Rust, вводя небезопасный код и циклические ссылки. Я думаю, мне просто интересно, есть ли какой-то другой очевидный шаблон проектирования, который больше соответствовал идиоматическому c способу делать вещи.

1 Ответ

1 голос
/ 08 января 2020

После прочтения комментариев к вопросу и просмотра выступления RystConf 2018 kyren (спасибо trentcl ) я понял, что ОО-подход к моему игровому движку в корне несовместим с Rust (или в хотя бы довольно сложно).

После работы над этим в течение одного дня я настоятельно рекомендую посмотреть опубликованное видео и затем использовать библиотеку specs (реализация системы ECS, упомянутой user2722968).

Надеюсь, это поможет кому-то еще в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...