309 lines
9.0 KiB
C#
309 lines
9.0 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public enum BuildAxis
|
|
{
|
|
X, // YZ plane
|
|
Y, // XZ plane (horizontal)
|
|
Z // XY plane
|
|
}
|
|
|
|
public class VirtualPlatformManager : MonoBehaviour
|
|
{
|
|
private static VirtualPlatformManager instance;
|
|
|
|
[Header("Platform Settings")]
|
|
[SerializeField] private float platformThickness = 0.1f;
|
|
|
|
[Header("Visual Settings")]
|
|
[SerializeField] private bool showGrid = true;
|
|
[SerializeField] private float gridSpacing = 1f;
|
|
[SerializeField] private int gridExtent = 50; // How many grid lines from center
|
|
[SerializeField] private float lineWidth = 0.5f;
|
|
[SerializeField] private Color gridColor = new Color(1f, 1f, 1f, 0.3f);
|
|
[SerializeField] private Material gridMaterial;
|
|
|
|
[Header("Current Platform")]
|
|
[SerializeField] private BuildAxis currentAxis = BuildAxis.Y;
|
|
[SerializeField] private float currentDistance = 0f;
|
|
|
|
private List<LineRenderer> gridLines = new List<LineRenderer>();
|
|
|
|
private GameObject currentPlatform;
|
|
private GameObject gridVisual;
|
|
private GameObject colliderObj;
|
|
private BoxCollider platformCollider;
|
|
private Camera mainCamera;
|
|
|
|
private void Awake()
|
|
{
|
|
if (instance == null) instance = this;
|
|
else Destroy(this.gameObject);
|
|
}
|
|
public static VirtualPlatformManager getInstance() => instance;
|
|
|
|
private void Start()
|
|
{
|
|
mainCamera = Camera.main;
|
|
|
|
if (gridMaterial == null)
|
|
{
|
|
gridMaterial = new Material(Shader.Find("Sprites/Default"));
|
|
}
|
|
|
|
CreatePlatform();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (showGrid && gridVisual != null)
|
|
{
|
|
UpdateGridPosition();
|
|
}
|
|
|
|
// Update collider position and size to match grid
|
|
if (platformCollider != null)
|
|
{
|
|
UpdateColliderPosition();
|
|
}
|
|
}
|
|
|
|
private void UpdateGridPosition()
|
|
{
|
|
Vector3 cameraPos = mainCamera.transform.position;
|
|
Vector3 planeOrigin = GetPlatformOrigin();
|
|
Vector3 axis1, axis2;
|
|
GetPlatformAxes(out axis1, out axis2);
|
|
|
|
Vector3 relativePos = cameraPos - planeOrigin;
|
|
float coord1 = Mathf.Round(Vector3.Dot(relativePos, axis1) / gridSpacing) * gridSpacing;
|
|
float coord2 = Mathf.Round(Vector3.Dot(relativePos, axis2) / gridSpacing) * gridSpacing;
|
|
|
|
Vector3 gridCenter = planeOrigin + axis1 * coord1 + axis2 * coord2;
|
|
|
|
UpdateGridLines(gridCenter, axis1, axis2);
|
|
}
|
|
|
|
private void UpdateColliderPosition()
|
|
{
|
|
Vector3 cameraPos = mainCamera.transform.position;
|
|
Vector3 planeOrigin = GetPlatformOrigin();
|
|
Vector3 axis1, axis2;
|
|
GetPlatformAxes(out axis1, out axis2);
|
|
|
|
// Project camera position onto the plane
|
|
Vector3 relativePos = cameraPos - planeOrigin;
|
|
float coord1 = Vector3.Dot(relativePos, axis1);
|
|
float coord2 = Vector3.Dot(relativePos, axis2);
|
|
|
|
// Center collider on camera's projected position
|
|
Vector3 colliderCenter = planeOrigin + axis1 * coord1 + axis2 * coord2;
|
|
colliderObj.transform.position = colliderCenter;
|
|
|
|
// Make collider large enough to cover the grid
|
|
float colliderSize = gridExtent * gridSpacing * 2f;
|
|
platformCollider.size = new Vector3(colliderSize, platformThickness, colliderSize);
|
|
}
|
|
|
|
private void UpdateGridLines(Vector3 center, Vector3 axis1, Vector3 axis2)
|
|
{
|
|
int lineIndex = 0;
|
|
|
|
// Update lines along axis1
|
|
for (int i = -gridExtent; i <= gridExtent; i++)
|
|
{
|
|
Vector3 offset = axis2 * (i * gridSpacing);
|
|
Vector3 start = center + offset - axis1 * (gridExtent * gridSpacing);
|
|
Vector3 end = center + offset + axis1 * (gridExtent * gridSpacing);
|
|
|
|
if (lineIndex < gridLines.Count)
|
|
{
|
|
gridLines[lineIndex].SetPosition(0, start);
|
|
gridLines[lineIndex].SetPosition(1, end);
|
|
}
|
|
lineIndex++;
|
|
}
|
|
|
|
// Update lines along axis2
|
|
for (int i = -gridExtent; i <= gridExtent; i++)
|
|
{
|
|
Vector3 offset = axis1 * (i * gridSpacing);
|
|
Vector3 start = center + offset - axis2 * (gridExtent * gridSpacing);
|
|
Vector3 end = center + offset + axis2 * (gridExtent * gridSpacing);
|
|
|
|
if (lineIndex < gridLines.Count)
|
|
{
|
|
gridLines[lineIndex].SetPosition(0, start);
|
|
gridLines[lineIndex].SetPosition(1, end);
|
|
}
|
|
lineIndex++;
|
|
}
|
|
}
|
|
|
|
public void SwitchToAxis(BuildAxis axis)
|
|
{
|
|
currentAxis = axis;
|
|
RecreatePlatform();
|
|
}
|
|
|
|
public void MovePlatform(float delta)
|
|
{
|
|
currentDistance += delta;
|
|
UpdatePlatformDistance();
|
|
}
|
|
|
|
public void SetPlatformDistance(float distance)
|
|
{
|
|
currentDistance = distance;
|
|
UpdatePlatformDistance();
|
|
}
|
|
|
|
private void UpdatePlatformDistance()
|
|
{
|
|
// Just update the rotation/orientation without recreating everything
|
|
SetupPlatformTransform();
|
|
}
|
|
|
|
private void RecreatePlatform()
|
|
{
|
|
if (currentPlatform != null)
|
|
Destroy(currentPlatform);
|
|
if (gridVisual != null)
|
|
Destroy(gridVisual);
|
|
|
|
CreatePlatform();
|
|
}
|
|
|
|
private void CreatePlatform()
|
|
{
|
|
// Create container
|
|
currentPlatform = new GameObject($"Platform_{currentAxis}_{currentDistance}");
|
|
currentPlatform.transform.parent = transform;
|
|
|
|
// Create invisible collider platform
|
|
colliderObj = new GameObject("Collider");
|
|
colliderObj.transform.parent = currentPlatform.transform;
|
|
colliderObj.layer = LayerMask.NameToLayer("World");
|
|
|
|
platformCollider = colliderObj.AddComponent<BoxCollider>();
|
|
|
|
// Position and orient the platform based on axis
|
|
SetupPlatformTransform();
|
|
|
|
// Create visual grid if enabled
|
|
if (showGrid)
|
|
{
|
|
CreateGridVisual();
|
|
}
|
|
}
|
|
|
|
private void CreateGridVisual()
|
|
{
|
|
gridVisual = new GameObject("GridVisual");
|
|
gridVisual.transform.parent = currentPlatform.transform;
|
|
|
|
// Pre-create all line renderers
|
|
int totalLines = (gridExtent * 2 + 1) * 2;
|
|
gridLines.Clear();
|
|
|
|
for (int i = 0; i < totalLines; i++)
|
|
{
|
|
LineRenderer line = CreateLine(Vector3.zero, Vector3.zero);
|
|
gridLines.Add(line);
|
|
}
|
|
}
|
|
|
|
private void SetupPlatformTransform()
|
|
{
|
|
Vector3 rotation = Vector3.zero;
|
|
|
|
switch (currentAxis)
|
|
{
|
|
case BuildAxis.X: // YZ plane
|
|
rotation = new Vector3(0, 0, 90);
|
|
break;
|
|
|
|
case BuildAxis.Y: // XZ plane (horizontal)
|
|
rotation = Vector3.zero;
|
|
break;
|
|
|
|
case BuildAxis.Z: // XY plane
|
|
rotation = new Vector3(90, 0, 0);
|
|
break;
|
|
}
|
|
|
|
colliderObj.transform.rotation = Quaternion.Euler(rotation);
|
|
|
|
// Initial position will be updated in LateUpdate
|
|
UpdateColliderPosition();
|
|
}
|
|
|
|
private LineRenderer CreateLine(Vector3 start, Vector3 end)
|
|
{
|
|
GameObject lineObj = new GameObject("GridLine");
|
|
lineObj.transform.parent = gridVisual.transform;
|
|
|
|
LineRenderer line = lineObj.AddComponent<LineRenderer>();
|
|
|
|
line.material = gridMaterial;
|
|
line.startColor = gridColor;
|
|
line.endColor = gridColor;
|
|
line.startWidth = lineWidth;
|
|
line.endWidth = lineWidth;
|
|
line.positionCount = 2;
|
|
line.SetPosition(0, start);
|
|
line.SetPosition(1, end);
|
|
line.useWorldSpace = true;
|
|
|
|
return line;
|
|
}
|
|
|
|
private Vector3 GetPlatformOrigin()
|
|
{
|
|
switch (currentAxis)
|
|
{
|
|
case BuildAxis.X:
|
|
return new Vector3(currentDistance, 0, 0);
|
|
case BuildAxis.Y:
|
|
return new Vector3(0, currentDistance, 0);
|
|
case BuildAxis.Z:
|
|
return new Vector3(0, 0, currentDistance);
|
|
default:
|
|
return Vector3.zero;
|
|
}
|
|
}
|
|
|
|
private void GetPlatformAxes(out Vector3 axis1, out Vector3 axis2)
|
|
{
|
|
switch (currentAxis)
|
|
{
|
|
case BuildAxis.X: // YZ plane
|
|
axis1 = Vector3.up;
|
|
axis2 = Vector3.forward;
|
|
break;
|
|
case BuildAxis.Y: // XZ plane
|
|
axis1 = Vector3.right;
|
|
axis2 = Vector3.forward;
|
|
break;
|
|
case BuildAxis.Z: // XY plane
|
|
axis1 = Vector3.right;
|
|
axis2 = Vector3.up;
|
|
break;
|
|
default:
|
|
axis1 = Vector3.right;
|
|
axis2 = Vector3.up;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void ToggleGridVisibility(bool visible)
|
|
{
|
|
showGrid = visible;
|
|
if (gridVisual != null)
|
|
gridVisual.SetActive(visible);
|
|
}
|
|
|
|
public BuildAxis GetCurrentAxis() => currentAxis;
|
|
public float GetCurrentDistance() => currentDistance;
|
|
public Vector3 GetPlatformPosition() => GetPlatformOrigin();
|
|
} |