Unity3D开发技术研究-构建稀疏空间地图SparseSpatitalMap

一、框架视图

二、关键代码

//================================================================================================================================

//================================================================================================================================

using easyar;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace SpatialMap_Dense_BallGame
{
    public class UIController : MonoBehaviour
    {
        public Text Status;
        public ARSession Session;
        public GameObject Ball;
        public int MaxBallCount = 30;
        public float BallLifetime = 15;

        private Color meshColor;
        private VIOCameraDeviceUnion vioCamera;
        private DenseSpatialMapBuilderFrameFilter dense;
        private List balls = new List();

        private void Awake()
        {
            vioCamera = Session.GetComponentInChildren();
            dense = Session.GetComponentInChildren();
        }

        private void Start()
        {
            meshColor = dense.MeshColor;
        }

        private void Update()
        {
            Status.text = "VIO Device Type: " + (vioCamera.Device == null ? "-" : vioCamera.Device.DeviceType.ToString()) + Environment.NewLine +
                "Tracking Status: " + (Session.WorldRootController == null ? "-" : Session.WorldRootController.TrackingStatus.ToString()) + Environment.NewLine +
                "Dense Mesh Block Count: " + dense.MeshBlocks.Count + Environment.NewLine +
                "Ball Count: " + balls.Count + "/" + MaxBallCount + Environment.NewLine +
                Environment.NewLine +
                "Gesture Instruction" + Environment.NewLine +
                "\tShoot Ball: Tap Screen";

            if (Input.GetMouseButtonDown(0) && Input.touchCount > 0 && !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.touches[0].position);
                var launchPoint = Camera.main.transform;
                var ball = Instantiate(Ball, launchPoint.position, launchPoint.rotation);
                var rigid = ball.GetComponent();
                rigid.velocity = Vector3.zero;
                rigid.AddForce(ray.direction * 15f + Vector3.up * 5f);
                if (balls.Count > 0 && balls.Count == MaxBallCount)
                {
                    Destroy(balls[0]);
                    balls.RemoveAt(0);
                }
                balls.Add(ball);
                StartCoroutine(Kill(ball, BallLifetime));
            }
        }

        public void RenderMesh(bool show)
        {
            if (!dense)
            {
                return;
            }
            dense.RenderMesh = show;
        }


        public void TransparentMesh(bool trans)
        {
            if (!dense)
            {
                return;
            }
            dense.MeshColor = trans ? Color.clear : meshColor;
        }

        private IEnumerator Kill(GameObject ball, float lifetime)
        {
            yield return new WaitForSeconds(lifetime);
            if (balls.Remove(ball)) { Destroy(ball); }
        }
    }
}

//================================================================================================================================
//

//================================================================================================================================

using easyar;
using System;
using System.Collections.Generic;

namespace SpatialMap_SparseSpatialMap
{
    [Serializable]
    public class MapMeta
    {
        public SparseSpatialMapController.MapManagerSourceData Map = new SparseSpatialMapController.MapManagerSourceData();
        public List Props = new List();

        public MapMeta(SparseSpatialMapController.SparseSpatialMapInfo map, List props)
        {
            Map = new SparseSpatialMapController.MapManagerSourceData() { Name = map.Name, ID = map.ID };
            Props = props;
        }

        [Serializable]
        public class PropInfo
        {
            public string Name = string.Empty;
            public float[] Position = new float[3];
            public float[] Rotation = new float[4];
            public float[] Scale = new float[3];
        }
    }
}

//================================================================================================================================
//

//================================================================================================================================

using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace SpatialMap_SparseSpatialMap
{
    public class MapMetaManager
    {
        private static readonly string root = Application.persistentDataPath + "/SparseSpatialMap";

        public static List LoadAll()
        {
            var metas = new List();
            var dirRoot = GetRootPath();
            try
            {
                foreach (var path in Directory.GetFiles(dirRoot, "*.meta"))
                {
                    try
                    {
                        metas.Add(JsonUtility.FromJson(File.ReadAllText(path)));
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogError(e.Message);
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError(e.Message);
            }
            return metas;
        }

        public static bool Save(MapMeta meta)
        {
            try
            {
                File.WriteAllText(GetPath(meta.Map.ID), JsonUtility.ToJson(meta));
            }
            catch (System.Exception e)
            {
                Debug.LogError(e.Message);
                return false;
            }
            return true;
        }

        public static bool Delete(MapMeta meta)
        {
            if (!File.Exists(GetPath(meta.Map.ID)))
            {
                return false;
            }
            try
            {
                File.Delete(GetPath(meta.Map.ID));
            }
            catch (System.Exception e)
            {
                Debug.LogError(e.Message);
                return false;
            }
            return true;
        }

        private static string GetRootPath()
        {
            if (!File.Exists(root))
            {
                Directory.CreateDirectory(root);
            }
            return root;
        }

        private static string GetPath(string id)
        {
            return GetRootPath() + "/" + id + ".meta";
        }
    }
}

//================================================================================================================================
//

//================================================================================================================================

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

namespace SpatialMap_SparseSpatialMap
{
    public class PropCollection : MonoBehaviour
    {
        public static PropCollection Instance;
        public List Templets = new List();

        private void Awake()
        {
            Instance = this;
        }

        [Serializable]
        public class Templet
        {
            public GameObject Object;
            public Sprite Icon;
        }
    }
}

//================================================================================================================================

//================================================================================================================================

using easyar;
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Video;

namespace SpatialMap_SparseSpatialMap
{
    [RequireComponent(typeof(MeshRenderer), typeof(UnityEngine.Video.VideoPlayer))]
    public class VideoPlayerAgent : MonoBehaviour
    {
        public string VideoInStreamingAssets;

        private UnityEngine.Video.VideoPlayer player;
        private bool ready;
        private bool playable = true;

        public bool Playable
        {
            get { return playable; }
            set
            {
                playable = value;
                StatusChanged();
            }
        }

        private void OnEnable()
        {
            StatusChanged();
        }

        private void Start()
        {
            player = GetComponent();
            player.source = VideoSource.Url;

            var path = Application.streamingAssetsPath + "/" + VideoInStreamingAssets;
            if (Application.platform == RuntimePlatform.Android)
            {
                path = Application.persistentDataPath + "/" + VideoInStreamingAssets;

                {
                    // Workaround Unity bug: https://issuetracker.unity3d.com/issues/android-video-player-cannot-play-files-located-in-the-persistent-data-directory-on-android-10
                    // more info in this thread: https://forum.unity.com/threads/error-videoplayer-on-android.742451/
                    // If you are using Unity versions with this issue fixed, you can safely skip this code block
                    int sdkVersion = 0;
#if UNITY_ANDROID && !UNITY_EDITOR
                    using (var buildVersion = new AndroidJavaClass("android.os.Build$VERSION"))
                    {
                        sdkVersion = buildVersion.GetStatic("SDK_INT");
                    }
#endif
                    if (sdkVersion >= 29)
                    {
                        GUIPopup.EnqueueMessage("Use web video to workaround Unity VideoPlayer bug on Android Q\nthe video play may be slow", 5);
                        path = "https://staticfile-cdn.sightp.com/easyar/video/" + Path.GetFileName(VideoInStreamingAssets);
                    }
                }
            }

            // Note: Use the Unity VideoPlayer in your own way.
            // We use video file in StreamingAssets in the samples only to keep compatiblity.
            // Some versions of Unity will have strange behaviors if video in resources.
            if (Application.platform == RuntimePlatform.Android && !File.Exists(path) && !path.StartsWith("https://"))
            {
                StartCoroutine(FileUtil.LoadFile(VideoInStreamingAssets, PathType.StreamingAssets, (data) =>
                {
                    StartCoroutine(WriteFile(path, data));
                }));
            }
            else
            {
                player.url = FileUtil.PathToUrl(path);
                ready = true;
                StatusChanged();
            }
        }

        private IEnumerator WriteFile(string path, byte[] data)
        {
            if (data == null || data.Length <= 0)
            {
                yield break;
            }

            bool finished = false;
            EasyARController.Instance.Worker.Run(() =>
            {
                var dir = Path.GetDirectoryName(path);
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                if (!File.Exists(path))
                {
                    File.WriteAllBytes(path, data);
                }
                finished = true;
            });

            while (!finished)
            {
                yield return 0;
            }
            player.url = FileUtil.PathToUrl(path);
            ready = true;
            StatusChanged();
        }

        private void StatusChanged()
        {
            if (!ready)
            {
                return;
            }
            if (playable)
            {
                player.Play();
            }
            else
            {
                player.Pause();
            }
        }
    }
}

//================================================================================================================================

//================================================================================================================================

using easyar;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class CreateViewController : MonoBehaviour
    {
        public GameObject Tips;
        public GameObject UploadPopup;
        public GameObject InfoWithPreview;
        public GameObject InfoWithoutPreview;
        public InputField MapNameInput;
        public Button UploadOKButton;
        public Button UploadCancelButton;
        public Button SaveButton;
        public Button TipsButton;
        public Button SnapshotButton;
        public Toggle PreviewToggle;
        public RawImage PreviewImage;
        public UnityEngine.UI.Image PreviewImageBorder;
        public Text SaveStatus;

        private MapSession mapSession;
        private bool isTipsOn;
        private bool withPreview = true;
        private string mapName;
        private Texture2D capturedImage;
        private int uploadingTime;

        private void OnEnable()
        {
            TipsButton.gameObject.SetActive(true);
            SaveButton.gameObject.SetActive(true);
            SaveButton.interactable = false;

            PreviewToggle.isOn = true;

            isTipsOn = false;
            Tips.SetActive(false);

            StopUploadUI();
            UploadPopup.transform.localScale = Vector3.zero;
            UploadPopup.gameObject.SetActive(false);
            var buttonText = UploadOKButton.transform.Find("Text").GetComponent();
            buttonText.text = "OK";
        }

        private void Update()
        {
            if ((mapSession.MapWorker.LocalizedMap == null || mapSession.MapWorker.LocalizedMap.PointCloud.Count <= 20) && !Application.isEditor)
            {
                SaveButton.interactable = false;
            }
            else
            {
                SaveButton.interactable = true;
            }
        }

        private void OnDestroy()
        {
            if (capturedImage)
            {
                Destroy(capturedImage);
            }
        }

        public void SetMapSession(MapSession session)
        {
            mapSession = session;
        }

        public void Save()
        {
            SaveButton.gameObject.SetActive(false);
            TipsButton.gameObject.SetActive(false);
            UploadPopup.gameObject.SetActive(true);
            MapNameInput.text = mapName = "Map_" + DateTime.Now.ToString("yyyy-MM-dd_HHmm");
            mapSession.MapWorker.enabled = false;
            Snapshot();
            StartCoroutine(ShowPopup(UploadPopup.transform, Vector3.one));
        }

        public void ShowTips()
        {
            isTipsOn = !isTipsOn;
            Tips.SetActive(isTipsOn);
        }

        public void Snapshot()
        {
            var oneShot = Camera.main.gameObject.AddComponent();
            oneShot.Shot(true, (texture) =>
            {
                if (capturedImage)
                {
                    Destroy(capturedImage);
                }
                capturedImage = texture;
                PreviewImage.texture = capturedImage;
            });
        }

        public void TogglePreview(bool enable)
        {
            withPreview = enable;
            InfoWithPreview.SetActive(withPreview);
            InfoWithoutPreview.SetActive(!withPreview);
            PreviewImageBorder.gameObject.SetActive(withPreview);
        }

        public void TogglePreview()
        {
            if (!PreviewToggle.interactable)
            {
                return;
            }
            PreviewToggle.isOn = !withPreview;
        }

        public void OnMapNameChange(string name)
        {
            UploadOKButton.interactable = !string.IsNullOrEmpty(name);
            mapName = name;
        }

        public void Upload()
        {
            using (var buffer = easyar.Buffer.wrapByteArray(capturedImage.GetRawTextureData()))
            using (var image = new easyar.Image(buffer, PixelFormat.RGB888, capturedImage.width, capturedImage.height))
            {
                mapSession.Save(mapName, withPreview ? image : null);
            }
            StartUploadUI();
            StartCoroutine(SavingStatus());
            StartCoroutine(Saving());
        }

        private IEnumerator Saving()
        {
            while (mapSession.IsSaving)
            {
                yield return 0;
            }
            if (mapSession.Saved)
            {
                gameObject.SetActive(false);
                ViewManager.Instance.LoadMainView();
            }
            else
            {
                var buttonText = UploadOKButton.transform.Find("Text").GetComponent();
                buttonText.text = "Retry";
                StopUploadUI();
            }
        }

        private IEnumerator SavingStatus()
        {
            while (mapSession.IsSaving)
            {
                SaveStatus.text = "Upload and Generate Map.";
                for (int i = 0; i < uploadingTime; ++i)
                {
                    SaveStatus.text += ".";
                }
                uploadingTime = (uploadingTime + 1) % 3;
                yield return new WaitForSeconds(1);
            }
            SaveStatus.text = "Upload and Generate Map";
        }

        private static IEnumerator ShowPopup(Transform t, Vector3 scale)
        {
            while (t.transform.localScale.x < scale.x)
            {
                t.transform.localScale += scale * 6 * Time.deltaTime;
                if (t.transform.localScale.x > scale.x)
                {
                    t.transform.localScale = scale;
                }
                yield return 0;
            }
        }

        private void StartUploadUI()
        {
            UploadOKButton.interactable = false;
            PreviewToggle.interactable = false;
            MapNameInput.interactable = false;
            UploadCancelButton.interactable = false;
            SnapshotButton.interactable = false;
            uploadingTime = 0;
        }

        private void StopUploadUI()
        {
            SaveStatus.text = "Upload and Generate Map";
            UploadOKButton.interactable = true;
            PreviewToggle.interactable = true;
            MapNameInput.interactable = true;
            UploadCancelButton.interactable = true;
            SnapshotButton.interactable = true;
            uploadingTime = 0;
        }
    }
}

//================================================================================================================================
//

//================================================================================================================================

using System;
using UnityEngine;

namespace SpatialMap_SparseSpatialMap
{
    public class OneShot : MonoBehaviour
    {
        private bool mirror;
        private Action callback;
        private bool capturing;

        public void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            Graphics.Blit(source, destination);
            if (!capturing) { return; }

            var destTexture = new RenderTexture(Screen.width, Screen.height, 0);
            if (mirror)
            {
                var mat = Instantiate(Resources.Load("Sample_MirrorTexture"));
                mat.mainTexture = source;
                Graphics.Blit(null, destTexture, mat);
            }
            else
            {
                Graphics.Blit(source, destTexture);
            }

            RenderTexture.active = destTexture;
            var texture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
            texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
            texture.Apply();
            RenderTexture.active = null;
            Destroy(destTexture);

            callback(texture);
            Destroy(this);
        }

        public void Shot(bool mirror, Action callback)
        {
            if (callback == null) { return; }
            this.mirror = mirror;
            this.callback = callback;
            capturing = true;
        }
    }
}

//================================================================================================================================
//
//
//================================================================================================================================

using Common;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;

namespace SpatialMap_SparseSpatialMap
{
    public class Dragger : MonoBehaviour
    {
        public GameObject OutlinePrefab;
        public GameObject FreeMove;
        public UnityEngine.UI.Toggle VideoPlayable;

        private RectTransform rectTransform;
        private UnityEngine.UI.Image dummy;
        private TouchController touchControl;
        private MapSession mapSession;
        private GameObject candidate;
        private GameObject selection;
        private bool isOnMap;
        private bool isMoveFree = true;

        public event Action CreateObject;
        public event Action DeleteObject;

        private void Awake()
        {
            rectTransform = GetComponent();
            dummy = GetComponentInChildren(true);
            touchControl = GetComponentInChildren(true);
            OutlinePrefab = Instantiate(OutlinePrefab);
            OutlinePrefab.SetActive(false);
        }

        private void Update()
        {
            transform.position = Input.mousePosition;
            var isEditorOrStandalone = Application.isEditor || Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.OSXPlayer;
            var isPointerOverGameObject = (isEditorOrStandalone && EventSystem.current.IsPointerOverGameObject())
                || (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId));

            if (candidate)
            {
                if (mapSession != null && !isPointerOverGameObject && Input.touchCount > 0)
                {
                    var point = mapSession.HitTestOne(new Vector2(Input.touches[0].position.x / Screen.width, Input.touches[0].position.y / Screen.height));
                    if (point.OnSome)
                    {
                        candidate.transform.position = point.Value + Vector3.up * candidate.transform.localScale.y / 2;
                        isOnMap = true;
                    }
                }

                if (isPointerOverGameObject || !isOnMap)
                {
                    HideCandidate();
                }
                else
                {
                    ShowCandidate();
                }
            }
            else
            {
                if (!isPointerOverGameObject && ((isEditorOrStandalone && Input.GetMouseButtonDown(0)) || (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)))
                {
                    var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                    RaycastHit hitInfo;
                    if (Physics.Raycast(ray, out hitInfo))
                    {
                        StopEdit();
                        StartEdit(hitInfo.collider.gameObject);
                    }
                }
            }

