C ++ ООП дизайн — передача данных в другие классы — это разумно?

У меня есть еще один вопрос, который, я надеюсь, подытожит мои мысли.

Предположим, у меня есть следующие 3 класса:

Класс игрока:

class Player {
private:
int positionX, positionY;
public:
void move(Board& b) {
// player changes its position on the board(move)
b.removeCharFromBoard(positionX, positionY);
positionX++;
positionY++;
// 'P' indicates a Player in the Board....
b.insertCharToBoard(positionX, positionY, 'P');
}
};

классная доска:

class Board {
private:
// BOARD_C and BOARD_R are both "#define ..." for some integer number.
char board[BOARD_C][BOARD_R];
};

Класс GameEngine:

class GameEngine {
private:
Board* board;
public:
void playTurn(const Player& p) {
p.move(board);
}
};

Вам кажется разумным, что функция playTurn в GameBoard будет вызывать функцию перемещения игрока с параметром «board»?
Мне нужно сделать это, чтобы отметить в поле данных участника, что игрок изменил свою позицию.
Соблюдать ли основные правила ООП?

Спасибо вам всем,
Синдикатор!

6

Решение

Да, в этом случае это кажется разумным (под «в данном случае» я имею в виду «, учитывая то, что я могу догадаться о семантике вашего GameEngine а также Board классы и характер их ассоциации / агрегации отношений «):

  1. Лучше использовать умный указатель, чем необработанный указатель для хранения Board объект в GameEngine, unique_ptr это, вероятно, то, что вы хотите в этом случае, потому что все другие псевдонимы кажутся просто наблюдателями, и время жизни объекта доски связано с одним из GameEngine объект. Однако, если необходимо совместное владение, выберите shared_ptr, Просто старайтесь не использовать сырые указатели, new, а также deleteпотому что они приводят к ошибочному коду;
  2. Вам все еще нужно предоставить публичные функции на интерфейсе Board класс для изменения доски, потому что Player не сможет получить доступ к своим закрытым переменным-членам (и board бывает один).
  3. Скорее, чем #defines, использовать constexpr значения для размеров платы (если вы используете C ++ 11). Вы также можете рассмотреть Boost.MultiArray для создания безопасный двумерные массивы в стиле C
4

Другие решения

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

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

3

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

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

1

Многое уже сказано, но, если можно, добавлю.

Проходя Board (будь то private или нет) Player не плохо как таковой, и такой дизайн используется в нескольких архитектурах (код взят из SFML 2.0):

void Sprite::draw(RenderTarget& target, RenderStates states) const
{
if (m_texture)
{
states.transform *= getTransform();
states.texture = m_texture;
target.draw(m_vertices, 4, Quads, states);
}
}

RenderTarget твой Board, Эта вещь, чтобы понять здесь, что вы будете оперировать Board только используя свой открытый интерфейс (к которому у вас есть доступ). В приведенном выше коде, draw() это метод, который используется на target заставить его нарисовать что-то.

Вся эта идея передачи внутреннего объекта в класс более высокого уровня (например, Player) можно интерпретировать как мост OO шаблон, где может быть несколько реализаций интерфейса Board и несколько классов могут реализовать IBoardManipulator (или как то так).

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

  1. Зарегистрировать сущности игры (в данном случае игрока)
  2. Захватить вход игрока
  3. дайджест & реагировать на вход игрока (запрос перемещения игрока)
  4. Обработка логики игры (проверьте, может ли игрок переместиться в указанное место, и если да, переместите его)
  5. Для каждого зарегистрированного лица GameEngine позвоню draw() прохождение Board в качестве цели, которую могут использовать объекты.
  6. Повторите с шага 2

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector