游戏经历总结

从事游戏工作,大部分时间是在做业务逻辑。游戏的业务逻辑大体上分两类,单人玩法和多人玩法。单人玩法例如收发邮件,背包操作,多人玩法例如组队匹配。


入门

个人写功能逻辑的流程是:

1. 通读文档,检查文档逻辑是否有问题,大致评估实现难点。
  2. 画思维导图,从内存数据结构,db存储格式,C/S交互以及功能逻辑要点,配置需求这几个点去写。
  3. 实现具体的逻辑代码。
  4. 自行写出CheckList进行自测以及代码优化。 测试点包括:从是否存在刷道具情况(尤其是有循环发奖代码), 数据落地再Load出来后是否一致,如果需要比较大的测试用例,则自己写机器人覆盖用例进行测试,涉及到读频率远远大于写的数据(例如个人属性战力),需要做cache。一些排序的耗时操作是否可以让前端自己来做(复杂的计算尽量不在后端做,尽量做到大部分是O(1)复杂度的操作)。
  5. 提交QA测试。


进阶

大概写了几个逻辑模块后,应该是上手了。 这时候一般的逻辑模块实现起来没难度了。 这时候就可以去看一些比较核心的逻辑系统实现,譬如任务系统的框架(新增任务是否需要策划来配置即可),属性系统的框架(新加属性是否需要加代码),这些好的框架原则上是可扩展可配置的,也就是只需要策划负责就OK了。 但好框架需要策划和程序根据需求一起构思,缺一不可。 比较底层且核心的背包系统的实现,关注点有: 1)对其他系统暴露的api是否合适(增删查); 2).道具增加过程如果满了改成用别的途径发放。 3).删道具要保证原子性,要么可以删完,要么一个都不删。 关注点是系统的健壮性。

大概把任务属性背包这些非场景相关功能了解后,逻辑功能开发算是入门了。然后就可以去了解场景相关模块的实现。

场景模块主要是AOI和同步策略,AOI最通用的做法就是九宫格,即将场景划分成很多个边长为r的正方形格子,每个对象只关注自己所在的九宫格发生的事件(例如玩家移动,战斗技能释放),从一个九宫格A移动到另外一个九宫格B,则A-B(A有B无的格子)被告知该玩家离开了AOI范围,A and B(AB相关的格子)被告知该玩家移动了,B-A(B有A无的事件),则被告知该玩家加入了AOI范围。而同步策略主要考虑网络延时的影响,这个没接触过就不多说了。

以上系统都熟悉之后,就可以去看服务器底层架构代码了,主要涉及任务调度,网络IO,定时器,日志等模块。把代码流程都看懂之后,就可以往性能方面去思考了。
关于服务器性能,这篇文章 http://blog.sina.com.cn/s/blog_72995dcc0102uzdg.html 提到影响服务器高性能的四大来源,有兴趣可以去阅读下。

  • 数据拷贝. 譬如数据从TCP层拿到应用层后,往往要进行粘包拆分检查,数据格式化组装然后发送到应用进行处理的过程。但数据拷贝更多是发生在逻辑代码中(例如函数使用值传递而不是引用),时刻提醒自己能用引用绝不用拷贝。

  • 上下文切换. 限制活跃线程数少于或等于CPU个数,例如目前Linux下都是用Epoll去管理多连接,而不是Apache的一个连接一个进程。

  • 内存分配. 比较好的做法是内存池,例如Stl的Allocator就是这样做的,容器释放的内存被Allcator回收到一个free_list,等容器需要分配内存时就先到free_list去拿,内存不足再向系统申请内存。 比较成熟的库有 tcmalloc,直接用吧。

  • 锁竞争。 这个主要是针对多线程应用的。 涉及锁的一个原则是: 两个请求不应该产生竞争,除非它们在同一个阶段需要同样的数据集。根据这个原则不断去去掉不必要的锁。 还有一个是我自己的体会,不确定是否正确。 如果是I/O密集型的应用,推荐使用CAS锁,而计算密集型的应用则可以使用Mutex。 应为I/O密集型的应用计算量小,一般占用锁后去处理事件的时间不会长,使用CAS锁的一个特点是会一直询问锁是否可用,这个过程不会释放线程,这就不会产生上下文切换。 只要询问的时间代价
    比上下文切换的代价小,必然选用CAS锁。 而Mutex则会释放线程的占用,直到锁可用之后才会占用线程继续操作。


再谈谈熟悉代码方法

  • 熟悉服务器启停方法,了解所需的进程数目以及其具体的作用.
  • 了解RPC框架(目前接触的两个游戏都是使用rpc通信),熟悉数据流。 对于RPC框架,需要了解几个部件。
    1. 通讯的方式,是socket,共享内存还是管道,面向客户端的通讯大多数是采用TCP,而服务器内部服务之间的通讯则不一,单机架构下可以选择共享内存或者socket,分布式架构则必须通过socket。如果是socket,对于游戏服务器,一般是长连接。

    2. 如何寻址,即A服务怎样告诉RPC框架,如何连上B服务并进行通信。 目前只接触过socket通讯,方法是写一份所有服务所在的ip和监听端口配置。服务读取配置,从配置中读出这些信息,然后只需要告诉rpc框架向目标ip和端口发起连接,然后互相告知自己的身份即可。

    3. 发起rpc调用,方法和参数需要通过网络底层协议如tcp发送到另外一个服务,网络协议是基于二进制的,这些在内存的方法和参数就要序列化成二进制形式,然后发送。 对应的,接收端要对这些二进制信息进行反序列化,转换成内存可以解析的形式。 序列化工具比较常用的是pb。

    4. 第3步从结果看是数据成功在服务之间进行传递,实际上在数据进入网络层传输前后,还需要经过一系列的调度,才能成功对消息进行收发。 网上开源的消息队列有Zeromq,Kafka,游戏相关的话可以了解云风开源的skynet或者是其简化版hive,基于Actor模型。

    5. 了解网络模型,目前Linux下一般是采用epoll,具体做法是单独开辟I/O线程,每个线程上跑一个epoll实例。

    6. 了解db和cache的接口和用法。

    7. 以上的东西都了解后,就可以自己写个简单的demo去测试一下。

猜你喜欢

转载自blog.csdn.net/lewiskyo/article/details/86664368
今日推荐