            if (mapSession != null && selection && !isMoveFree)
            {
                if (!isPointerOverGameObject && Input.touchCount == 1)
                {
                    var point = mapSession.HitTestOne(new Vector2(Input.touches[0].position.x / Screen.width, Input.touches[0].position.y / Screen.height));
                    if (point.OnSome)
                    {
                        selection.transform.position = point.Value + Vector3.up * selection.transform.localScale.y / 2;
                    }
                }
            }
        }

        private void OnDisable()
        {
            mapSession = null;
            StopEdit();
        }

        public void SetMapSession(MapSession session)
        {
            mapSession = session;
            if (mapSession.MapWorker)
            {
                mapSession.MapWorker.MapLoad += (arg1, arg2, arg3, arg4) =>
                {
                    StartCoroutine(CheckVideo());
                };
            }
        }

        public void SetFreeMove(bool free)
        {
            isMoveFree = free;
            if (selection)
            {
                if (free)
                {
                    touchControl.TurnOn(selection.transform, Camera.main, true, true, true, true);
                }
                else
                {
                    touchControl.TurnOn(selection.transform, Camera.main, false, false, true, true);
                }
            }
        }

        public void StartCreate(PropCellController controller)
        {
            StopEdit();
            isOnMap = false;
            rectTransform.sizeDelta = controller.GetComponent().sizeDelta;
            dummy.sprite = controller.Templet.Icon;
            dummy.color = Color.white;
            candidate = Instantiate(controller.Templet.Object);
            candidate.name = controller.Templet.Object.name;
            if (candidate)
            {
                var video = candidate.GetComponentInChildren(true);
                if (video) { video.Playable = false; }
            }
            FreeMove.SetActive(false);
            HideCandidate();
        }

