先来看看序列图:
看之前先看看一些补充说明,左边是Tank所在的机子,右边是Building所在的机子。前面两个ReceiveData调用缺少了SendData调用,另外有一些地方实际上是异步操作,例如某些ReceiveData,为了画图简便,我都用掉用来表示了。希望大家看这个图的时候,对照一下最新版本的代码来看。
在最新版本的代码里面,Action添加了8个(2*2对)虚函数。分别是GetXXInfo/SetXXInfo和GetXXResult/SetXXResult,XX是Subject和Target(主语和宾语)。简单一点讲,在Action.OnAction计算之前,可能首先需要知道双方的一些具体数据,这个时候就会向Subject和Target的拥有者发送信息,要求给出这些计算所需要的数据。拥有者收到消息则在本地生成同样的Action对象,调用SetXXInfo,然后本地的Engine就会将设置好的信息发送出去。Action所在机器收到消息之后,Engine就会调用Action.GetXXInfo来更新本地对象的副本。可以看到,这里仅仅获取和更新副本的非常少的信息,这个信息是某一个Action在进行OnAction计算所必需的信息,其他信息部通过这里进行更新,以减少计算量和通信量。OnAction之后,按道理就会对宾语,甚至是主语的某些数据进行更新。我假设一个比上图更复杂的动作,例如Heal治疗,那么HealAction.OnAction就应该减少Subject的MP并增加Target的HP。这个时候OnAction就应该调用本地的SetXXResult来发布相应的结果信息,原始对象拥有者在收到信息的时候,Engine就调用HealAction.GetXXResult来更新本地对象的相应信息。
现在应该明白,我的设计里面有三个要素,Subject、Action、Target。这三个要素在这个设计里面不需要在同一台机子上面,但是在同一台机子上面也是可以的。如果Subject、Action、Target都在同一台机器上,那就是单机版。如果Subject、Target在不同的机器上,Action在这两台机器的其中一台,那么就是1vs1的对战游戏。如果Subject、Target在不同的机器上,Action可能在也可能不在同一台机器上,那就是SC的LanGame模式。如果Subject、Target、Action可以在任意的机子上面,并且没有任何关系上面的约束,那就是我所说的终极目标——分布计算模式了。可以看到这个设计理论上应该能够适应好几种不同的模式,并且这个不需要改变Action和Character的设计,Action和Character也只需要一个版本,不需要分裂成client版和server版,这样在开发上面来说,难度应当比较小一点。使用什么模式,大概只需要在引擎里面进行一些设置就可以了。
需要注意到一个问题是这里还没有仔细考虑清楚的,就是同步互斥问题。dudu提出了同步互斥问题,举了两个例子:一个是一群的Tank对一个Building发动攻击的情况,另外一个是两个Tank互相攻击的情况。对于前一个情况我认为不是一个问题,至少不需要把对象锁定来达到同步的目的。我们只需要在ResultData里面传送delta值,比如HP减少了12,那么在Building进行更新数据的时候一旦发现HP<0,那就立刻“爆炸”同时进入“废物”状态,这个时候在减小HP也不会体现出来。其实在SC或者C&C里面经常会见到这么一个情形:A对Building发送了一颗炮弹,炮弹到达Building的时候HP就小于0了。但是在炮弹发射之后到达之前一瞬间,Building的HP还是大于0的,这个时候其他的Tank也对他发动攻击。当其他Tank的炮弹到达的时候,Building已经挂了,但是游戏还是没有任何影响,我们也不觉得奇怪。所以对于这种情形来说,我们不需要锁定对象来达到同步的目的的。但是对于第二种情况,我目前还没有思考清楚,也许会有一些什么问题存在,大家觉得呢?
希望大家看完之后,能够有点什么建议,这样我们才能更上一层楼。谢谢。
看之前先看看一些补充说明,左边是Tank所在的机子,右边是Building所在的机子。前面两个ReceiveData调用缺少了SendData调用,另外有一些地方实际上是异步操作,例如某些ReceiveData,为了画图简便,我都用掉用来表示了。希望大家看这个图的时候,对照一下最新版本的代码来看。
在最新版本的代码里面,Action添加了8个(2*2对)虚函数。分别是GetXXInfo/SetXXInfo和GetXXResult/SetXXResult,XX是Subject和Target(主语和宾语)。简单一点讲,在Action.OnAction计算之前,可能首先需要知道双方的一些具体数据,这个时候就会向Subject和Target的拥有者发送信息,要求给出这些计算所需要的数据。拥有者收到消息则在本地生成同样的Action对象,调用SetXXInfo,然后本地的Engine就会将设置好的信息发送出去。Action所在机器收到消息之后,Engine就会调用Action.GetXXInfo来更新本地对象的副本。可以看到,这里仅仅获取和更新副本的非常少的信息,这个信息是某一个Action在进行OnAction计算所必需的信息,其他信息部通过这里进行更新,以减少计算量和通信量。OnAction之后,按道理就会对宾语,甚至是主语的某些数据进行更新。我假设一个比上图更复杂的动作,例如Heal治疗,那么HealAction.OnAction就应该减少Subject的MP并增加Target的HP。这个时候OnAction就应该调用本地的SetXXResult来发布相应的结果信息,原始对象拥有者在收到信息的时候,Engine就调用HealAction.GetXXResult来更新本地对象的相应信息。
现在应该明白,我的设计里面有三个要素,Subject、Action、Target。这三个要素在这个设计里面不需要在同一台机子上面,但是在同一台机子上面也是可以的。如果Subject、Action、Target都在同一台机器上,那就是单机版。如果Subject、Target在不同的机器上,Action在这两台机器的其中一台,那么就是1vs1的对战游戏。如果Subject、Target在不同的机器上,Action可能在也可能不在同一台机器上,那就是SC的LanGame模式。如果Subject、Target、Action可以在任意的机子上面,并且没有任何关系上面的约束,那就是我所说的终极目标——分布计算模式了。可以看到这个设计理论上应该能够适应好几种不同的模式,并且这个不需要改变Action和Character的设计,Action和Character也只需要一个版本,不需要分裂成client版和server版,这样在开发上面来说,难度应当比较小一点。使用什么模式,大概只需要在引擎里面进行一些设置就可以了。
需要注意到一个问题是这里还没有仔细考虑清楚的,就是同步互斥问题。dudu提出了同步互斥问题,举了两个例子:一个是一群的Tank对一个Building发动攻击的情况,另外一个是两个Tank互相攻击的情况。对于前一个情况我认为不是一个问题,至少不需要把对象锁定来达到同步的目的。我们只需要在ResultData里面传送delta值,比如HP减少了12,那么在Building进行更新数据的时候一旦发现HP<0,那就立刻“爆炸”同时进入“废物”状态,这个时候在减小HP也不会体现出来。其实在SC或者C&C里面经常会见到这么一个情形:A对Building发送了一颗炮弹,炮弹到达Building的时候HP就小于0了。但是在炮弹发射之后到达之前一瞬间,Building的HP还是大于0的,这个时候其他的Tank也对他发动攻击。当其他Tank的炮弹到达的时候,Building已经挂了,但是游戏还是没有任何影响,我们也不觉得奇怪。所以对于这种情形来说,我们不需要锁定对象来达到同步的目的的。但是对于第二种情况,我目前还没有思考清楚,也许会有一些什么问题存在,大家觉得呢?
希望大家看完之后,能够有点什么建议,这样我们才能更上一层楼。谢谢。