@import url(http://www.cppblog.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
来源:http://cl314413.blog.163.com/blog/static/1905079762012102124637521/
https://blog.51cto.com/kenkao/1707619
前言:
本简易文档主要翻译自Photon官方Mmo文档,也加入了一些自己的理解和提示,以后会尝试着用自己的项目来讲一讲具体的开发流程。当然。。水平问题,肯定会有我不知道的错误,建议对照着英文原版来看。(虽然这货耽误了我两个月时间,但还是想说好值啊!)不多废话了,直接开始。
一、基础:兴趣管理(Interest Management)
玩游戏都知道,作为一个在线游戏来讲,人物的走动是基础中的基础。然而,在虚拟世界中,一个东西位置发生变化会触发位置更新消息。为了在其他客户端展示这个东西是在流畅的运动,最少需要每秒10次的更新。
但问题在于,如果这个游戏是成百上千人在玩的话。。。作为客户端来讲肯定不能让它接受到所有人物移动的消息的,计算机会爆掉。。所以呢,兴趣管理就是解决这个问题的好方法了。每个客户端都只获取他想要的事件,也就是他所能看见的东西的事件。
二、概念
游戏中的虚拟世界(IWorld)有一个建立在坐标基础上的虚拟空间。
每个坐标都是被3D向量表现出来的。几个坐标定义了一个区域(IArea)。
每一个在这个虚拟世界中存在的物体都被叫做“物品”(Item)。
客户端用位置和范围定义他们感兴趣的区域,并且只能看到这个兴趣区域(Interest Area)范围内的物品。
思路来了,但是呢,计算哪些物品进入哪些兴趣区域会非常消耗CPU资源,尤其当物品和兴趣区域在快速的运动的时候。
一个加快这个计算过程的简单方法就是把虚拟空间划分成一些固定地带(fixed Regions)然后只计算哪些地带和兴趣区域是重叠的。
客户端会接收到所有重叠地带中的事件。
而这,就是传说中的贴图算法了(Square Tile Algorithm)。
一旦一个物品出现在了特定的兴趣区域的边界之内,这个兴趣区域就会自动的把客户端实例(peer)和这个物品的事件频道(event channel)相订阅。
客户端从这一刻起就会收到所有被这个物品或者通过它发送的消息。
如果一个物品是在兴趣区域的边界来回晃悠的话,很可能就会造成频繁的订阅和未订阅的变化。为了解决这个问题,一个附加的更大的兴趣范围(interest area radius)就这么被创造出来了。已订阅的物体如果出了这个范围那就不再被订阅,客户端也就不再接收它的事件。
三、Photon MMO 功能
1、基于地带(region)的兴趣管理
使用贴图算法,长度和宽度可变,并且平铺尺寸也已经实现好了(tile size is implemented)
很方便用其他的地带算法取代默认的贴图算法。
2、物品(角色,NPC,共享的游戏对象)【Items(Avatars,NPCs,shared game objects)】
客户端可以产生、销毁或者移动物品。
物品具有可以被其他客户端读取以及被所有者更改的属性。
物品属性里有一个修订号码(revision number),客户端如果在一定时间内看不到一个物体了,可以把修订号码进行比较,以此决定接不接受该物品属性的更新。
3、兴趣区域:物品的事件在兴趣区域中是被自动接收的
兴趣领域有两个兴趣界点(interestthresholds)。物品进入里面的兴趣区域边界(inner radius)会变的可视,离开外面的兴趣范围就会变得不可视。这会最优的减少频繁的可视状态变化。
1 不可视物品,范围之外
2 不可视物品进入外围兴趣区域
3 不可视物品进入内部兴趣区域变得可视了
4 可视物品离开内部兴趣区域
5 可视物品离开外围兴趣区域变得不可视了
兴趣区域可以被重新设置范围大小:调整视野范围以适应能看见的物品的数量
为了提高在拥挤区域内的程序性能
在物品比较稀少的区域可以展示较远的物品。
兴趣区域可以附加给任何物品:无论是在物品移动了兴趣区域之后还是改变了兴趣区域本身。这对本身的角色移动兴趣区域尤其有用。(Whenever the item moves the interest area follows and changes theinterest accordingly. This is especially useful to move the interest area withthe own avatar.)
已分离的兴趣区域可以被自由的移动,这对摄像机漫游很有帮助。
客户端可以有多个兴趣区域在同一时间展示世界的不同部分。
4、自动的兴趣管理
客户端可以自动的申请或者取消掉物品的兴趣区域。(Clients can manually (un-)declare interest in items.)
5、自定义事件(Custom events)可以通过物品发送到两个可能的目标
物品的拥有者所有对物品感兴趣的客户端
6、最优化的位置更新机制:客户端只会在物品移动的时候才会发送更新消息。
7、复制用户的确认信息:发生在后的用户连接会重置之前的连接信息。(Duplicate user recognition: A subsequent user connection resets theprevious con-nection.)
四、状态机(StateMachine)
一个客户端实例peer有如下的状态。
1、 Connected:在连接之后的初始状态,玩家还没有进入世界。
2、 WorldEntered:在向服务端发出EnterWorld的请求以后,玩家进入世界。
3、 Disconnected:客户端未连接。
Peer实例为每一个状态使用一个不同的申请句柄(operation handler)。这允许申请在每个状态下表现的不同。下面是用到的申请句柄。
-
State Connected: Photon.MmoDemo.Server.MmoPeer
-
State WorldEntered: Photon.MmoDemo.Server.MmoActor
-
State Disconnected: Photon.SocketServer.Rpc.OperationHandlerDisconnected
客户端应该在呼叫一个状态变化申请之后一直等待与之关联的申请返回或者事件(operation response / event)。客户端实例peer的状态和现在的申请句柄【operationhandler (operation behavior)】在没有接收到返回或者事件是不会被确认的。EnterWorld申请将会返回一个申请返回,ExitWorld申请将会返回一个事件WorldExited。
五、白杨的话
1、整个的MMO项目(包括客户端和服务端)就在photon服务端SDK的src-server文件夹下。右键sln解决方案,用VS2010打开就可以看到了。
我第一次看的时候一下子就懵了。。这忒复杂了吧,都什么啊。。。
但是后来慢慢探索就明白各个项目的关系了。
简单的来说,Client.DotNet的项目内容和Client.Unity3D等同。是客户端例子的基础,已经封装好了peer初始化、operation申请、兴趣区域等基础类。这两个项目编译出来以后都是一个单独的类库,是后面那三个client例子用的。Client例子的任务就是引用基础类库,开发更加图形化的功能,比如Radar(物品雷达,用来管理地图上的物品,画小地图)。
MmoDemo.Common和MmoDemo.Server都是服务端的内容。Common定义了几个用来传送事件的ID或Code枚举。而Server就主要是用来实现服务端逻辑了。
2、如何用这货来开发MMO功能呢?
举例来说,如何开发一个简单的登陆注册功能?
大概思路如下:(这里只是简述,肯定不完整,我会争取在我的项目比较稳定以后用项目来说明)
1) 在client基础类库项目的GameStateStrategies中加入一个新状态类Login.cs。
2) 在项目的Operations.cs中实现入一个新的传送用户名和密码的方法,注意,这里你使用的OperationCode服务端还无法识别,先记下。过程中别忘了新状态。
3) 在你要更改的例子中,在enterworld之前调用这一方法。
4) 来到服务端的common,在OperationCode.cs之中定义好你刚才在客户端中传送的OperationCode,还要分别在ErrorCode和EventCode中给这个登录方法加一个申请返回和事件回复的Code。
5) 再来到server,在Operations中加入判断登录信息的新类,在Events中加入返回成功失败消息的新类。过程中还是别忘了判断Login状态。
3、 至于用什么数据库。。。能力有限,一直用的都是LINQ To SQL,架设比较方便,在photon中使用也很简单,这方面的技术查阅C#红皮书或者新出的数据库技术的书就好。不过目测这货已经过时了,所以。。也不是太敢确定会一直用它,慢慢来,比起各种缺文档的photon,数据库好学多了不是么!