Bouncing Circle

Back
Tags:
Drawing API
Example how to draw bouncing circle on the map.
Usage instructions:
Add this script to map GameObject and start the scene.
Click on the map. A marker and a bouncing circle around it will be created at the point where you clicked.
BouncingCircle.cs
/*         INFINITY CODE         */
/*   https://infinity-code.com   */

using System;
using System.Collections.Generic;
using OnlineMaps;
using UnityEngine;

namespace OnlineMapsExamples
{
    /// <summary>
    /// Example how to draw bouncing circle on the map.
    /// </summary>
    [AddComponentMenu(Utils.ExampleMenuPath + "BouncingCircle")]
    public class BouncingCircle : MonoBehaviour
    {
        /// <summary>
        /// Reference to the map. If not set, the current instance will be used.
        /// </summary>
        public Map map;

        /// <summary>
        /// Animation curve
        /// </summary>
        public AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 1, 1);
        
        /// <summary>
        /// Duration of animation
        /// </summary>
        public float duration = 3;

        /// <summary>
        /// Radius of the circle
        /// </summary>
        public float radiusKM = 0.1f;

        /// <summary>
        /// Number of segments
        /// </summary>
        public int segments = 32;

        private List<BoundingItem> items;

        /// <summary>
        /// This method is called when the script starts
        /// </summary>
        private void Start()
        {
            // If map is not specified, use the current instance.
            if (!map && !(map = Map.instance))
            {
                Debug.LogError("Map not found");
                return;
            }
            
            // Subscribe to click on map event
            map.control.OnClick += OnMapClick;
        }

        /// <summary>
        /// This method is called when a user clicks on a map
        /// </summary>
        private void OnMapClick()
        {
            // Get the coordinates under cursor
            GeoPoint point = map.control.ScreenToLocation();

            // Create a new marker under cursor
            map.marker2DManager.Create(point, "Marker " + map.marker2DManager.count);

            if (items == null) items = new List<BoundingItem>();

            items.Add(new BoundingItem (this, point));
        }
        
        private void Update()
        {
            // If there are no items, we do not need to update them
            if (items == null || items.Count == 0) return;

            // Update items and remove completed
            items.RemoveAll(i => i.Update());

            // Redraw map
            map.Redraw();
        }

        /// <summary>
        /// Class that stores information about the circle
        /// </summary>
        public class BoundingItem
        {
            /// <summary>
            /// Center of the circle
            /// </summary>
            public GeoPoint center;

            /// <summary>
            /// Is the animation completed?
            /// </summary>
            public bool finished;

            /// <summary>
            /// Array of points of the circle
            /// </summary>
            public MercatorPoint[] points;

            /// <summary>
            /// Reference to the BouncingCircle instance
            /// </summary>
            private BouncingCircle instance;

            /// <summary>
            /// Animation progress
            /// </summary>
            private float progress;

            /// <summary>
            /// Polygon that displays the circle
            /// </summary>
            private Polygon polygon;

            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="instance">Reference to the BouncingCircle instance</param>
            /// <param name="center">Center of the circle</param>
            public BoundingItem(BouncingCircle instance, GeoPoint center)
            {
                this.instance = instance;
                this.center = center;
                
                // Create an array of points
                points = new MercatorPoint[instance.segments];
                
                // Create a polygon
                polygon = new Polygon(points, Color.red, 3);
                instance.map.drawingElementManager.Add(polygon);
            }

            /// <summary>
            /// Finish animation
            /// </summary>
            private void Finish()
            {
                progress = 1;
                finished = true;
                    
                // Remove polygon
                instance.map.drawingElementManager.Remove(polygon);
            }

            /// <summary>
            /// Update circle
            /// </summary>
            /// <returns>True - animation is completed, False - otherwise</returns>
            public bool Update()
            {
                // Update animation progress
                progress += Time.deltaTime / instance.duration;
                if (progress >= 1)
                {
                    Finish();
                    return true;
                }

                // Calculate radius
                float radius = instance.radiusKM * instance.curve.Evaluate(progress);

                // Find the coordinate at the desired distance
                GeoPoint distantCoordinate = center.Distant(radius, 90);

                // Get the projection of the map
                Projection projection = instance.map.view.projection;
                
                // Convert the coordinate under cursor to tile position
                MercatorPoint m1 = center.ToMercator(projection);

                // Convert remote coordinate to tile position
                MercatorPoint m2 = distantCoordinate.ToMercator(projection);

                // Calculate radius in tiles
                double r = m2.x - m1.x;

                int segments = points.Length;

                // Calculate a step
                double step = 360d / segments;

                // Calculate each point of circle
                for (int i = 0; i < segments; i++)
                {
                    double px = m1.x + Math.Cos(step * i * Constants.Deg2Rad) * r;
                    double py = m1.y + Math.Sin(step * i * Constants.Deg2Rad) * r;
                    points[i] = new MercatorPoint(px, py);
                }
                
                // Update polygon
                polygon.SetPoints(points);

                return false;
            }
        }
    }
}