6

我还有一个问题希望总结一下我的想法。

假设我有以下 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];
};

类游戏引擎:

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

GameBoard 的 playTurn 函数会使用参数“board”调用玩家的 move 函数对您来说是否合理?我需要这样做以便在棋盘数据成员中标记玩家已经改变了他的位置。是否遵守 OOP 的基本规则?

谢谢大家,辛迪加!

4

4 回答 4

4

是的,在这种情况下,这似乎是合理的(“在这种情况下”我的意思是“考虑到我能猜到你GameEngineBoard类的语义以及它们的关联/聚合关系的性质”):

  1. 与其使用原始指针,不如使用智能指针将Board对象保存在GameEngine. unique_ptr在这种情况下可能是您想要的,因为所有其他别名似乎只是观察者,并且 board 对象的生命周期绑定到GameEngine对象之一。但是,如果需要共享所有权,请选择shared_ptr. 尽量不要使用原始指针 ,newdelete,因为它们会导致代码错误;
  2. 您仍然需要在Board类的接口上提供公共函数来修改板,因为Player将无法访问其私有成员变量(并且board恰好是一个)。
  3. 而不是#defines,使用constexpr值作为板的大小(如果您使用的是 C++11)。您可能还想考虑使用Boost.MultiArray创建安全的二维 C 样式数组。
于 2013-01-28T21:50:37.140 回答
3

你的方法很好。GameEngine 将用作您游戏的某种控制器。多亏了它,您可以过滤玩家动作,检查这种动作是否可能,或者在特定玩家操作的情况下做其他事情。

其次,有了这个解决方案,您不必将玩家连接到特定的棋盘,这扩展了您的其他选项的可能性,例如在棋盘之间轻松转移玩家。我认为你的方式很好:)

于 2013-01-28T21:50:27.370 回答
1

您必须考虑您的应用程序将如何更改,以及您想引入哪些功能。从这段代码看起来还不错,但是当您引入新功能时会是这样吗?

其他解决方案是放入玩家仅移动逻辑,它将更新其位置,然后您的 GameEngine 将根据所有玩家当前位置更新棋盘条目。想象一段时间后您将希望实施碰撞检测,然后在每个玩家更新其位置或运动后,碰撞检测将发生并纠正这些运动,并且只有稍后您的棋盘上才会正确更新。

于 2013-01-28T21:50:36.790 回答
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.

于 2013-01-29T08:08:44.090 回答