        public void StopCreate()
        {
            if (candidate.activeSelf)
            {
                if (CreateObject != null)
                {
                    CreateObject(candidate);
                    StartEdit(candidate);
                }
            }
            else
            {
                Destroy(candidate);
            }

            dummy.gameObject.SetActive(false);
            FreeMove.SetActive(true);
            isOnMap = false;
            candidate = null;
        }

        public void StartEdit(GameObject obj)
        {
            selection = obj;
            if (selection && VideoPlayable.isOn)
            {
                var video = selection.GetComponentInChildren(true);
                if (video) { video.Playable = true; }
            }

            var meshFilter = selection.GetComponentInChildren();
            OutlinePrefab.SetActive(true);
            OutlinePrefab.GetComponent().mesh = meshFilter.mesh;
            OutlinePrefab.transform.parent = meshFilter.transform;
            OutlinePrefab.transform.localPosition = Vector3.zero;
            OutlinePrefab.transform.localRotation = Quaternion.identity;
            OutlinePrefab.transform.localScale = Vector3.one;

            SetFreeMove(isMoveFree);
        }

        public void StopEdit()
        {
            if (selection)
            {
                var video = selection.GetComponentInChildren(true);
                if (video) { video.Playable = false; }
            }
            selection = null;
            if (OutlinePrefab)
            {
                OutlinePrefab.transform.parent = null;
                OutlinePrefab.SetActive(false);
            }
            if (touchControl)
            {
                touchControl.TurnOff();
            }
        }

        public void DeleteSelection()
        {
            if (!selection)
            {
                return;
            }
            if (DeleteObject != null)
            {
                DeleteObject(selection);
            }
            Destroy(selection);
            StopEdit();
        }

        public void ToggleVideoPlayable(bool playable)
        {
            if (selection)
            {
                var video = selection.GetComponentInChildren(true);
                if (video) { video.Playable = playable; }
            }
        }

        private void ShowCandidate()
        {
            dummy.gameObject.SetActive(false);
            candidate.SetActive(true);
        }

        private void HideCandidate()
        {
            candidate.SetActive(false);
            dummy.gameObject.SetActive(true);
        }

