MMO可见格子算法
看注释吧,写的很清楚了
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZoneTest { public class Zone { public int mId; public float Width; public float Height; public List<Zone> VisibleZoneList = new List<Zone>(); public Zone(int id, float width, float height) { mId = id; Width = width; Height = height; } public void AddVisibleZone(Zone zone) { VisibleZoneList.Add(zone); } } public class Scene { private List<Zone> mZoneList = new List<Zone>(); public Scene(float w,float h) { mSceneWidth = w; mSceneHeight = h; } public const float ZONE_SIDE = 1.0f; //场景宽高 private float mSceneWidth; private float mSceneHeight; //格子列数和行数 private int mZoneColumnCount; private int mZoneLineCount; public Zone GetZone(int id) { if (id < 0 || id > mZoneList.Count) { return null; } return mZoneList[id]; } //Zone示意图 /* | mSceneWidth | ----------------- -- | | | | |ZONE_SIDE ----------------- | | | | | ----------------- mSceneHeight | | | | | ----------------- -- ----------------- line 0 ----------------- line 1 ----------------- line 2 ----------------- line 3 column0 column1 column2 column3 | | | | | | | | | | | | | | | | * */ public bool InitZone() { //计算场景内zone行和列 mZoneLineCount = (int)Math.Ceiling((double)mSceneHeight / (double)ZONE_SIDE); mZoneColumnCount = (int)Math.Ceiling((double)mSceneWidth / (double)ZONE_SIDE); //创建zone for (int i = 0; i < mZoneLineCount; i++) { for (int j = 0; j < mZoneColumnCount; j++) { int id = i * mZoneColumnCount + j; Zone zone = new Zone(id, ZONE_SIDE, ZONE_SIDE); mZoneList.Add(zone); } } //最大周围多少个格子被可见 MaxNearByZoneNumber*MaxNearByZoneNumber 个 const int MaxNearByZoneNumber = 3; //可见格子的起始偏移 const int Offset = MaxNearByZoneNumber / 2; //把周围可见格子加入列表 /* * ------------- * |0 |1 |2 | * ------------- * |3 |4 |5 | * ------------- * |6 |7 |8 | * ------------- */ //0的可见格子为 0134 //4的可见格子为 0123456789 //7的可见格子为 345678 //遍历所有格子行 for (int i = 0; i < mZoneLineCount; i++) { //遍历所有格子列 for (int j = 0; j < mZoneColumnCount; j++) { //当前要判断可见性的格子id int id = i * mZoneColumnCount + j; Zone zone = mZoneList[id]; //遍历周围 MaxNearByZoneNumber*MaxNearByZoneNumber个格子 //判断[x,y]这个格子是否出界 //行 for (int n = 0; n < MaxNearByZoneNumber; n++) { int y = i - Offset + n; if (y < 0 || y >= mZoneLineCount) continue;//y出界 //列 for (int m = 0; m < MaxNearByZoneNumber; m++) { int x = j - Offset + m; if (x < 0 || x >= mZoneColumnCount) continue;//x出界 //算当前格子id int visibleZoneId = y * mZoneColumnCount + x; //if (visibleZoneId == id) continue;//是自己格子也要加入,自己属于自己可见格子 zone.AddVisibleZone(mZoneList[visibleZoneId]); } } } } return true; } public void Print() { for (int i = 0; i < mZoneLineCount; i++) { string str = ""; //遍历所有格子列 for (int j = 0; j < mZoneColumnCount; j++) { str += (i * mZoneColumnCount + j).ToString()+"\t"; } Debug.Print(str); } } public void PrintZone(int i) { Debug.Print("[{0}]---------------------",i); var zone = mZoneList[i]; string str = ""; foreach(var z in zone.VisibleZoneList) { str+=z.mId.ToString()+"\t"; } Debug.Print(str); Debug.Print("[{0}]---------------------",i); } } class Program { static void Main(string[] args) { Scene scene = new Scene(5,7); scene.InitZone(); scene.Print(); int oldId = 5; int newId = 10; Zone oldZone = scene.GetZone(oldId); Zone newZone = scene.GetZone(newId); /* //比较计算应该删除我的zone List<Zone> deleteMeZone = new List<Zone>(); foreach (var zone in oldZone.VisibleZoneList) { if (!newZone.VisibleZoneList.Contains(zone)) { deleteMeZone.Add(zone); Debug.Print(zone.mId.ToString()); } } Debug.Print("-----------"); //比较计算应该创建我的 List<Zone> createMeZone = new List<Zone>(); foreach (var zone in newZone.VisibleZoneList) { if (!oldZone.VisibleZoneList.Contains(zone)) { createMeZone.Add(zone); Debug.Print(zone.mId.ToString()); } } */ scene.PrintZone(4); scene.PrintZone(16); scene.PrintZone(28); scene.PrintZone(30); } } }
//当角色位置发生改变
protected void UpdateZone() { //安全检查 if (null == Scene || null == Zone) return; //获得我的zone id int zoneId = Scene.Pos2ZoneId(mPosition.X, mPosition.Y); Zone newZone = Scene.GetZone(zoneId); if (null==newZone) { Logger.Fatal("[{0}] move out of scene[{1},{2}]", GetName(), GetPosition().X, GetPosition().Y); } //如果我的zone没变化 if (zoneId == Zone.Id) return; //比较计算应该删除我的zone List<Zone> deleteMeZone = new List<Zone>(); foreach (var zone in Zone.VisibleZoneList) { if (!newZone.VisibleZoneList.Contains(zone)) { deleteMeZone.Add(zone); } } //比较计算应该创建我的 List<Zone> createMeZone = new List<Zone>(); foreach (var zone in newZone.VisibleZoneList) { if (!Zone.VisibleZoneList.Contains(zone)) { createMeZone.Add(zone); } } //发包删除我 foreach(var zone in deleteMeZone) { zone.PushAction2AllPlayer((player)=>{ player.Proxy.DeleteObj(ObjId, (int)ReasonType.VisibilityChanged); },ObjId); } //把该删除的通知我 if (GetObjType() == ObjType.PLAYER) { ObjPlayer player = this as ObjPlayer; foreach (var zone in deleteMeZone) { zone.PushAction((obj) => { if(obj!=this) { player.Proxy.DeleteObj(obj.ObjId, (int)ReasonType.VisibilityChanged); } }); } } //发包创建我 CreateObjMsg msg2Other = new CreateObjMsg(); ObjData data = DumpObjData(ReasonType.VisibilityChanged); msg2Other.Data.Add(data); foreach (var zone in createMeZone) { zone.PushAction2AllPlayer((player) => { if (IsVisibleTo(player)) { player.Proxy.CreateObj(msg2Other); } }, ObjId); } //把周围所有人通知给我 if(GetObjType()==ObjType.PLAYER) { ObjPlayer player = this as ObjPlayer; CreateObjMsg msg2Me = new CreateObjMsg(); foreach (var zone in createMeZone) { zone.PushAction((obj) => { if(obj!=this) { if (obj.IsVisibleTo(this)) { msg2Me.Data.Add(obj.DumpObjData(ReasonType.VisibilityChanged)); } } }); } player.Proxy.CreateObj(msg2Me); } Zone.RemoveObj(this); newZone.AddObj(this); SetZone(newZone); }