Files
2026-07-21 08:56:10 +03:00

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();
}