        private IEnumerator CheckVideo()
        {
            yield return new WaitForEndOfFrame();
            if (mapSession == null) { yield return 0; }
            foreach (var prop in mapSession.Maps[0].Props)
            {
                if (prop)
                {
                    var video = prop.GetComponentInChildren(true);
                    if (video) { video.Playable = false; }
                }
            }
        }
    }
}

//================================================================================================================================

//================================================================================================================================

using System;
using UnityEngine;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class PropCellController : MonoBehaviour
    {
        public Image Icon;

        public event Action PointerDown;
        public event Action PointerUp;

        public PropCollection.Templet Templet { get; private set; }

        public void SetData(PropCollection.Templet templet)
        {
            Templet = templet;
            Icon.sprite = templet.Icon;
        }

        public void OnPointerDown()
        {
            Icon.color = Color.gray;
            if (PointerDown != null)
            {
                PointerDown();
            }
        }

        public void OnPointerUp()
        {
            Icon.color = Color.white;
            if (PointerUp != null)
            {
                PointerUp();
            }
        }
    }
}

//================================================================================================================================
//
//
//================================================================================================================================

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class PropGridController : MonoBehaviour
    {
        public GameObject PropCellPrefab;
        public Dragger PropDragger;

        private GridLayoutGroup layout;
        private RectTransform rectTransform;
        private List cells = new List();

        private void Start()
        {
            layout = GetComponent();
            rectTransform = GetComponent();

            var cellHeight = rectTransform.rect.height * 0.7f;
            var padding = (int)(cellHeight * 0.1f);
            layout.padding.left = padding;
            layout.cellSize = new Vector2(cellHeight, cellHeight);
            layout.spacing = new Vector2(padding, padding);

            foreach (var templet in PropCollection.Instance.Templets)
            {
                var cell = Instantiate(PropCellPrefab);
                cell.transform.SetParent(transform);
                var controller = cell.GetComponent();
                controller.SetData(templet);
                controller.PointerDown += () =>
                {
                    PropDragger.StartCreate(controller);
                };
                controller.PointerUp += PropDragger.StopCreate;
                cells.Add(controller);
            }
        }

        private void Update()
        {
            var offset = rectTransform.childCount * (layout.cellSize.x + layout.padding.left) + layout.padding.left - rectTransform.rect.width;
            if (offset > 0)
            {
                var offserMax = rectTransform.offsetMax;
                offserMax.x = offset;
                rectTransform.offsetMax = offserMax;
            }
        }
    }
}

//================================================================================================================================
//

//
//================================================================================================================================

using System;
using UnityEngine;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class MapCellController : MonoBehaviour
    {
        public Button DeleteButton;

        private Text text;
        private Image sprite;

        public event Action PointerDown;
        public event Action Delete;

        public bool Selected { get; private set; }
        public MapMeta MapMeta { get; private set; }

        public void Awake()
        {
            text = GetComponentInChildren();
            sprite = GetComponent();
            Cancel();
        }

        public void SetData(MapMeta meta)
        {
            MapMeta = meta;
            text.text = meta.Map.Name;
        }

        public void OnPointerDown()
        {
            if (Selected)
            {
                Cancel();
            }
            else
            {
                Selete();
            }
            if (PointerDown != null)
            {
                PointerDown();
            }
        }

        public virtual void OnDelete()
        {
            if (Delete != null)
            {
                Delete();
            }
        }

        private void Selete()
        {
            sprite.color = new Color(0.2f, 0.58f, 0.99f);
            text.color = new Color(1, 1, 1);
            DeleteButton.gameObject.SetActive(true);
            Selected = true;
        }

        private void Cancel()
        {
            sprite.color = new Color(1, 1, 1);
            text.color = new Color(0.2f, 0.58f, 0.99f);
            DeleteButton.gameObject.SetActive(false);
            Selected = false;
        }
    }
}

//================================================================================================================================
//

//
//================================================================================================================================

