面向Web服务的游戏设计4:自定义服务参数设计
服务器与客户端的数据交换涉及大量数据参数和数据类型。对于每次数据交换,数据参数的数量和类型可能都是不同的。举个简单例子,客户端从服务器端获得当前地图的精灵信息,假设某次通信得到10个精灵的信息。下次通信时,假设其中一个精灵被kill了,同时另外9个精灵只是部分信息变化了,我们希望只传输更新了的信息而不是传递所有信息。可以想象,这两次通信的数据参数变化极大。或者说,几乎每次通信的参数都是不同的。如果针对每一种可能都定义一个服务方法和一组参数组合,需要定义大量的方法来实现,显然这种设计缺乏灵活性,很不可取。
笔者在游戏中采用的方法是:定义一个通用的方法,方法的参数是固定的,所有游戏数据都序列化在自定义的字符串参数之中,通过解析该参数来实现不同的功能。这样做的好处是简化了服务器与客户端通信的接口的设计,提供最大的灵活性。该方法的关键是对自定义参数的设计。
首先给出通用方法的原型。
string request(int playerId, string inputParams)
客户端通过inputParams字符串把当前的状态信息和命令等传递给服务器。服务器端的状态信息通过返回值(字符串)返回给客户端。
参数格式分为简单模式和组合模式。
简单模式:
obj1:param1,value1;param2,value2;...
组合模式:
obj1:param1,value1;param2,value2|obj2:param1,value1;param2,value2|...
一个简单模式的例子:
"PlayerObj:x,100;y,200;speed,150;action,2"
这个例子中包含了一个player对象,首先是对象名称,后面则是该对象的参数。值得注意的是不一定该对象的所有参数都包含在该字符串里,为了节省传输量,只有更新了的参数才需要传输,从而体现了该设计的灵活性。组合模式就是所有对象的叠加,实际应用中几乎都是组合模式的。
当需要实现新的数据类型或命令,只要更新服务端和客户端的参数的解析部分就可以了,服务的接口部分代码完全不用改动。
参数中的每个对象的一个限制要求是只能包含简单类型,如数值,字符串。对于复杂类型,例如自定义对象,需要用另一个对象参数来表达。
本文介绍的自定义参数设计并非尽善尽美。例如,对象序列化没有标准支持,也不提供类型检验,全部都要靠自己去包装和解析,增加了一些额外的工作量。不过对于传递游戏参数,还是比较简洁高效的。
如果大家有什么更简便灵活的办法,不妨一起讨论一下。谢谢。