public Face2D Build(CameraScene cameraScene, CirclePrimitive player, CirclePrimitive target) { // 3 steps: // 1. Make face from room bounds // 2. For each primitive make the occlusion field and cut it from the face // 3. Cut middle zone from the face, in this zone both the player and the target are visible, // but there aren't any camera angle to see them both Face2D res = MakeStartField(cameraScene.RoomBound); BooleanOperator bop = new BooleanOperator(); foreach (var circle_obstacle in cameraScene.Circles) { res = bop.Intersect(res, MakeOcclusionLoop(player, circle_obstacle, -0.1f)); } res = bop.Intersect(res, MakeOcclusionLoop(player, target, 0.0f)); foreach (var circle_obstacle in cameraScene.Circles) { res = bop.Intersect(res, MakeOcclusionLoop(target, circle_obstacle, 0.1f)); } res = bop.Intersect(res, MakeMiddleZone(player, target)); return(res); }
// Update is called once per frame void Update() { var player = field_builder.player; var target = field_builder.target; CirclePrimitive player_primitive = new CirclePrimitive(); player_primitive.center = ConvertTo2d(player.gameObject.transform.position); player_primitive.radius = player.radius * player.gameObject.transform.localScale.magnitude; CirclePrimitive target_primitive = new CirclePrimitive(); target_primitive.center = ConvertTo2d(target.gameObject.transform.position); target_primitive.radius = target.radius * target.gameObject.transform.localScale.magnitude; Face2D field = field_builder.Build(field_builder.scene_loader.Scene, player_primitive, target_primitive); Vector2 anchor_pos = ConvertTo2d(anchor.position); if (!field.IsPointInside(anchor_pos)) { anchor_pos = field.GetClosestPointOnBorder(anchor_pos); } var new_lookat = field_builder.MakeMiddlePrimitive(player_primitive, target_primitive).center; lookat.position = new Vector3(new_lookat.x, lookat.position.y, new_lookat.y); cam_operator.RefreshDestination(new Vector3(anchor_pos.x, anchor.position.y, anchor_pos.y), Vector3.zero, 0, time); cam_operator.DBG_Show(0); }
public void Add(Vector3 center, Vector3 normal, float radius, Color color, float hideAt = 0) { var primitive = freePrimitives.First; if (primitive == null) { primitive = new CirclePrimitive( ); } else { primitive.Remove( ); } normal = normal.normalized; Vector3 forward = normal == Vector3.up ? Vector3.ProjectOnPlane(Vector3.forward, normal).normalized : Vector3.ProjectOnPlane(Vector3.up, normal).normalized; Vector3 right = Vector3.Cross(normal, forward); primitive.Value.center = center; primitive.Value.forward = forward; primitive.Value.right = right; primitive.Value.radius = radius; primitive.Value.color = color; primitive.Value.hideAt = hideAt; usedPrimitives.AddFirst(primitive); }
internal static bool CheckLineToCircleCollision(LinePrimitive line, CirclePrimitive circle) { #region Argument Check if (line == null) { throw new ArgumentNullException("line"); } if (circle == null) { throw new ArgumentNullException("circle"); } #endregion // It's enough to check only one of the line's points if (IsPointInCircle(line.Start, circle)) { return(true); } var circleDirection = line.Start - circle.Center; var a = line.Direction * line.Direction; var b = 2 * (circleDirection * line.Direction); var c = (circleDirection * circleDirection) - circle.RadiusSquared; var d = b.Sqr() - 4 * a * c; return(d.IsPositiveOrZero()); }
protected override void LoadProperties(Content.IContentManager contentManager, INode node) { base.LoadProperties(contentManager, node); CirclePrimitive circlePrimitive = (CirclePrimitive)node; circlePrimitive.Radius = Radius; }
CirclePrimitive CreatePrimitive(Transform tf, CapsuleCollider collider) { CirclePrimitive res = new CirclePrimitive(); res.center = ConvertTo2d(tf.position); res.radius = collider.radius; return(res); }
public CirclePrimitive MakeMiddlePrimitive(CirclePrimitive player, CirclePrimitive target) { CirclePrimitive res = new CirclePrimitive(); Vector2 p2t = target.center - player.center; res.radius = ((p2t.magnitude + player.radius * 5 + target.radius * 3) / 2); Vector2 p2t_norm = p2t.normalized; res.center = player.center - p2t_norm * player.radius * 5 + p2t_norm * res.radius; return(res); }
// Is the point inside or on the circle? public static bool IsPointInCircle(Point2D point, CirclePrimitive circle) { #region Argument Check if (circle == null) { throw new ArgumentNullException("circle"); } #endregion // If a point is on a circle, it is considered to be in this circle return((point.GetDistanceSquared(circle.Center) - circle.RadiusSquared).IsNegativeOrZero()); }
private List <ICuttableEdge> MakeOcclusionLoop(CirclePrimitive player, CirclePrimitive obstacle, float radius_shift) { Vector2 center2center = player.center - obstacle.center; float cp_param = Mathf.Atan2(center2center.y, center2center.x); float param_spread = Mathf.Acos(Mathf.Min((player.radius + obstacle.radius) / center2center.magnitude, 1.0f)); CircleEdge circle_edge = new CircleEdge( new CircleArc { center = obstacle.center, radius = obstacle.radius * (1 + radius_shift), t_start = cp_param - param_spread, t_end = cp_param + param_spread }, false); var circle_end = circle_edge.Eval(0); LineEdge edge1 = new LineEdge( new LineSegment { p0 = circle_end.pt, p1 = circle_end.pt - circle_end.dir * 100 }, false); circle_end = circle_edge.Eval(1); LineEdge edge2 = new LineEdge( new LineSegment { p0 = circle_end.pt, p1 = circle_end.pt + circle_end.dir * 100 }, true); List <ICuttableEdge> res = new List <ICuttableEdge>(); res.Add(edge1); for (int i = 0; i < 5; ++i) { res.Add(new LineEdge(new LineSegment { p0 = circle_edge.Eval(1.0f * i / 5).pt, p1 = circle_edge.Eval(1.0f * (i + 1) / 5).pt }, true)); } res.Add(edge2); return(res); }
// Update is called once per frame void Update() { CirclePrimitive player_primitive = new CirclePrimitive(); player_primitive.center = Utils.ConvertTo2d(player.gameObject.transform.position); player_primitive.radius = player.radius * player.gameObject.transform.localScale.magnitude; CirclePrimitive target_primitive = new CirclePrimitive(); target_primitive.center = Utils.ConvertTo2d(target.gameObject.transform.position); target_primitive.radius = target.radius * target.gameObject.transform.localScale.magnitude; if (show_player) { player_primitive.DBG_Show(Color.red); target_primitive.DBG_Show(Color.red); } if (show_occlusion_fields) { foreach (var circle_obstacle in scene_loader.Scene.Circles) { var loop = MakeOcclusionLoop(player_primitive, circle_obstacle, 0.0f); foreach (var edge in loop) { edge.DBG_Show(Color.blue); } } } if (show_visibility_field) { Build(scene_loader.Scene, player_primitive, target_primitive).DBG_Show(Color.magenta); } if (show_middle_zone) { var loop = MakeMiddleZone(player_primitive, target_primitive); foreach (var edge in loop) { edge.DBG_Show(Color.yellow); } } }
internal static bool CheckCircleToPolygonCollision(CirclePrimitive circle, ConvexPolygonPrimitive polygon) { #region Argument Check if (circle == null) { throw new ArgumentNullException("circle"); } if (polygon == null) { throw new ArgumentNullException("polygon"); } #endregion return(IsPointInPolygon(circle.Center, polygon) || polygon.Edges.Any(edge => CheckLineToCircleCollision(edge, circle))); }
internal static bool CheckCircleToCircleCollision(CirclePrimitive circle1, CirclePrimitive circle2) { #region Argument Check if (circle1 == null) { throw new ArgumentNullException("circle1"); } if (circle2 == null) { throw new ArgumentNullException("circle2"); } #endregion var centerDistanceSqr = circle1.Center.GetDistanceSquared(circle2.Center); var radiusSumSqr = (circle1.Radius + circle2.Radius).Sqr(); var difference = radiusSumSqr - centerDistanceSqr; return(difference > 0f || difference.IsZero()); }
private List <ICuttableEdge> MakeMiddleZone(CirclePrimitive player, CirclePrimitive target) { // 4 circle edges CircleArc arc = new CircleArc(); CirclePrimitive primitive = MakeMiddlePrimitive(player, target); arc.radius = primitive.radius; arc.center = primitive.center; arc.t_start = 0; arc.t_end = Mathf.PI * 2; var res = new List <ICuttableEdge>(); var circle_edge = new CircleEdge(arc, false); for (int i = 0; i < 100; ++i) { res.Add(new LineEdge(new LineSegment { p0 = circle_edge.Eval(1.0f * i / 100).pt, p1 = circle_edge.Eval(1.0f * (i + 1) / 100).pt }, true)); } return(res); }
private MoveDirection FindSafestMove(IEnumerable <ShotViewData> allShots, ChickenUnitState unitState) { var safetyCircle = new CirclePrimitive(unitState.Position, _dangerousRadius); var dangerousShots = new List <ShotViewData>(unitState.View.Shots.Count); //// ReSharper disable once LoopCanBeConvertedToQuery foreach (var shot in allShots) { if (unitState.Position.GetDistance(shot.Position) > _tooCloseShot) { continue; } var shotDirection = shot.Angle.ToUnitVector(); var shotToUnitVector = unitState.Position - shot.Position; var angle = shotDirection.GetAngle(shotToUnitVector); if (angle.DegreeValue.Abs() >= MathHelper.QuarterRevolutionDegrees) { continue; } var shotLine = new LinePrimitive( shot.Position, shot.Position + shot.Angle.ToUnitVector() * _boardDiagonalSize); if (CollisionDetector.CheckCollision(shotLine, safetyCircle)) { dangerousShots.Add(shot); } } if (dangerousShots.Count <= 0) { return(null); } var safeMoves = GameHelper.BasicMoveDirections.ToDictionary(item => item, item => 0); foreach (var dangerousShot in dangerousShots) { var shotVector = dangerousShot.Angle.ToUnitVector(); var maxDistanceMove = MoveDirection.None; var maxDistanceSqr = float.MinValue; foreach (var moveDirection in GameHelper.BasicMoveDirections) { var potentialPosition = GameHelper.GetNewPosition( unitState.Position, unitState.BeakAngle, moveDirection, GameConstants.ChickenUnit.DefaultRectilinearSpeed); var shotToUnitVector = potentialPosition - dangerousShot.Position; var shotToUnitVectorLengthSquared = shotToUnitVector.GetLengthSquared(); var angleCosine = shotVector.GetAngleCosine(shotToUnitVector); var distanceSqr = shotToUnitVectorLengthSquared - shotToUnitVectorLengthSquared * angleCosine.Sqr(); if (distanceSqr > maxDistanceSqr) { maxDistanceSqr = distanceSqr; maxDistanceMove = moveDirection; } } safeMoves[maxDistanceMove]++; } var actuallySafeMovePair = safeMoves .Where(pair => pair.Value > 0) .OrderByDescending(pair => pair.Value) .FirstOrDefault(); return(actuallySafeMovePair.Value > 0 ? actuallySafeMovePair.Key : null); }