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()+"	";
				}
				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()+"	";
			}
			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);
		
		}

  

原文地址:https://www.cnblogs.com/mrblue/p/4652091.html