This repository has been archived on 2025-04-28. You can view files and clone it, but cannot push or open issues or pull requests.
ARPlusSystem/ARPlusSystem-250418/Assets/ARLocation/Experimental/World Builder/WorldBuilderApplicationCont...

418 lines
15 KiB
C#

using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
namespace ARLocation
{
[RequireComponent(typeof(WorldBuilder))]
public class WorldBuilderApplicationController : MonoBehaviour
{
[System.Serializable]
public class UiElementsSettings
{
public Button CubeBtn;
public Button CylinderBtn;
public Button LogoBtn;
public Button MoveBtn;
public Button RotateBtn;
public Button DeselectBtn;
public Button ClearWorldBtn;
public Button HeightBtn;
public Button DeleteObjectBtn;
public Text DebugText;
}
[System.Serializable]
public class RaycastMarginSettings
{
public float Top;
public float Bottom;
public float Left;
public float Right;
}
[System.Serializable]
public class GeneralSettings
{
public float HeightAdjustmentSensitivity = 0.25f;
public float RotationAdjustmentSensitivity = 1.0f;
public string SaveWorldUrl;
public string RestoreWorldUrl;
public bool SaveToServer;
}
public UiElementsSettings UiElements;
public RaycastMarginSettings RaycastMargins;
public GeneralSettings Settings;
private WorldBuilder worldBuilder;
private PlaceAtLocation selectedObject;
private WorldBuilder.Entry selectedObjectEntry;
enum AppState
{
PlacementMode,
MoveMode,
RotateMode,
HeightMode,
IdleMode
};
class State
{
public string CurrentMeshId;
public AppState AppState;
}
private readonly State state = new State();
private void Awake()
{
worldBuilder = GetComponent<WorldBuilder>();
if (Settings.SaveToServer)
{
worldBuilder.UseLocalStorage = false;
}
Debug.Assert(worldBuilder != null);
Debug.Assert(worldBuilder.PrefabDatabase.Entries.Count > 0);
state.CurrentMeshId = "Cube";
UiElements.CubeBtn.image.color = UiElements.CubeBtn.colors.pressedColor;
SetObjectSelectedUIVisible(false);
InitListeners();
}
IEnumerator Start()
{
if (Settings.SaveToServer)
{
while (!worldBuilder.Initialized)
{
yield return new WaitForSeconds(0.1f);
}
yield return RestoreWorldFromServer();
}
}
IEnumerator RestoreWorldFromServer()
{
var request = UnityWebRequest.Get($"{Settings.RestoreWorldUrl}{worldBuilder.Id}");
yield return request.SendWebRequest();
if (Utils.Misc.WebRequestResultIsError(request))
{
Debug.Log("Failed to restore world from server!");
yield break;
}
Debug.Log(request.downloadHandler.text);
Debug.Log(request.responseCode);
worldBuilder.FromJson(request.downloadHandler.text);
}
IEnumerator SaveWorldToServer()
{
var request = new UnityWebRequest($"{Settings.SaveWorldUrl}{worldBuilder.Id}", "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(worldBuilder.ToJson());
request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (Utils.Misc.WebRequestResultIsError(request))
{
Debug.LogWarning("Failed to save to server!");
}
}
void SetObjectSelectedUIVisible(bool visible)
{
UiElements.MoveBtn.gameObject.SetActive(visible);
UiElements.RotateBtn.gameObject.SetActive(visible);
UiElements.DeselectBtn.gameObject.SetActive(visible);
UiElements.HeightBtn.gameObject.SetActive(visible);
UiElements.DeleteObjectBtn.gameObject.SetActive(visible);
UiElements.CubeBtn.gameObject.SetActive(!visible);
UiElements.CylinderBtn.gameObject.SetActive(!visible);
UiElements.LogoBtn.gameObject.SetActive(!visible);
UiElements.ClearWorldBtn.gameObject.SetActive(!visible);
}
void SetMoveMode()
{
UiElements.MoveBtn.image.color = UiElements.MoveBtn.colors.pressedColor;
UiElements.RotateBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.DeselectBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.HeightBtn.image.color = UiElements.MoveBtn.colors.normalColor;
state.AppState = AppState.MoveMode;
}
void SetRotateMode()
{
UiElements.MoveBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.RotateBtn.image.color = UiElements.MoveBtn.colors.pressedColor;
UiElements.DeselectBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.HeightBtn.image.color = UiElements.MoveBtn.colors.normalColor;
state.AppState = AppState.RotateMode;
}
private void SetHeightMode()
{
UiElements.MoveBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.RotateBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.DeselectBtn.image.color = UiElements.MoveBtn.colors.normalColor;
UiElements.HeightBtn.image.color = UiElements.MoveBtn.colors.pressedColor;
state.AppState = AppState.HeightMode;
}
void InitListeners()
{
UiElements.ClearWorldBtn.onClick.AddListener(() =>
{
worldBuilder.ClearWorld();
SetObjectSelectedUIVisible(false);
state.AppState = AppState.PlacementMode;
});
UiElements.CubeBtn.onClick.AddListener(() =>
{
UiElements.CubeBtn.image.color = UiElements.CubeBtn.colors.pressedColor;
UiElements.CylinderBtn.image.color = UiElements.CylinderBtn.colors.normalColor;
UiElements.LogoBtn.image.color = UiElements.LogoBtn.colors.normalColor;
state.CurrentMeshId = "Cube";
});
UiElements.CylinderBtn.onClick.AddListener(() =>
{
UiElements.CubeBtn.image.color = UiElements.CubeBtn.colors.normalColor;
UiElements.CylinderBtn.image.color = UiElements.CylinderBtn.colors.pressedColor;
UiElements.LogoBtn.image.color = UiElements.LogoBtn.colors.normalColor;
state.CurrentMeshId = "Cylinder";
});
UiElements.LogoBtn.onClick.AddListener(() =>
{
UiElements.CubeBtn.image.color = UiElements.CubeBtn.colors.normalColor;
UiElements.CylinderBtn.image.color = UiElements.CylinderBtn.colors.normalColor;
UiElements.LogoBtn.image.color = UiElements.LogoBtn.colors.pressedColor;
state.CurrentMeshId = "Logo";
});
UiElements.DeselectBtn.onClick.AddListener(() =>
{
state.CurrentMeshId = "Cube";
UiElements.CubeBtn.image.color = UiElements.CubeBtn.colors.pressedColor;
UiElements.CylinderBtn.image.color = UiElements.CylinderBtn.colors.normalColor;
UiElements.LogoBtn.image.color = UiElements.LogoBtn.colors.normalColor;
state.AppState = AppState.PlacementMode;
SetObjectSelectedUIVisible(false);
selectedObjectEntry = null;
});
UiElements.RotateBtn.onClick.AddListener(() =>
{
SetRotateMode();
});
UiElements.MoveBtn.onClick.AddListener(() =>
{
SetMoveMode();
});
UiElements.HeightBtn.onClick.AddListener(() =>
{
SetHeightMode();
});
UiElements.DeleteObjectBtn.onClick.AddListener(() =>
{
worldBuilder.RemoveEntry(selectedObjectEntry);
});
}
void DebugOutput(string text)
{
if (UiElements.DebugText)
{
UiElements.DebugText.text = text;
}
}
void Update()
{
DebugOutput($" c = {ARLocationManager.Instance.MainCamera.transform.position}");
if (Input.touchCount == 1)
{
var touch = Input.touches[0];
if (state.AppState == AppState.RotateMode)
{
if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary)
{
float dx = Settings.RotationAdjustmentSensitivity * (180.0f / Mathf.PI) * touch.deltaPosition.x / Screen.width;
DebugOutput($"dx = {dx}");
if (selectedObjectEntry != null && selectedObjectEntry.Instance != null)
{
var euler = selectedObjectEntry.Instance.transform.localEulerAngles;
selectedObjectEntry.Rotation = euler.y + dx;
selectedObjectEntry.Instance.transform.localEulerAngles = new Vector3(euler.x, selectedObjectEntry.Rotation, euler.z);
}
}
return;
}
else if (state.AppState == AppState.HeightMode)
{
if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary)
{
float dy = Settings.HeightAdjustmentSensitivity * (180.0f / Mathf.PI) * touch.deltaPosition.y / Screen.height;
DebugOutput($"dy = {dy}");
if (selectedObjectEntry != null && selectedObjectEntry.Instance != null)
{
var Location = selectedObjectEntry.Instance.GetComponent<PlaceAtLocation>().Location.Clone();
Location.Altitude += dy;
selectedObjectEntry.Location.Altitude += dy;
selectedObjectEntry.Instance.GetComponent<PlaceAtLocation>().Location = Location;
}
}
return;
}
else if (touch.phase == TouchPhase.Began)
{
if (UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(0)) return;
OnTouchOrClick(touch.position);
}
}
if (Application.isEditor && Input.GetMouseButtonDown(0))
{
OnTouchOrClick(Input.mousePosition);
}
}
private void OnTouchOrClick(Vector2 p)
{
float x = p.x / Screen.width;
float y = p.y / Screen.height;
if (x < RaycastMargins.Left || x > (1 - RaycastMargins.Right)) return;
if (y < RaycastMargins.Bottom || y > (1 - RaycastMargins.Top)) return;
var camera = Application.isEditor ? Camera.main : ARLocationManager.Instance.MainCamera;
var ray = camera.ScreenPointToRay(p);
if (state.AppState == AppState.PlacementMode)
{
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
GameObject go = null;
WorldBuilder.Entry entry = null;
var o = hit.collider.transform;
while (o.parent)
{
Debug.Log(o.name);
entry = worldBuilder.GetWorld().Entries.Find(e => e.Instance == o.gameObject);
if (entry != null)
{
go = entry.Instance;
break;
}
o = o.parent;
}
if (go != null && entry != null)
{
selectedObjectEntry = entry;
SetObjectSelectedUIVisible(true);
SetMoveMode();
return;
}
}
}
float enter;
if (RaycastGround(ray, out enter))
{
var point = ray.GetPoint(enter);
switch (state.AppState)
{
case AppState.PlacementMode:
OnPlacementRaycast(point);
break;
case AppState.MoveMode:
OnMoveModeRaycast(point);
break;
}
}
}
private bool RaycastGround(Ray ray, out float t)
{
var arRaycastManager = FindObjectOfType<ARRaycastManager>();
if (Application.isEditor || arRaycastManager == null)
{
var camera = Application.isEditor ? Camera.main : ARLocationManager.Instance.MainCamera;
var plane = new Plane(new Vector3(0, 1, 0), camera.transform.position - new Vector3(0, 1.4f, 0));
return plane.Raycast(ray, out t);
}
else
{
List<ARRaycastHit> hits = new List<ARRaycastHit>();
arRaycastManager.Raycast(ray, hits, trackableTypes: UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinInfinity);
if (hits.Count > 0)
{
t = hits[0].distance;
return true;
}
else
{
var camera = Application.isEditor ? Camera.main : ARLocationManager.Instance.MainCamera;
var plane = new Plane(new Vector3(0, 1, 0), camera.transform.position - new Vector3(0, 1.4f, 0));
return plane.Raycast(ray, out t);
}
}
}
private void OnMoveModeRaycast(Vector3 point)
{
worldBuilder.MoveEntry(selectedObjectEntry, point);
}
private void OnPlacementRaycast(Vector3 v)
{
Debug.Log("ok!");
worldBuilder.AddEntry(state.CurrentMeshId, v);
if (Settings.SaveToServer)
{
Debug.Log("ok2!");
StartCoroutine(SaveWorldToServer());
}
}
}
}