Пример #1
0
    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);
    }
Пример #2
0
    // 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);
    }
Пример #3
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);
        }
Пример #4
0
        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());
        }
Пример #5
0
        protected override void LoadProperties(Content.IContentManager contentManager, INode node)
        {
            base.LoadProperties(contentManager, node);

            CirclePrimitive circlePrimitive = (CirclePrimitive)node;

            circlePrimitive.Radius = Radius;
        }
Пример #6
0
    CirclePrimitive CreatePrimitive(Transform tf, CapsuleCollider collider)
    {
        CirclePrimitive res = new CirclePrimitive();

        res.center = ConvertTo2d(tf.position);
        res.radius = collider.radius;

        return(res);
    }
Пример #7
0
    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);
    }
Пример #8
0
        // 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());
        }
Пример #9
0
    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);
    }
Пример #10
0
    // 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);
            }
        }
    }
Пример #11
0
        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)));
        }
Пример #12
0
        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());
        }
Пример #13
0
    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);
    }
Пример #14
0
        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);
        }