Drag and zoom inertia

Back
Tags:
Math
Example of how to make drag and zoom inertia for the map.
Usage instructions:
Add this script to map GameObject and start the scene.
Drag the map to see the inertia.
DragAndZoomInertia.cs
/*         INFINITY CODE         */
/*   https://infinity-code.com   */

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace InfinityCode.OnlineMapsExamples
{
    /// <summary>
    /// Example of how to make drag and zoom inertia for the map.
    /// </summary>
    [AddComponentMenu("Infinity Code/Online Maps/Examples (API Usage)/DragAndZoomInertia")]
    public class DragAndZoomInertia : MonoBehaviour
    {
        /// <summary>
        /// Reference to the map. If not specified, the current instance will be used.
        /// </summary>
        public OnlineMaps map;
        
        /// <summary>
        /// Deceleration rate (0 - 1).
        /// </summary>
        public float friction = 0.9f;

        private bool isInteract;
        private List<double> speedX;
        private List<double> speedY;
        private List<float> speedZ;
        private double rsX;
        private double rsY;
        private float rsZ;
        private double ptx;
        private double pty;
        private float pz;
        private const int maxSamples = 5;

        private OnlineMapsControlBase control;

        private void Start()
        {
            if (map == null) map = OnlineMaps.instance;
            control = map.control;

            // Subscribe to map events
            control.OnMapPress += OnMapPress;
            control.OnMapRelease += OnMapRelease;

            // Initialize arrays of speed
            speedX = new List<double>(maxSamples);
            speedY = new List<double>(maxSamples);
            speedZ = new List<float>(maxSamples);
        }

        private void FixedUpdate()
        {
            if (isInteract && control.GetTouchCount() == 0) isInteract = false;

            // If there is interaction with the map.
            if (isInteract)
            {
                // Calculates speeds.
                double tx, ty;
                map.GetTilePosition(out tx, out ty, 20);

                double cSpeedX = tx - ptx;
                double cSpeedY = ty - pty;
                float cSpeedZ = map.floatZoom - pz;

                int halfMax = 1 << 19;
                int max = 1 << 20;
                if (cSpeedX > halfMax) cSpeedX -= max;
                else if (cSpeedX < -halfMax) cSpeedX += max;

                while (speedX.Count >= maxSamples) speedX.RemoveAt(0);
                while (speedY.Count >= maxSamples) speedY.RemoveAt(0);
                while (speedZ.Count >= maxSamples) speedZ.RemoveAt(0);

                speedX.Add(cSpeedX);
                speedY.Add(cSpeedY);
                speedZ.Add(cSpeedZ);

                ptx = tx;
                pty = ty;
                pz = map.floatZoom;
            }
            // If no interaction with the map.
            else if (rsX * rsX + rsY * rsY > 0.01 || rsZ > 0.01)
            {
                // Continue to move the map with the current speed.
                ptx += rsX;
                pty += rsY;

                int max = 1 << 20;
                if (ptx >= max) ptx -= max;
                else if (ptx < 0) ptx += max;

                map.SetTilePosition(ptx, pty, 20);
                map.floatZoom += rsZ;

                // Reduces the current speed.
                rsX *= friction;
                rsY *= friction;
                rsZ *= friction;
            }
        }

        /// <summary>
        /// This method is called when you press on the map.
        /// </summary>
        private void OnMapPress()
        {
            // Get tile coordinates of map
            map.GetTilePosition(out ptx, out pty, 20);
            pz = map.floatZoom;

            // Is marked, that is the interaction with the map.
            isInteract = true;
        }

        /// <summary>
        /// This method is called when you release on the map.
        /// </summary>
        private void OnMapRelease()
        {
            if (control.GetTouchCount() != 0) return;

            // Is marked, that ended the interaction with the map.
            isInteract = false;

            // Calculates the average speed.
            rsX = speedX.Count > 0 ? speedX.Average() : 0;
            rsY = speedY.Count > 0 ? speedY.Average() : 0;
            rsZ = speedZ.Count > 0 ? speedZ.Average() : 0;

            speedX.Clear();
            speedY.Clear();
            speedZ.Clear();
        }
    }
}