Arpg 游戏设计
| 0.整体结构 <ignore_js_op> 1.心跳机制 BigHeart心跳器,是游戏中统一的动力来源,提供游戏的动力驱动。心跳器会以一定的时间间隔跳动,感兴趣的监听者可以向心跳器注册。 心跳器驱动的有:每个游戏循环内场景的更新函数update(deltaTime)、定时对引用计数为0的动画资源、图标资源等做垃圾回收gc、活动以及领取奖励的倒计时等、向服务器发送心跳包。 因为游戏的动力都是来源于此心跳器,可以很好的解决flash插件的睡眠模式问题。即使自身丧失动力,也可以由外部容器定时调用心跳函数,来保证正常的游戏循环得以进行。 很多游戏都提供了对timer进行管理的功能,但职责更多的是创建timer,并按不同时间间隔存放timer。而不能像心跳器这样避免很多timer实例的存在。
2.资源管理
加载器内部维护不同优先级的待加载队列,可以设置并发加载的最大数量,当前资源加载完成,或者正在加载的资源数量小于最大并发数量时,会从待加载队列中找出优先级最高的进行加载。当用户请求一个资源的时候,会首先查看其请求的资源是否已经在加载或请求队列中,如果已经存在,只需添加请求者信息到资源的请求队列中。资源加载完成后,通知所有的请求者进行处理。 为了明确职责,加载器只负责资源的加载,不负责存储,也不进行另外的解码等操作。已经下载完成的资源,交由其请求者处理后,加载器不再保存其引用。为了缓存游戏的地图区块图片、位图动画、图标、SWF皮肤资源,提供专门负责地图区块图片管理的MapDefManager、专门负责动画资源管理的管理器AnimationDefManager、专门负责图标资源管理的ImageDefManager、专门负责皮肤资源管理的SkinManager。有了这些资源管理器后,上层用户也不需要和加载器直接打交道,而是通过这些管理器请求资源。 具体的一个动画资源AnimationDef、图标资源ImageDef都保存有引用其的BmpAnimation、Image类的引用计数,会定时的清理计数为0的资源。 划分出不同类型的资源管理器,而不是一个统一的缓存管理器的目的也是为了明确职责,尽量使每个类只做一件事情,满足单一责任的原则。
3.网络 网络模块提供客户端与服务器间进行socket交互的功能。基本上每个游戏都会和服务器有两个连接以上的交互。一种就是先与账号服务器交互,账号验证后在整个游戏循环内一直保持与网关的连接交互。另外一种就是为了减轻网关的压力,在账号服务器验证过后,持有其发送过来的ticket,去直接分别连接场景服务器、聊天服务器、全局服务器,而不统一通过网关转发。 为了适用这些模型,提供一个ConnectionManager管理与服务器的各个连接Connection,每个Connection以ip+port作为key。每个Connection收到的数据统一交由Dispatcher类进行分发。对某个以cmd标识的消息感兴趣的用户,可以向Dispather进行注册接收。 如果想避免手动写消息结构的序列化以及反序列化的代码,可以利用类的反射机制,编写一个自动序列化器自动对消息结构进行序列化和反序列化的操作。例如使用技能的消息: <ignore_js_op>
图3.1 4.场景 4.1分层结构
图4.1
4.2 Terrain设计
1)整个地图是作为一个位图(fp9位图最大为2880,fp10中位图最大为4096,超过限制则可分成多个)来移动,
但是加载采用切块的方法,当某个i_j位置的切块地图加载进来的时候,将此块地图数据通过copyPixel拷贝到terrainData的响应位置处。 2)地图是一个sprite容器,terrainSprite:Sprite = new Sprite().只将屏幕周围的区块给addChild进来。根据游戏主角的位置,调整terrainSprite的偏移。 3)地图是一个画布,terrainCanvas:Bitamp =new Bitmap();将屏幕周围的区块的位图数据画到这个画布上。根据游戏主角的位置,调整terrainSprite的偏移。
4.3场景元素类的设计(部分)
图4.2 职能类部分的设计借鉴了Cocos2D中Action系列类以及Unity3D中Components系列类的设计思想,将场景元素的某部分特定功能抽取出来成为一个职能类,如AvatarCom、MoveCom、FlyCom。例如,如果某个元素需要有行走的功能,只需组合一个MoveCom的实例即可。而有些游戏则采用的是继承的方案,在角色、怪物和元素基类中间有个Animal的类负责行走逻辑,不利于扩展。职能类的设计避免了所有的逻辑都写在一个类中,从来形成一个具有几千行代码的臃肿类。
4.4 网络同步 页游中对地图的处理方式,决定了其基本不可能采用向前预测法。普遍的是当前角色每走三个方格向服务器同步一次,或者其他数量的方格。但是因为网络延迟的存在,当发现角色位置不同步的时候,如果不采取一定的平滑的同步策略或者直接拉扯到最新位置,体验都不好。有两种比较简单同时也很实用的处理方式: 1) 2) 4.5 场景优化 1)地图缓动移动 对地图的移动采用缓动处理,是为了地图能够平滑的滚动,带来更好的视觉效果。从早期的天书奇谈到目前的很多arpg页游都采用了这种优化方式。 2)直线探测寻路 如果当前场景是稀疏场景或者点击位置是在角色周围一定距离内,则可以先通过类似于图形学上的直线光栅化的方法,快速产生一条从角色到目的地的路径。先判断这条路径是否可走,如果不可通行,则转由传统的寻路算法处理。首先判断是否是稀疏场景或者点击位置是在角色周围一定距离内的原因,是因为这样的条件下,直线探测的成功率较高。 3)分时处理 为提高帧率,避免一个游戏循环的更新函数内,处理过多的逻辑,而导致帧频下降,需要将更新函数内的逻辑尽可能的分布在多个帧内完成。如可以设定N帧执行一次深度排序、每N帧做一次鼠标over判定、每一帧处理所有的角色怪物状态处理改为每一帧只依次处理几个、进入场景每一帧只创建几个其他角色或怪物对象而非收到角色怪物列表后一次性创建完,等等。上面只是列举出来了几个,其实需要分时优化处理的地方非常多,除了场景部分,其他子系统也会有很多。
5.FlyMVP框架 Fly:轻量级,框架的接口很多都是标识接口。此框架的目的,仅仅是为了让用户对一个子系统按照框架列出的部分来划分,区分职责,降低耦合。每个子系统都包含Model、View两个大部分。 Model层:数据模拟层,View层依赖于Model层,但Model层不知道View层的存在,也就是说View层对Model层不可见。就像操作系统的设计一样,操作系统的核心是可以独立于界面系统的存在的,但是界面系统却依赖于系统核心。系统核心提供统一的接口,不同的界面系统都可以基于核心提供的接口而存在,有不同的显示。 1)ConfigManager:模块的配置数据及管理,与InfoManager部分的数据区分开,隔离可变和不可变部分,职责划分清楚。因为是配置的,以后更改时只需更改配置文件即可,不用更改程序部分,方便以后的修改。 2)Service:与服务器通信的交互函数。 3)InfoManager:子系统的模型层部分可变数据信息以及数据管理。 每个子系统的Model部分都放置在Model.swf库中。各个子系统间数据共享,通过单例向其他子系统公开数据查询的接口。 View层:子系统的显示层。将逻辑部分独立出去,显示部分就只需要关心自己的样式以及布局。 1)Mediator:与子系统的GUI界面的某个孩子相关联,负责其逻辑。 2)Presentor:继承自Mediator,负责子系统的GUI界面的打开、关闭、以及界面的逻辑。 对于某个子系统的View层,有且仅有一个展示器Presentor。对于GUI界面不复杂的子系统,可以让展示器来负责所有显示部分的逻辑。而比较复杂的子系统,如果某个孩子的逻辑处理较多,可以写一个Mediator类来负责这个孩子的逻辑。 每个子系统的View层部分都放置在GUI.swf库中,当然也可以独立成一个单独的swf。 |

浙公网安备 33010602011771号