假设有一个游戏。有一个地图类和一个玩家类。地图存储字段和字段存储播放器。 这将是一个在OOP中正确的方法。当负责玩家行走的方法是Player :: walk或Map :: playerWalk?
时关于第一个例子(Player :: walk),似乎在现实生活中这是正确的方式和它的相似之处 - 走路的玩家, 但是它必须通过地图实例访问目标字段,检查它是否可以走到那里,从开始字段中删除它并在目的地字段上添加它,我的印象是玩家会过多地知道"。
答案 0 :(得分:3)
最终这是一个设计问题,两者都很适合OOP范例。
我倾向于在语义上放置最有意义的类。在这种情况下,这意味着Player::walk
,除非地图做了什么让“玩家”移动(即在脚蹼游戏中,游戏板使球[又名'玩家'移动)然后它可能更多语义使该实体调用例如Board::movePlayer
。
如果您选择Player::walk
设计,则应将地图实例传递给播放器。所以你最终得到了Player::walk(Map &map /*more parameters here, maybe a direction or vector speed?*/)
。
要指出的另一点是,您应该尝试告诉而不是询问。这意味着不是:
//in Player::walk
if (map.cells[wantToWalkTo] == 0) {
map.cells[wantToWalkTo] = this.playerId;
}
//TODO: handle failed moves
您应该执行以下操作:
bool moved = map.moveTo(position, this); //encapsulate the logic for moving a player to a position
//TODO: handle failed moves
答案 1 :(得分:1)
您的播放器实例不必“知道”所有这些内容。它可以通过接口与Map实例通信。一个人可以看到周围的环境,看到一些东西,但看不到其他东西(例如可以看到一堵墙,但不能看到背后的东西)。 Map实例可以控制可见内容和不可见内容。
Python-ish伪代码:
class Player:
def __init__(self, Map, location):
"""Create a player, and tell them what Map they live on."""
self.Map = Map
self.location = location
def walk(self, destination):
"""Try to walk to the destination."""
path = self.Map.path_visible(location, destination)
if path:
self.location = destination
class Map:
def path_visible(self, location, destination):
"""Can a player at location see how to get to the destination?"""
答案 2 :(得分:0)
正确的OOP方法是让地图呈现某种允许的接口:
移动播放器的逻辑应完全在播放器类中。因此,检查玩家是否可以访问目标字段,是否为空等等,应该由玩家使用Map接口或其他类提供的信息来处理。例如,当你想允许玩家穿过墙壁,在水上行走或类似的东西时 - 例如,改变的是玩家,而不是地图!