public void CopyFrom(RangeCfg cfg) { if (cfg == null) { return; } Util.Copy(cfg, this, BindingFlags.Public | BindingFlags.Instance); }
//注意外部一定要传进来一个默认的碰撞点collidePos(比如target),内部不一定会修改这个值 public static bool Hit(Vector3 source, Vector3 dir, Vector3 target, float radius, RangeCfg cfg, float factor = 0f) { float offsetAngle; Vector3 offsetPos; if (factor == 0) { offsetAngle = cfg.beginOffsetAngle; offsetPos = cfg.begingOffsetPos; } else if (factor == 1f) { offsetAngle = cfg.endOffsetAngle; offsetPos = cfg.endOffsetPos; } else { offsetAngle = Mathf.Lerp(cfg.beginOffsetAngle, cfg.endOffsetAngle, factor); offsetPos = Vector3.Lerp(cfg.begingOffsetPos, cfg.endOffsetPos, factor); } //计算偏移后的点 dir.y = 0;//y方向无效 if (offsetAngle != 0) { dir = Quaternion.Euler(0, offsetAngle, 0) * dir; } if (dir == Vector3.zero)//没有方向??? { Debuger.LogError("没有方向"); return(false); } dir.y = 0; if (offsetPos != Vector3.zero) { source += Quaternion.LookRotation(dir) * offsetPos; } if (!HitHeight(source.y, target.y, cfg.heightLimit)) { return(false); } //开始2d相关计算 if (cfg.IngoreRadius)//有时候不希望计算半径 { radius = 0; } target.y = source.y; Vector3 link = target - source; Vector2 source2d = new Vector2(source.x, source.z); Vector2 target2d = new Vector2(target.x, target.z); Vector2 link2d = new Vector2(link.x, link.z); Vector2 dir2d = new Vector2(dir.x, dir.z); float disSq = link2d.sqrMagnitude; float radSq = radius * radius; //如果source在target圆上那么就已经碰撞了 if (disSq <= radSq) { return(true); } //不同类型的碰撞检测 if (cfg.type == enRangeType.circle) { //半径 if (disSq >= cfg.distance * cfg.distance + radSq + 2 * cfg.distance * radius)//a>(b+c) => a^2>(b+c)^2 { return(false); } //计算碰撞的点 //if (needCollidePos) //{ // Vector2 collide2d = source2d + link2d - link2d.normalized * radius; // collidePos.Set(collide2d.x, collidePos.y, collide2d.y); //} return(true); } else if (cfg.type == enRangeType.sector) { //半径 if (disSq >= cfg.distance * cfg.distance + radius * radius + 2 * cfg.distance * radius)//a>(b+c) => a^2>(b+c)^2 { return(false); } //夹角 float angle = Vector2.Angle(dir2d, link2d); if (angle <= cfg.angleLimit)//圆心在扇形内的情况,那么交点和圆一样计算 { ////计算碰撞的点 //if (needCollidePos) //{ // Vector2 collide2d = source2d + link2d - link2d.normalized * radius; // collidePos.Set(collide2d.x, collidePos.y, collide2d.y); //} return(true); } else if (radius == 0)//优化下,如果为0,则判断下扇形内就足够了 { return(false); } else//圆心在扇形外的情况 { //用相对于source方向同一边的扇形的边缘做碰撞检测 Vector3 dirAngle; if (Vector3.Cross(dir, link).y > 0) { dirAngle = Quaternion.Euler(new Vector3(0, cfg.angleLimit, 0)) * dir; } else { dirAngle = Quaternion.Euler(new Vector3(0, -cfg.angleLimit, 0)) * dir; } if (dirAngle.y != 0)//检错下 { Debuger.LogError("计算出来的方向不为2d的"); } //Debug.DrawRay(source + Vector3.up*1, dirAngle*20, Color.yellow, 3); //计算有没有交点 Vector2 dirAngle2d = new Vector2(dirAngle.x, dirAngle.z); Vector2 project2d = Util.Project(link2d, dirAngle2d); //投影在方向上的点(相对于source) Vector2 verticalDir2d = link2d - project2d; //垂线,投影在角色方向上的点到target(相对于source) //Vector3 project = new Vector3(project2d.x,source.y ,project2d.y); //Debug.DrawRay(source + project + Vector3.up * 1, new Vector3(verticalDir2d.x, 0, verticalDir2d.y) , Color.red, 3); float vDirSq = verticalDir2d.sqrMagnitude; if (vDirSq > radSq)//投影点在圆外,那么碰撞不到 { return(false); } if (vDirSq == radSq) //投影点在圆上 { if (angle < 90 && Vector2.Dot(project2d, dirAngle2d) < 0) //如果要求夹角是小于90的那么要判断方向是不是在主角前方 { return(false); } //if (needCollidePos) //{ // Vector2 collide2d = source2d + project2d; // collidePos.Set(collide2d.x, collidePos.y, collide2d.y); //} return(true); } else //投影点在圆内 { if (angle < 90 && Vector2.Dot(project2d, dirAngle2d) < 0)//如果要求夹角是小于90的那么要判断方向是不是在主角前方 { return(false); } //if (needCollidePos) //{ // float d = Mathf.Sqrt(radSq - vDirSq);//交点到投影点的距离,勾股定理求第三边,这里按照之前的判断是肯定能成直角三角形的 // Vector2 collide2d = source2d + project2d - project2d.normalized * d; // collidePos.Set(collide2d.x, collidePos.y, collide2d.y); //} return(true); } } } else if (cfg.type == enRangeType.rect) { //先计算出到角色方向上的投影点 Vector2 project2d = Util.Project(link2d, dir2d); //投影在方向上的点(相对于source) Vector2 verticalDir2d = link2d - project2d; //垂线,投影在角色方向上的点到target(相对于source) float vDirSq = verticalDir2d.sqrMagnitude; Vector3 project = new Vector3(project2d.x, source.y, project2d.y); Vector3 vertical = new Vector3(verticalDir2d.x, 0, verticalDir2d.y); //Debug.DrawRay(source +project+ Vector3.up * 1, vertical, Color.yellow, 3); //宽度限制 if (vDirSq >= cfg.rectLimit * cfg.rectLimit + radSq + 2 * cfg.rectLimit * radius)//a>(b+c) => a^2>(b+c)^2 { return(false); } //长度限制 float halfDis = cfg.distance / 2; //Vector2 center = source2d + dir2d.normalized*cfg.distance/2;//中心点,矩形的中心点 //Vector2 linkCenter2d = target2d-source2d; float hDir = Vector2.Dot(dir2d, project2d) < 0 ? project2d.magnitude + halfDis : Mathf.Abs(project2d.magnitude - halfDis); //算出投影点到中心点的距离 float hDirSq = hDir * hDir; if (hDirSq >= halfDis * halfDis + radSq + 2 * halfDis * radius) //a>(b+c) => a^2>(b+c)^2 { return(false); } //计算碰撞的点 //if (needCollidePos) //{ // Vector2 collide2d = source2d + link2d - link2d.normalized * radius; // collidePos.Set(collide2d.x, collidePos.y, collide2d.y); //} return(true); } else { Debuger.LogError("不能用ColliderUtil系统检测的类型:{0}", cfg.type); } return(false); }
public static void Draw(RangeCfg cfg, DrawGL draw, Vector3 pos, Vector3 dir, Color clr, float factor = 0f) { if (!cfg.showRange) { return; } //碰撞类型的话画调线 if (cfg.type == enRangeType.collider) { if (cfg.heightLimit <= 0) { return; } draw.DrawLine(clr * 0.7f, pos + Vector3.up * cfg.heightLimit, pos - Vector3.up * cfg.heightLimit); return; } //下面是其他类型 //计算偏移后的点 float offsetAngle; Vector3 offsetPos; if (factor == 0) { offsetAngle = cfg.beginOffsetAngle; offsetPos = cfg.begingOffsetPos; } else if (factor == 1f) { offsetAngle = cfg.endOffsetAngle; offsetPos = cfg.endOffsetPos; } else { offsetAngle = Mathf.Lerp(cfg.beginOffsetAngle, cfg.endOffsetAngle, factor); offsetPos = Vector3.Lerp(cfg.begingOffsetPos, cfg.endOffsetPos, factor); } //计算偏移后的点 dir.y = 0;//y方向无效 if (offsetAngle != 0) { dir = Quaternion.Euler(0, offsetAngle, 0) * dir; } if (dir == Vector3.zero)//没有方向??? { return; } dir.y = 0; if (offsetPos != Vector3.zero) { pos += Quaternion.LookRotation(dir) * offsetPos; } float d2 = cfg.distance * 2; if (cfg.type == enRangeType.circle) { Vector3 scale = new Vector3(d2, cfg.heightLimit <= 0 ? 3 : cfg.heightLimit * 2, d2); draw.DrawCylinder(clr * 0.7f, pos, scale, Quaternion.LookRotation(dir)); } else if (cfg.type == enRangeType.sector) { Vector3 scale = new Vector3(d2, cfg.heightLimit <= 0 ? 3 : cfg.heightLimit * 2, d2); draw.DrawSectorCylinder(clr * 0.7f, cfg.angleLimit, pos, scale, Quaternion.LookRotation(dir)); } else if (cfg.type == enRangeType.rect) { pos += dir.normalized * cfg.distance / 2; Vector3 scale = new Vector3(cfg.rectLimit * 2, cfg.heightLimit <= 0 ? 3 : cfg.heightLimit * 2, cfg.distance); draw.DrawBox(clr * 0.7f, pos, scale, Quaternion.LookRotation(dir)); } }