using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class MapDockController : MonoBehaviour
    {
        public Button OpenButton;

        private RectTransform rectTransform;

        private void Awake()
        {
            rectTransform = GetComponent();
        }

        private void Update()
        {
            if (((Application.isEditor || Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.OSXPlayer) && Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
                || (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began && !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)))
            {
                ShowAndHide(OpenButton.gameObject.activeSelf);
            }
        }

        public void ShowAndHide(bool isShow)
        {
            StopAllCoroutines();
            if (isShow)
            {
                StartCoroutine(Show());
            }
            else
            {
                StartCoroutine(Hide());
            }
        }

        private IEnumerator Show()
        {
            var offsetMax = rectTransform.offsetMax;
            var offsetMin = rectTransform.offsetMin;
            OpenButton.gameObject.SetActive(false);
            while (offsetMax.x < 0)
            {
                offsetMax.x += Screen.width * Time.deltaTime;
                offsetMin.x += Screen.width * Time.deltaTime;
                rectTransform.offsetMax = offsetMax;
                rectTransform.offsetMin = offsetMin;
                if (offsetMax.x > 0)
                {
                    offsetMax.x = 0;
                    offsetMin.x = 0;
                    rectTransform.offsetMax = offsetMax;
                    rectTransform.offsetMin = offsetMin;
                }
                yield return 0;
            }
        }

        private IEnumerator Hide()
        {
            var offsetMax = rectTransform.offsetMax;
            var offsetMin = rectTransform.offsetMin;
            var width = rectTransform.rect.width + Screen.width * 0.01f;
            while (offsetMax.x > -width && offsetMin.x > -width)
            {
                offsetMax.x -= Screen.width * Time.deltaTime;
                offsetMin.x -= Screen.width * Time.deltaTime;
                rectTransform.offsetMax = offsetMax;
                rectTransform.offsetMin = offsetMin;
                if (offsetMax.x < -width)
                {
                    offsetMax.x = -width;
                    offsetMin.x = -width;
                    rectTransform.offsetMax = offsetMax;
                    rectTransform.offsetMin = offsetMin;
                }
                yield return 0;
            }
            OpenButton.gameObject.SetActive(true);
        }
    }
}

//================================================================================================================================
//

//
//================================================================================================================================

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

namespace SpatialMap_SparseSpatialMap
{
    public class MapGridController : MonoBehaviour
    {
        public GameObject MapCellPrefab;

        private GridLayoutGroup layout;
        private RectTransform rectTransform;
        private List cells = new List();

        public int CellCount { get { return cells.Count; } }

        private void OnEnable()
        {
            foreach (var meta in MapMetaManager.LoadAll())
            {
                var cell = Instantiate(MapCellPrefab);
                cell.transform.SetParent(transform);
                var controller = cell.GetComponent();
                controller.SetData(meta);
                controller.PointerDown += OnCellChange;
                controller.Delete += () =>
                {
                    if (cells.Remove(controller))
                    {
                        MapMetaManager.Delete(controller.MapMeta);
                        Destroy(controller.gameObject);
                        OnCellChange();
                        easyar.GUIPopup.EnqueueMessage(
                            "DELETED: {(Sample) Meta Data}" + Environment.NewLine +
                            "NOT DELETED: {Map Cache, Map on Server}" + Environment.NewLine +
                            "Use recycle bin button to delete map cache" + Environment.NewLine +
                            "Use web develop center to manage maps on server", 5);
                    }
                };
                cells.Add(controller);
            }
        }

        private void Start()
        {
            layout = GetComponent();
            rectTransform = GetComponent();
            var cellWidth = rectTransform.rect.width * 0.9f;
            var padding = (int)(cellWidth * 0.1f);
            layout.padding.top = padding;
            layout.cellSize = new Vector2(cellWidth, cellWidth * 0.5f);
            layout.spacing = new Vector2(padding, padding);
        }

        private void Update()
        {
            var sizeDelta = rectTransform.sizeDelta;
            sizeDelta.y = rectTransform.childCount * (layout.cellSize.y + layout.padding.top) + layout.padding.top;
            rectTransform.sizeDelta = sizeDelta;
        }

        private void OnDisable()
        {
            foreach (var cell in cells)
            {
                if (cell) { Destroy(cell.gameObject); }
            }
            cells.Clear();
        }

