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
}
}