Initial commit
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class CanvasPlatformUI : MonoBehaviour
|
||||
{
|
||||
private CanvasVirtualPlatformManager platformManager;
|
||||
|
||||
[Header("Plane Selection")]
|
||||
[SerializeField] private TMP_Dropdown planeDropdown;
|
||||
|
||||
[Header("Canvas Size Controls")]
|
||||
[SerializeField] private Slider canvasSizeSlider;
|
||||
[SerializeField] private float minCanvasSize = 1000f;
|
||||
[SerializeField] private float maxCanvasSize = 10000f;
|
||||
|
||||
[Header("Visibility Toggles")]
|
||||
[SerializeField] private Toggle platformToggle;
|
||||
[SerializeField] private Toggle gridToggle;
|
||||
|
||||
[Header("Display Info (Optional)")]
|
||||
[SerializeField] private TextMeshProUGUI infoText;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
platformManager = CanvasVirtualPlatformManager.getInstance();
|
||||
|
||||
if (platformManager == null)
|
||||
{
|
||||
Debug.LogError("CanvasVirtualPlatformManager not found in scene!");
|
||||
return;
|
||||
}
|
||||
|
||||
SetupUI();
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
private void SetupUI()
|
||||
{
|
||||
// Setup Plane Dropdown
|
||||
if (planeDropdown != null)
|
||||
{
|
||||
planeDropdown.ClearOptions();
|
||||
planeDropdown.AddOptions(new System.Collections.Generic.List<string>
|
||||
{
|
||||
"XZ",
|
||||
"XY",
|
||||
"YZ"
|
||||
});
|
||||
planeDropdown.value = (int)platformManager.GetCurrentPlane();
|
||||
planeDropdown.onValueChanged.AddListener(OnPlaneChanged);
|
||||
}
|
||||
|
||||
// Setup Canvas Size Slider (for uniform sizing)
|
||||
if (canvasSizeSlider != null)
|
||||
{
|
||||
canvasSizeSlider.minValue = minCanvasSize;
|
||||
canvasSizeSlider.maxValue = maxCanvasSize;
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
canvasSizeSlider.value = currentSize.x; // Use width as default
|
||||
canvasSizeSlider.onValueChanged.AddListener(OnCanvasSizeSliderChanged);
|
||||
}
|
||||
|
||||
|
||||
// Setup Platform Toggle
|
||||
if (platformToggle != null)
|
||||
{
|
||||
platformToggle.isOn = platformManager.IsPlatformVisible();
|
||||
platformToggle.onValueChanged.AddListener(OnPlatformToggleChanged);
|
||||
}
|
||||
|
||||
// Setup Grid Toggle
|
||||
if (gridToggle != null)
|
||||
{
|
||||
gridToggle.isOn = true; // Grid visible by default
|
||||
gridToggle.onValueChanged.AddListener(OnGridToggleChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlaneChanged(int index)
|
||||
{
|
||||
platformManager.SwitchToPlane((PlaneAxis)index);
|
||||
UpdateCanvasSizeFields();
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
private void OnCanvasSizeSliderChanged(float value)
|
||||
{
|
||||
// Set both width and height to the same value (square canvas)
|
||||
platformManager.SetCurrentCanvasSize(value, value);
|
||||
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
private void OnCanvasWidthChanged(string value)
|
||||
{
|
||||
if (float.TryParse(value, out float width))
|
||||
{
|
||||
width = Mathf.Clamp(width, minCanvasSize, maxCanvasSize);
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
platformManager.SetCurrentCanvasSize(width, currentSize.y);
|
||||
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCanvasSizeFields();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCanvasHeightChanged(string value)
|
||||
{
|
||||
if (float.TryParse(value, out float height))
|
||||
{
|
||||
height = Mathf.Clamp(height, minCanvasSize, maxCanvasSize);
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
platformManager.SetCurrentCanvasSize(currentSize.x, height);
|
||||
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCanvasSizeFields();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCanvasSizeFields()
|
||||
{
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
|
||||
if (canvasSizeSlider != null)
|
||||
canvasSizeSlider.value = currentSize.x;
|
||||
}
|
||||
|
||||
private void OnPlatformToggleChanged(bool isOn)
|
||||
{
|
||||
platformManager.TogglePlatformVisibility(isOn);
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
private void OnGridToggleChanged(bool isOn)
|
||||
{
|
||||
platformManager.ToggleGridVisibility(isOn);
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
private void UpdateInfoDisplay()
|
||||
{
|
||||
if (infoText != null && platformManager != null)
|
||||
{
|
||||
string planeText = platformManager.GetCurrentPlane().ToString();
|
||||
string visibilityText = platformManager.IsPlatformVisible() ? "Visible" : "Hidden";
|
||||
Vector2 canvasSize = platformManager.GetCurrentCanvasSize();
|
||||
|
||||
infoText.text = $"Current Plane: {planeText}\n" +
|
||||
$"Platform: {visibilityText}\n" +
|
||||
$"Canvas Size: {canvasSize.x:F0} x {canvasSize.y:F0}";
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Keyboard shortcuts for plane selection
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1))
|
||||
{
|
||||
if (planeDropdown != null)
|
||||
planeDropdown.value = 0;
|
||||
else
|
||||
platformManager.SwitchToPlane(PlaneAxis.XZ);
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.Alpha2))
|
||||
{
|
||||
if (planeDropdown != null)
|
||||
planeDropdown.value = 1;
|
||||
else
|
||||
platformManager.SwitchToPlane(PlaneAxis.XY);
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.Alpha3))
|
||||
{
|
||||
if (planeDropdown != null)
|
||||
planeDropdown.value = 2;
|
||||
else
|
||||
platformManager.SwitchToPlane(PlaneAxis.YZ);
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
// Toggle platform visibility with V key
|
||||
if (Input.GetKeyDown(KeyCode.V))
|
||||
{
|
||||
bool newState = !platformManager.IsPlatformVisible();
|
||||
platformManager.TogglePlatformVisibility(newState);
|
||||
if (platformToggle != null)
|
||||
platformToggle.isOn = newState;
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
|
||||
// Adjust canvas size with bracket keys
|
||||
if (Input.GetKeyDown(KeyCode.LeftBracket))
|
||||
{
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
float newSize = Mathf.Max(minCanvasSize, currentSize.x - 500f);
|
||||
platformManager.SetCurrentCanvasSize(newSize, newSize);
|
||||
UpdateCanvasSizeFields();
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.RightBracket))
|
||||
{
|
||||
Vector2 currentSize = platformManager.GetCurrentCanvasSize();
|
||||
float newSize = Mathf.Min(maxCanvasSize, currentSize.x + 500f);
|
||||
platformManager.SetCurrentCanvasSize(newSize, newSize);
|
||||
UpdateCanvasSizeFields();
|
||||
UpdateInfoDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88d2b2e866ecc9442b01e061f3dccacb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,324 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public enum PlaneAxis
|
||||
{
|
||||
XZ = 0, // Horizontal plane (Y = 0)
|
||||
XY = 1, // Front plane (Z = 0)
|
||||
YZ = 2 // Side plane (X = 0)
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class VirtualPlane
|
||||
{
|
||||
public PlaneAxis planeAxis;
|
||||
public GameObject canvasGrid; // The Canvas with grid visual
|
||||
[HideInInspector]
|
||||
public GameObject colliderObject; // The collider (generated dynamically)
|
||||
}
|
||||
|
||||
public class CanvasVirtualPlatformManager : MonoBehaviour
|
||||
{
|
||||
private static CanvasVirtualPlatformManager instance;
|
||||
|
||||
[Header("Plane Configurations")]
|
||||
[SerializeField] private VirtualPlane[] virtualPlanes;
|
||||
|
||||
[Header("Collider Settings")]
|
||||
[SerializeField] private float colliderThickness = 0.1f;
|
||||
[SerializeField] private string colliderLayer = "World";
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private PlaneAxis currentPlane = PlaneAxis.XZ;
|
||||
[SerializeField] private bool platformVisible = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null) instance = this;
|
||||
else Destroy(this.gameObject);
|
||||
}
|
||||
|
||||
public static CanvasVirtualPlatformManager getInstance() => instance;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GenerateColliders();
|
||||
UpdatePlaneVisibility();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate colliders for all planes based on their canvas sizes
|
||||
/// </summary>
|
||||
private void GenerateColliders()
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
if (plane.canvasGrid == null) continue;
|
||||
|
||||
// Get the canvas component
|
||||
Canvas canvas = plane.canvasGrid.GetComponent<Canvas>();
|
||||
if (canvas == null) continue;
|
||||
|
||||
RectTransform rectTransform = canvas.GetComponent<RectTransform>();
|
||||
if (rectTransform == null) continue;
|
||||
|
||||
// Create collider object
|
||||
if (plane.colliderObject != null)
|
||||
{
|
||||
Destroy(plane.colliderObject);
|
||||
}
|
||||
|
||||
plane.colliderObject = new GameObject($"Collider_{plane.planeAxis}");
|
||||
plane.colliderObject.transform.SetParent(transform);
|
||||
|
||||
// Match canvas position
|
||||
plane.colliderObject.transform.position = plane.canvasGrid.transform.position;
|
||||
|
||||
// Set rotation based on plane axis (not canvas rotation)
|
||||
plane.colliderObject.transform.rotation = GetColliderRotation(plane.planeAxis);
|
||||
|
||||
// Add box collider
|
||||
BoxCollider boxCollider = plane.colliderObject.AddComponent<BoxCollider>();
|
||||
|
||||
// Calculate collider size based on canvas size and scale
|
||||
float width = rectTransform.rect.width * canvas.transform.localScale.x;
|
||||
float height = rectTransform.rect.height * canvas.transform.localScale.y;
|
||||
|
||||
// All colliders use the same size format (width, thickness, height)
|
||||
// Rotation handles the orientation
|
||||
boxCollider.size = new Vector3(width, colliderThickness, height);
|
||||
|
||||
// Set layer
|
||||
int layer = LayerMask.NameToLayer(colliderLayer);
|
||||
if (layer != -1)
|
||||
{
|
||||
plane.colliderObject.layer = layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Layer '{colliderLayer}' not found. Using default layer.");
|
||||
}
|
||||
|
||||
Debug.Log($"Generated collider for {plane.planeAxis}: Size = {new Vector3(width, colliderThickness, height)}, Rotation = {GetColliderRotation(plane.planeAxis).eulerAngles}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the rotation for the collider based on plane axis
|
||||
/// </summary>
|
||||
private Quaternion GetColliderRotation(PlaneAxis axis)
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
case PlaneAxis.XZ: // Horizontal plane (rotate to lay flat)
|
||||
return Quaternion.Euler(0, 0, 0);
|
||||
|
||||
case PlaneAxis.XY: // Front plane (vertical, facing forward)
|
||||
return Quaternion.Euler(90, 0, 0);
|
||||
|
||||
case PlaneAxis.YZ: // Side plane (vertical, facing sideways)
|
||||
return Quaternion.Euler(0, 0, 90);
|
||||
|
||||
default:
|
||||
return Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regenerate colliders (useful if canvas size changes at runtime)
|
||||
/// </summary>
|
||||
public void RegenerateColliders()
|
||||
{
|
||||
GenerateColliders();
|
||||
UpdatePlaneVisibility();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Switch to a different plane axis
|
||||
/// </summary>
|
||||
public void SwitchToPlane(PlaneAxis plane)
|
||||
{
|
||||
currentPlane = plane;
|
||||
UpdatePlaneVisibility();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle platform visibility (canvas and collider)
|
||||
/// </summary>
|
||||
public void TogglePlatformVisibility(bool visible)
|
||||
{
|
||||
platformVisible = visible;
|
||||
UpdatePlaneVisibility();
|
||||
}
|
||||
|
||||
private void UpdatePlaneVisibility()
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
bool isActive = (plane.planeAxis == currentPlane) && platformVisible;
|
||||
|
||||
if (plane.canvasGrid != null)
|
||||
{
|
||||
plane.canvasGrid.SetActive(isActive);
|
||||
}
|
||||
|
||||
if (plane.colliderObject != null)
|
||||
{
|
||||
plane.colliderObject.SetActive(isActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle only the canvas grid visibility, keep colliders active
|
||||
/// </summary>
|
||||
public void ToggleGridVisibility(bool visible)
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
if (plane.planeAxis == currentPlane && plane.canvasGrid != null)
|
||||
{
|
||||
plane.canvasGrid.SetActive(visible && platformVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current active plane
|
||||
/// </summary>
|
||||
public PlaneAxis GetCurrentPlane() => currentPlane;
|
||||
|
||||
/// <summary>
|
||||
/// Check if platform is currently visible
|
||||
/// </summary>
|
||||
public bool IsPlatformVisible() => platformVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Get the current active plane's collider object
|
||||
/// </summary>
|
||||
public GameObject GetCurrentCollider()
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
if (plane.planeAxis == currentPlane)
|
||||
{
|
||||
return plane.colliderObject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current active plane's canvas
|
||||
/// </summary>
|
||||
public GameObject GetCurrentCanvas()
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
if (plane.planeAxis == currentPlane)
|
||||
{
|
||||
return plane.canvasGrid;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the canvas size for a specific plane and regenerate its collider
|
||||
/// </summary>
|
||||
public void SetCanvasSize(PlaneAxis planeAxis, float width, float height)
|
||||
{
|
||||
foreach (var plane in virtualPlanes)
|
||||
{
|
||||
if (plane.planeAxis == planeAxis && plane.canvasGrid != null)
|
||||
{
|
||||
Canvas canvas = plane.canvasGrid.GetComponent<Canvas>();
|
||||
RectTransform rectTransform = canvas.GetComponent<RectTransform>();
|
||||
|
||||
if (rectTransform != null)
|
||||
{
|
||||
rectTransform.sizeDelta = new Vector2(width, height);
|
||||
|
||||
// Regenerate only this plane's collider
|
||||
RegenerateSingleCollider(plane);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the canvas size for the current active plane
|
||||
/// </summary>
|
||||
public void SetCurrentCanvasSize(float width, float height)
|
||||
{
|
||||
SetCanvasSize(currentPlane, width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regenerate collider for a single plane
|
||||
/// </summary>
|
||||
private void RegenerateSingleCollider(VirtualPlane plane)
|
||||
{
|
||||
if (plane.canvasGrid == null) return;
|
||||
|
||||
Canvas canvas = plane.canvasGrid.GetComponent<Canvas>();
|
||||
if (canvas == null) return;
|
||||
|
||||
RectTransform rectTransform = canvas.GetComponent<RectTransform>();
|
||||
if (rectTransform == null) return;
|
||||
|
||||
// Destroy old collider if exists
|
||||
if (plane.colliderObject != null)
|
||||
{
|
||||
Destroy(plane.colliderObject);
|
||||
}
|
||||
|
||||
// Create new collider
|
||||
plane.colliderObject = new GameObject($"Collider_{plane.planeAxis}");
|
||||
plane.colliderObject.transform.SetParent(transform);
|
||||
|
||||
// Match canvas position
|
||||
plane.colliderObject.transform.position = plane.canvasGrid.transform.position;
|
||||
|
||||
// Set rotation based on plane axis (not canvas rotation)
|
||||
plane.colliderObject.transform.rotation = GetColliderRotation(plane.planeAxis);
|
||||
|
||||
BoxCollider boxCollider = plane.colliderObject.AddComponent<BoxCollider>();
|
||||
|
||||
float width = rectTransform.rect.width * canvas.transform.localScale.x;
|
||||
float height = rectTransform.rect.height * canvas.transform.localScale.y;
|
||||
|
||||
// All colliders use the same size format (width, thickness, height)
|
||||
// Rotation handles the orientation
|
||||
boxCollider.size = new Vector3(width, colliderThickness, height);
|
||||
|
||||
int layer = LayerMask.NameToLayer(colliderLayer);
|
||||
if (layer != -1)
|
||||
{
|
||||
plane.colliderObject.layer = layer;
|
||||
}
|
||||
|
||||
// Update visibility based on current state
|
||||
plane.colliderObject.SetActive((plane.planeAxis == currentPlane) && platformVisible);
|
||||
|
||||
Debug.Log($"Regenerated collider for {plane.planeAxis}: Size = {new Vector3(width, colliderThickness, height)}, Rotation = {GetColliderRotation(plane.planeAxis).eulerAngles}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current canvas size
|
||||
/// </summary>
|
||||
public Vector2 GetCurrentCanvasSize()
|
||||
{
|
||||
GameObject canvas = GetCurrentCanvas();
|
||||
if (canvas != null)
|
||||
{
|
||||
RectTransform rectTransform = canvas.GetComponent<RectTransform>();
|
||||
if (rectTransform != null)
|
||||
{
|
||||
return rectTransform.sizeDelta;
|
||||
}
|
||||
}
|
||||
return Vector2.zero;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d38cae3122a6894b93b43d3b4231fe1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,90 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class PlatformUI : MonoBehaviour
|
||||
{
|
||||
private VirtualPlatformManager platformManager;
|
||||
|
||||
[Header("Axis Buttons")]
|
||||
[SerializeField] private Button xAxisButton;
|
||||
[SerializeField] private Button yAxisButton;
|
||||
[SerializeField] private Button zAxisButton;
|
||||
|
||||
[Header("Movement Buttons")]
|
||||
[SerializeField] private Button moveUpButton;
|
||||
[SerializeField] private Button moveDownButton;
|
||||
[SerializeField] private float moveStep = 1f;
|
||||
|
||||
[Header("Display")]
|
||||
[SerializeField] private Toggle gridToggle;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
platformManager = VirtualPlatformManager.getInstance();
|
||||
|
||||
SetupButtons();
|
||||
}
|
||||
|
||||
private void SetupButtons()
|
||||
{
|
||||
xAxisButton?.onClick.AddListener(() =>
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.X);
|
||||
});
|
||||
|
||||
yAxisButton?.onClick.AddListener(() =>
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.Y);
|
||||
});
|
||||
|
||||
zAxisButton?.onClick.AddListener(() =>
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.Z);
|
||||
});
|
||||
|
||||
moveUpButton?.onClick.AddListener(() =>
|
||||
{
|
||||
platformManager.MovePlatform(moveStep);
|
||||
});
|
||||
|
||||
moveDownButton?.onClick.AddListener(() =>
|
||||
{
|
||||
platformManager.MovePlatform(-moveStep);
|
||||
});
|
||||
|
||||
gridToggle?.onValueChanged.AddListener((visible) =>
|
||||
{
|
||||
platformManager.ToggleGridVisibility(visible);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Keyboard shortcuts
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1))
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.X);
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.Alpha2))
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.Y);
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.Alpha3))
|
||||
{
|
||||
platformManager.SwitchToAxis(BuildAxis.Z);
|
||||
}
|
||||
|
||||
// Arrow keys or +/- to move platform
|
||||
if (Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.Equals))
|
||||
{
|
||||
platformManager.MovePlatform(moveStep);
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.Minus))
|
||||
{
|
||||
platformManager.MovePlatform(-moveStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daeca078daa772e49b4ab1c824d31df8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,309 @@
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b8764f15669a7745ab9ebb85d6284de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "VirtualPlatformSystem",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88dfbf271f5bd104a90f9501590f7aa2
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user