        public void ClearAll()
        {
            // Notice:
            //   a) When clear both map cache and map list,
            //      load map will not trigger a download (cache is build when upload),
            //      and statistical request count will not be increased in a subsequent load (when edit or preview).
            //   b) When clear map cache only,
            //      load map after clear (only the first time each map) will trigger a download,
            //      and statistical request count will be increased in a subsequent load (when edit or preview).
            //      Map cache is used after a successful download and will be cleared if SparseSpatialMapManager.clear is called or app uninstalled.
            //
            // More about the statistical request count and limitations for different subscription mode can be found at EasyAR website.

            if (!ViewManager.Instance.MainViewRecycleBinClearMapCacheOnly)
            {
                // clear map meta and the list on UI
                foreach (var cell in cells)
                {
                    if (cell)
                    {
                        MapMetaManager.Delete(cell.MapMeta);
                        Destroy(cell.gameObject);
                    }
                }
                cells.Clear();
            }

            // clear map cache
            MapSession.ClearCache();

            // UI notification
            OnCellChange();
            if (!ViewManager.Instance.MainViewRecycleBinClearMapCacheOnly)
            {
                easyar.GUIPopup.EnqueueMessage(
                    "DELETED: {(Sample) Meta Data, Map Cache}" + Environment.NewLine +
                    "NOT DELETED: {Map on Server}" + Environment.NewLine +
                    "Use web develop center to manage maps on server", 5);
            }
            else
            {
                easyar.GUIPopup.EnqueueMessage(
                    "DELETED: {Map Cache}" + Environment.NewLine +
                    "NOT DELETED: {Map on Server, (Sample) Meta Data}" + Environment.NewLine +
                    "Use web develop center to manage maps on server", 5);
            }
        }

        private void OnCellChange()
        {
            ViewManager.Instance.SelectMaps(cells.Where(cell => cell && cell.Selected).Select(cell => cell.MapMeta).ToList());
        }
    }
}

//================================================================================================================================
//

//
//================================================================================================================================

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace SpatialMap_SparseSpatialMap
{
    public class MainViewController : MonoBehaviour
    {
        public Button Edit;
        public Button Preview;
        public Button Create;
        public GameObject ClearPupup;
        public MapGridController MapGrid;

        private void OnEnable()
        {
            StopAllCoroutines();
            var colors = Create.colors;
            colors.normalColor = new Color(0.2f, 0.58f, 0.988f);
            colors.highlightedColor = new Color(0.192f, 0.557f, 0.949f);
            colors.pressedColor = new Color(0.157f, 0.455f, 0.773f);
            Create.colors = colors;
            ClearPupup.SetActive(false);
            StartCoroutine(Twinkle(Create));
        }

        public void EnableEdit(bool enable)
        {
            Edit.interactable = enable;
        }

        public void EnablePreview(bool enable)
        {
            Preview.interactable = enable;
        }

        private IEnumerator Twinkle(Button button)
        {
            if (MapGrid.CellCount > 0) { yield break; }

            var colors = button.colors;
            var olist = new List
            {
                colors.normalColor,
                colors.highlightedColor,
                colors.pressedColor
            };

            var clist = new List();
            foreach (var color in olist)
            {
                Vector3 hsv;
                Color.RGBToHSV(color, out hsv.x, out hsv.y, out hsv.z);
                clist.Add(hsv);
            }

            float smin = 0.2f;
            float smax = clist[0].y;
            bool increase = false;

            while (MapGrid.CellCount <= 0)
            {
                for (int i = 0; i < clist.Count; ++i)
                {
                    var hsv = clist[i];
                    hsv.y += increase ? 0.2f * Time.deltaTime : -0.2f * Time.deltaTime;
                    clist[i] = hsv;
                }
                if (clist[0].y >= smax)
                {
                    for (int i = 0; i < clist.Count; ++i)
                    {
                        clist[i] = new Vector3(clist[i].x, smax, clist[i].z);
                    }
                    increase = false;
                }
                else if (clist[0].y < smin)
                {
                    for (int i = 0; i < clist.Count; ++i)
                    {
                        clist[i] = new Vector3(clist[i].x, smin, clist[i].z);
                    }
                    increase = true;
                }
                colors.normalColor = Color.HSVToRGB(clist[0].x, clist[0].y, clist[0].z);
                colors.highlightedColor = Color.HSVToRGB(clist[1].x, clist[1].y, clist[1].z);
                colors.pressedColor = Color.HSVToRGB(clist[2].x, clist[2].y, clist[2].z);
                button.colors = colors;
                yield return 0;
            }
            colors.normalColor = olist[0];
            colors.highlightedColor = olist[1];
            colors.pressedColor = olist[2];
            button.colors = colors;
        }
    }
}

你可能感兴趣的:(Unity3D开发技术研究-构建稀疏空间地图SparseSpatitalMap)