using System; using System.Collections.Generic; using System.Text; using CommonAI.Zone; using CommonLang; using CommonLang.Protocol; using CommonAI.RTS; using CommonLang.Vector; using CommonLang.Log; using CommonAI.Zone.ZoneEditor; using CommonAI.Zone.Helper; using CommonAI.RTS.Manhattan; namespace CommonAI.ZoneClient { partial class ZoneLayer { //------------------------------------------------------------------------------------------- /// /// 和地图做碰撞检测,是否阻挡 /// /// /// public bool TouchMap(ZoneUnit u) { return TryTouchMap(u, u.X, u.Y); } /// /// 目标点是否阻挡 /// /// /// /// public bool TouchMap(float x, float y) { return path_finder.TouchMapBlock((((int)x) / Terrain.GridCellW), (((int)y) / Terrain.GridCellH)); } /// /// 尝试用新的坐标和地图碰撞检测 /// /// /// /// /// public virtual bool TryTouchMap(ZoneUnit u, float x, float y) { int bx = (((int)x) / Terrain.GridCellW); int by = (((int)y) / Terrain.GridCellH); if (path_finder.TouchMapBlock(bx, by)) { return true; } if (this.IsIgnoreTerrainTouch) { foreach (var flag in mFlags.Values) { if (flag is ZoneEditorDecoration) { var deco = flag as ZoneEditorDecoration; if (deco.TouchBlock(x, y)) { return true; } } } } return false; } /** * 以目标点为中心,circle为半径,找可行走区域。找到了返回true;找不到返回false; * sx, sy 起始位置 * dstx, dsty 目标位置 * circle 搜寻半径 * outx, outy修改后的目标点 */ public bool GetNearWay(float sx, float sy, float dstx, float dsty, float circle, ref float outx, ref float outy) { //以目标点为中心,一圈一圈向外查找可行走的块 //起始点与终点连线方向上的点优先 int W = Terrain.GridCellW; int H = Terrain.GridCellH; float squCircle = circle * circle; int dr = ((int)circle) / W; float vx = sx > dstx ? 1 : -1; float vy = sy > dsty ? 1 : -1; bool f = true; for (int r = 1; r <= dr; r++) { for (int v = 1; v <= 4; v++) { float xx = dstx + W * r * vx; float yy = dsty + H * r * vy; for (int dx = f ? 0 : 1; f ? dx <= r : dx < r; dx++) { float x = dstx + dx * W * vx; if (MathVector.getDistanceSquare(x, yy, dstx, dsty) < squCircle) { if (!path_finder.TouchMapBlock(((int)x) / W, ((int)yy) / H)) { outx = x; outy = yy; return true; } } } for (int dy = f ? 1 : 0; f ? dy < r : dy <= r; dy++) { float y = dsty + dy * H * vy; if (MathVector.getDistanceSquare(xx, y, dstx, dsty) < squCircle) { if (!path_finder.TouchMapBlock(((int)xx) / W, ((int)y) / H)) { outx = xx; outy = y; return true; } } } if (f) vy *= -1; else vx *= -1; f = !f; } } outx = -1; outy = -1; return false; } /// /// 2个单位是否碰撞 /// /// /// /// public virtual bool TouchObject2(ZoneObject s, ZoneObject d) { if (s == d) return false; float w = s.X - d.X; float h = s.Y - d.Y; float r = s.RadiusSize + d.RadiusSize; if (w * w + h * h <= r * r) { return true; } return false; } /// /// 尝试用新的坐标碰撞检测 /// /// /// /// /// /// public virtual bool TryTouchObject2(ZoneObject s, float sx, float sy, ZoneObject d) { if (s == d) return false; float w = sx - d.X; float h = sy - d.Y; float r = s.RadiusSize + d.RadiusSize; if (w * w + h * h <= r * r) { return true; } return false; } /// /// 获得和当前单位碰撞的单位 /// /// /// public ZoneUnit TouchUnit(ZoneUnit src) { ZoneUnit ret = null; ForEachNearObjects(src.X, src.Y, src.BodySize, (ZoneObject o, ref bool cancel) => { if ((o != src) && (o is ZoneUnit)) { ZoneUnit u = o as ZoneUnit; if ((u.TouchObj) && TouchObject2(src, u)) { ret = u; cancel = true; } } }); return ret; } /// /// 获得和当前单位碰撞的建筑 /// /// /// public ZoneUnit TouchBuilding(ZoneUnit src) { ZoneUnit ret = null; ForEachNearObjects(src.X, src.Y, src.BodySize, (ZoneObject o, ref bool cancel) => { if ((o != src) && (o is ZoneUnit)) { ZoneUnit u = o as ZoneUnit; if (u.IsStaticBlockable) { if (u.TouchObj && TouchObject2(src, u)) { ret = u; cancel = true; } } } }); return ret; } public ZoneUnit TryTouchUnit(ZoneUnit src, float x, float y) { ZoneUnit ret = null; ForEachNearObjects(x, y, src.BodySize, (ZoneObject o, ref bool cancel) => { if ((o != src) && (o is ZoneUnit)) { ZoneUnit u = o as ZoneUnit; if ((u.TouchObj) && TryTouchObject2(src, x, y, u)) { ret = u; cancel = true; } } }); return ret; } public ZoneUnit TryTouchBuilding(ZoneUnit src, float x, float y) { ZoneUnit ret = null; ForEachNearObjects(x, y, src.BodySize, (ZoneObject o, ref bool cancel) => { if ((o != src) && (o is ZoneUnit)) { ZoneUnit u = o as ZoneUnit; if (u.IsStaticBlockable) { if (u.TouchObj && TryTouchObject2(src, x, y, u)) { ret = u; cancel = true; } } } }); return ret; } //------------------------------------------------------------------------------------------- /// /// 获取最近的一个单位 /// /// /// /// /// /// public virtual T GetNearUnit(float x, float y, float range, Predicate select) where T : ZoneObject { T min = null; float min_len = float.MaxValue; float r2 = range * range; ForEachNearObjects(x, y, range, (T u, ref bool cancel) => { if (select(u)) { float len = MathVector.getDistanceSquare(u.X, u.Y, x, y); if (len <= r2 && min_len > len) { min_len = len; min = u; } } }); return min; } /// /// 获取最近的一个单位 /// /// /// /// /// public virtual ZoneUnit GetNearTarget(ZoneActor owner, float range, SkillTemplate.CastTarget expect = SkillTemplate.CastTarget.Enemy) { return GetNearUnit(owner.X, owner.Y, range, (u) => { return IsAttackable(owner, u, expect); }); } /// /// 获取最近可检取单位 /// /// /// public ZoneItem GetNearPickableItem(ZoneActor owner) { if (mSpaceDiv != null) { return mSpaceDiv.GetNearPickableItem(owner); } else if (mObjectes != null) { return mObjectes.GetNearPickableItem(owner); } else { return null; } } public ZoneItem GetNearPopPanelItem(ZoneActor owner) { if (mSpaceDiv != null) { return mSpaceDiv.GetNearPopPanelItem(owner); } else if(mObjectes != null) { return mObjectes.GetNearPopPanelItem(owner); } else { return null; } } /// /// 获取掉落单位单位 /// /// /// public ZoneItem GetPickableItem() { return mObjectes.GetDropItem(); } /// /// 判断是否可检取 /// /// /// /// 不碰撞检测 /// public virtual bool IsPickableItem(ZoneActor owner, ZoneItem item, bool no_touch = false) { if (no_touch || CMath.intersectRound(item.X, item.Y, item.Info.BodySize, owner.X, owner.Y, owner.Info.BodySize)) { if (item.Info.Pickable && (item.Info.DropForAll || item.Force == owner.Force)) { return true; } } return false; } public virtual bool IsCanPickItem(ZoneActor owner, ZoneItem item) { return IsPickableItem(owner, item); } //------------------------------------------------------------------------------------------- [Obsolete] public virtual List GetSkillAttackableUnits(ZoneUnit src, SkillTemplate skill) { List list = new List(); GetSkillAttackableUnits(src, skill, list); return list; } /// /// 获取技能可打到的单位 /// /// /// /// public virtual void GetSkillAttackableUnits(ZoneUnit src, SkillTemplate skill, List list) { float range = src.GetSkillAttackRange(skill); ForEachNearObjects(src.X, src.Y, range, (ZoneUnit u, ref bool cancel) => { if (IsAttackable(src, u, skill.ExpectTarget)) { if (CMath.intersectRound(src.X, src.Y, range, u.X, u.Y, u.Info.BodyHitSize)) { list.Add(u); } } }); } //------------------------------------------------------------------------------------------- #region TERRAIN private ZoneManhattanMap path_terrain_data; private AstarManhattan path_finder; private ManhattanMapAreaGenerator path_terrain_area_gen; protected virtual void InitTerrain(ClientEnterScene msg, out ZoneManhattanMap terrain_data, out AstarManhattan path_finder, out ManhattanMapAreaGenerator area_gen) { if (msg.sender is Zone.Instance.InstanceZone) { var zone = msg.sender as Zone.Instance.InstanceZone; terrain_data = zone.PathFinderTerrain; path_finder = zone.PathFinder; area_gen = zone.TerrainAreaGenerator; this.IsShareTerrain = true; this.IsIgnoreTerrainTouch = false; } else { var data = mTerrainDataSrc.Clone() as ZoneInfo; terrain_data = new ZoneManhattanMap(data, Templates.TerrainDefinition); path_finder = new AstarManhattan(msg.sceneID, terrain_data, true, msg.spaceDiv); area_gen = new ManhattanMapAreaGenerator(terrain_data.Data); this.IsShareTerrain = false; this.IsIgnoreTerrainTouch = false; } //mData.Terrain = null; } protected virtual void DisposeTerrain() { if (!IsShareTerrain) { if (path_finder != null) { path_finder.Dispose(); } if (path_terrain_data != null) { path_terrain_data.Dispose(); } } this.path_finder = null; this.path_terrain_data = null; this.path_terrain_area_gen = null; } public AstarManhattan PathFinder { get { return path_finder; } } public ZoneManhattanMap PathFinderTerrain { get { return path_terrain_data; } } public ManhattanMapAreaGenerator TerrainAreaGenerator { get { return path_terrain_area_gen; } } /// /// 是否标记为共享寻路数据,表示多个场景共享一个PathFinderTerrain数据; /// 一般客户端多开或者共享服务端Terrain打开此功能。 /// public bool IsShareTerrain { get; protected set; } /// /// 是否忽略本地Decoration碰撞 /// public bool IsIgnoreTerrainTouch { get; protected set; } /// /// 寻路 /// /// /// /// /// /// public virtual AstarManhattan.MWayPoint FindPath(float sx, float sy, float dx, float dy) { AstarManhattan.MWayPoint wp; if (path_finder.findPath(sx, sy, dx, dy, out wp, true) == AstarManhattan.FindPathResult.Cross) { return wp; } return null; } public virtual AstarManhattan.FindPathResult FindPathResult(float sx, float sy, float dx, float dy, out AstarManhattan.MWayPoint wp) { return path_finder.findPath(sx, sy, dx, dy, out wp, true); } /// /// 获取位置所在的编辑器Area /// /// /// /// public ZoneEditorArea GetArea(float x, float y) { if (PathFinder == null) { return null; } var node = PathFinder.GetMapNodeByPos(x, y) as ZoneMapNode; if (node != null) { return node.ClientArea; } return null; } #endregion //-------------------------------------------------------------------------------------------------------// #region SPACE_DIVISION private SpaceDivision mSpaceDiv; public int SpaceDivSize { get; private set; } public int SpaceXCount { get { return (mSpaceDiv != null) ? mSpaceDiv.SpaceXCount : 0; } } public int SpaceYCount { get { return (mSpaceDiv != null) ? mSpaceDiv.SpaceYCount : 0; } } internal void SwapSpace(ZoneObject gu) { if (mSpaceDiv != null) { mSpaceDiv.SwapSpace(gu.mCurrentCellNode, gu.X, gu.Y, false); } } //-------------------------------------------------------------------------------------------------------// /// /// 获取当前坐标附近的所有单位 /// /// /// /// /// is cancel public bool ForEachNearObjects(float x, float y, SpaceDivision.ObjectForEachAction indexer) where T : ZoneObject { if (mSpaceDiv != null) { return mSpaceDiv.ForEachNearObjects(x, y, indexer); } else { var action = new Predicate((obj) => { if (obj is T) { bool cancel = false; indexer(obj as T, ref cancel); return cancel; } return false; }); return mObjectes.ForEachObjects(action); } } /// /// 获取当前坐标附近的所有单位 /// /// /// /// /// /// is cancel public bool ForEachNearObjects(float x, float y, float r, SpaceDivision.ObjectForEachAction indexer) where T : ZoneObject { if (mSpaceDiv != null) { return mSpaceDiv.ForEachNearObjects(x, y, r, indexer); } else { var action = new Predicate((obj) => { if (obj is T) { bool cancel = false; indexer(obj as T, ref cancel); return cancel; } return false; }); return mObjectes.ForEachObjects(action); } } /// /// 获取当前坐标附近的所有单位 /// /// /// /// /// /// /// is cancel public bool ForEachNearObjectsRect(float x1, float y1, float x2, float y2, SpaceDivision.ObjectForEachAction indexer) where T : ZoneObject { if (mSpaceDiv != null) { return mSpaceDiv.ForEachNearObjectsRect(x1, y1, x2, y2, indexer); } else { var action = new Predicate((obj) => { if (obj is T) { bool cancel = false; indexer(obj as T, ref cancel); return cancel; } return false; }); return mObjectes.ForEachObjects(action); } } #endregion } }