У меня есть еще один вопрос, который, я надеюсь, подытожит мои мысли.
Предположим, у меня есть следующие 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»?
Мне нужно сделать это, чтобы отметить в поле данных участника, что игрок изменил свою позицию.
Соблюдать ли основные правила ООП?
Спасибо вам всем,
Синдикатор!
Да, в этом случае это кажется разумным (под «в данном случае» я имею в виду «, учитывая то, что я могу догадаться о семантике вашего GameEngine
а также Board
классы и характер их ассоциации / агрегации отношений «):
Board
объект в GameEngine
, unique_ptr
это, вероятно, то, что вы хотите в этом случае, потому что все другие псевдонимы кажутся просто наблюдателями, и время жизни объекта доски связано с одним из GameEngine
объект. Однако, если необходимо совместное владение, выберите shared_ptr
, Просто старайтесь не использовать сырые указатели, new
, а также delete
потому что они приводят к ошибочному коду;Board
класс для изменения доски, потому что Player
не сможет получить доступ к своим закрытым переменным-членам (и board
бывает один).#define
s, использовать constexpr
значения для размеров платы (если вы используете C ++ 11). Вы также можете рассмотреть Boost.MultiArray для создания безопасный двумерные массивы в стиле CВаш подход в порядке. GameEngine будет использоваться в качестве контроллера вашей игры. Благодаря этому вы можете, например, фильтровать движения игрока, проверять, возможен ли этот тип движения, или делать что-то другое в случае определенных операций игрока.
Во-вторых, благодаря этому решению вам не нужно подключать игрока к определенной доске, что расширяет ваши возможности других опций, таких как легкое перемещение игроков между досками. Я думаю, что вы на хорошем пути 🙂
Вы должны подумать о том, как изменится ваше приложение, и какие функции вы хотели бы представить. Из этого кода это выглядит нормально, но будет ли это выглядеть так, когда вы представите новые функции?
Другое решение состоит в том, чтобы ввести в игру только логику движения, она обновит свои позиции, а затем ваш GameEngine обновит записи на доске, основываясь на текущих позициях всех ваших игроков. Представляя, что через некоторое время вы захотите реализовать обнаружение столкновений, затем после того, как каждый игрок обновит свои позиции или движения, обнаружение столкновений будет иметь место и исправит эти движения, и только позже на вашей доске будет правильно обновлено.
Многое уже сказано, но, если можно, добавлю.
Проходя 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
(или как то так).
Тем не менее, я бы сказал, что гораздо лучше следовать общей идее игрового движка:
GameEngine
позвоню draw()
прохождение Board
в качестве цели, которую могут использовать объекты.Я не говорю, что для простой архитектуры это необходимо, но в дольше управлять им гораздо проще, чем иметь дело с неприятными вещами, которые каждый из Player
подобные классы могут сделать для Board
,