in this method i create the circle using line renderer:
when i change the value of the variable height it’s changing the circle height.
void CreatePoints()
{
float angleStep = 360f / segments;
float angle = 0f;
float y = height; // Fixed height for the circle plane
// Adjust radii based on parent's scale
Vector3 parentScale = transform.parent ? transform.parent.lossyScale : Vector3.one;
float adjustedXRadius = xradius / parentScale.x;
float adjustedYRadius = yradius / parentScale.z;
for (int i = 0; i <= segments; i++) // <= to close the circle
{
float x = Mathf.Sin(Mathf.Deg2Rad * angle) * adjustedXRadius;
float z = Mathf.Cos(Mathf.Deg2Rad * angle) * adjustedYRadius;
line.SetPosition(i, new Vector3(x, y, z));
angle += angleStep;
}
}
in this method i create objects and put them position them on the circle:
public void CreateObjectsAroundPoint(int num, Vector3 point, float xRadius, float yRadius)
{
// Clear existing objects
ClearObjects(true);
// Ensure at least one object is created
if (num < 1) return;
// Temporary list to track new objects
List<GameObject> newObjects = new List<GameObject>();
for (int i = 0; i < num; i++)
{
// Distance around the ellipse
var radians = 2 * Mathf.PI / num * i;
// Calculate the position on the ellipse
var x = Mathf.Cos(radians) * xRadius;
var z = Mathf.Sin(radians) * yRadius;
var spawnPos = point + new Vector3(x, 0, z); // Set position on ellipse
// Instantiate and position the object
var obj = Instantiate(objectPrefab, spawnPos, Quaternion.identity);
// Set tag and name
obj.tag = "ObjectonCircle";
obj.name = "Object on Circle";
// Rotate the object to face the center
obj.transform.LookAt(point);
// Add the object to the list
newObjects.Add(obj);
}
// Update the objects array with the newly created objects
objects = newObjects.ToArray();
}
and in this method i adjust the objects positions:
private void AdjustPositions(int num, Vector3 point, float xRadius, float yRadius)
{
if (objects == null || objects.Length == 0 || num <= 0) return;
for (int i = 0; i < objects.Length; i++)
{
if (objects[i] == null) continue; // Skip if the object was destroyed
// Distance around the ellipse
var radians = 2 * Mathf.PI / num * i;
// Calculate the new position on the ellipse
var x = Mathf.Cos(radians) * xRadius;
var z = Mathf.Sin(radians) * yRadius;
var spawnPos = point + new Vector3(x, 0, z); // Set position on ellipse
// Update object position
objects[i].transform.position = spawnPos;
// Rotate the object to face the center
objects[i].transform.LookAt(point);
}
}
now when i change the circle radius size on the xrdaius or yradius the created objects also change position and keep staying on the circle radius even if i change only the xradius or only the yradius and it become ellipse the objects keep staying on the circle. same if i change the value of the variable changeBothRadius.
the problem is when i change the circle height the objects stay down not moving.
i tried to change in both methods CreateObjectsAroundPoint and AdjustPositions the line:
var spawnPos = point + new Vector3(x, 0, z);
to
var spawnPos = point + new Vector3(x, height, z);
when i change the height value the circle moves up but the objects on the circle move too much higher offset above the circle.
how to fix it? i want when i change the circle height that the objects will stay on the circle and move with it.
here is the full script:
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using TMPro;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
[ExecuteAlways]
[RequireComponent(typeof(LineRenderer))]
public class DrawCircleAroundObject : MonoBehaviour
{
[Header("Debug Information")]
public TextMeshProUGUI debugText; // Reference to the TextMeshPro text field
[Header("Draw Circle")]
[Range(0, 50)]
public int segments = 50;
[Range(0, 5)]
public float xradius = 5;
[Range(0, 5)]
public float yradius = 5;
[Range(0, 5)]
public float changeBothRadius = 1; // Synchronization control
[Range(0.1f, 5f)]
public float width = 0.1f;
[Range(0, 50)]
public float height = 0;
public bool draw = true;
[Header("Add Objects on Circle")]
[Range(0, 50)]
public int numOfObjects = 5;
public GameObject objectPrefab;
private int prevNumOfObjects;
[Header("Move Objects")]
public MoveObjects moveObjects;
private float previousBothRadius = -1; // Tracks the last value of changeBothRadius
private float previousXradius;
private float previousYradius;
private LineRenderer line;
private GameObject[] objects;
private float initialXRadius = -1;
private float initialYRadius = -1;
private float initialBothRadius = -1;
private Vector3 initialObjectPosition = Vector3.zero;
private GameObject referenceObject; // Reference to track one object
void Start()
{
prevNumOfObjects = numOfObjects;
line = gameObject.GetComponent<LineRenderer>();
ConfigureLineRenderer();
CreatePoints();
}
private void OnValidate()
{
// Handle changes to changeBothRadius
if (changeBothRadius != previousBothRadius)
{
SyncRadii(); // Sync radii when changeBothRadius changes
previousBothRadius = changeBothRadius;
}
else if (xradius != previousXradius || yradius != previousYradius)
{
// Allow independent changes to xradius and yradius
Debug.Log($"Updating radii: X = {xradius}, Y = {yradius}");
previousXradius = xradius;
previousYradius = yradius;
}
// Update LineRenderer and object positions
if (line != null && draw)
{
ConfigureLineRenderer();
CreatePoints();
AdjustPositions(numOfObjects, transform.position, xradius, yradius); // Pass both radii
}
}
private void Update()
{
if (line != null && draw)
{
line.enabled = true;
}
else if (line != null)
{
line.enabled = false;
}
if (prevNumOfObjects != numOfObjects)
{
CreateObjectsAroundPoint(numOfObjects, transform.position, xradius, yradius); // Pass both radii
prevNumOfObjects = numOfObjects;
}
// Update Debug Text
UpdateDebugText();
}
void ConfigureLineRenderer()
{
line.useWorldSpace = false;
line.loop = true; // Ensures the circle is closed
line.startWidth = width;
line.endWidth = width;
line.positionCount = segments + 1; // +1 to close the circle
}
void SyncRadii()
{
xradius = changeBothRadius;
yradius = changeBothRadius;
previousXradius = xradius;
previousYradius = yradius;
}
void CreatePoints()
{
float angleStep = 360f / segments;
float angle = 0f;
float y = height; // Fixed height for the circle plane
// Adjust radii based on parent's scale
Vector3 parentScale = transform.parent ? transform.parent.lossyScale : Vector3.one;
float adjustedXRadius = xradius / parentScale.x;
float adjustedYRadius = yradius / parentScale.z;
for (int i = 0; i <= segments; i++) // <= to close the circle
{
float x = Mathf.Sin(Mathf.Deg2Rad * angle) * adjustedXRadius;
float z = Mathf.Cos(Mathf.Deg2Rad * angle) * adjustedYRadius;
line.SetPosition(i, new Vector3(x, y, z));
angle += angleStep;
}
}
public void CreateObjectsAroundPoint(int num, Vector3 point, float xRadius, float yRadius)
{
// Clear existing objects
ClearObjects(true);
// Ensure at least one object is created
if (num < 1) return;
// Temporary list to track new objects
List<GameObject> newObjects = new List<GameObject>();
for (int i = 0; i < num; i++)
{
// Distance around the ellipse
var radians = 2 * Mathf.PI / num * i;
// Calculate the position on the ellipse
var x = Mathf.Cos(radians) * xRadius;
var z = Mathf.Sin(radians) * yRadius;
var spawnPos = point + new Vector3(x, 0, z); // Set position on ellipse
// Instantiate and position the object
var obj = Instantiate(objectPrefab, spawnPos, Quaternion.identity);
// Set tag and name
obj.tag = "ObjectonCircle";
obj.name = "Object on Circle";
// Rotate the object to face the center
obj.transform.LookAt(point);
// Add the object to the list
newObjects.Add(obj);
}
// Update the objects array with the newly created objects
objects = newObjects.ToArray();
}
private void AdjustPositions(int num, Vector3 point, float xRadius, float yRadius)
{
if (objects == null || objects.Length == 0 || num <= 0) return;
for (int i = 0; i < objects.Length; i++)
{
if (objects[i] == null) continue; // Skip if the object was destroyed
// Distance around the ellipse
var radians = 2 * Mathf.PI / num * i;
// Calculate the new position on the ellipse
var x = Mathf.Cos(radians) * xRadius;
var z = Mathf.Sin(radians) * yRadius;
var spawnPos = point + new Vector3(x, 0, z); // Set position on ellipse
// Update object position
objects[i].transform.position = spawnPos;
// Rotate the object to face the center
objects[i].transform.LookAt(point);
}
}
public void ClearObjects(bool createNew)
{
GameObject[] objectsOnCircle = GameObject.FindGameObjectsWithTag("ObjectonCircle");
foreach (var obj in objectsOnCircle)
{
if (Application.isPlaying)
{
Destroy(obj);
}
else
{
DestroyImmediate(obj);
}
}
// Clear the objects array
objects = new GameObject[0];
if (!createNew)
{
numOfObjects = 0;
}
}
private void UpdateDebugText()
{
if (debugText == null) return;
// Initialize radius values if not done yet
if (initialXRadius < 0) initialXRadius = xradius;
if (initialYRadius < 0) initialYRadius = yradius;
if (initialBothRadius < 0) initialBothRadius = changeBothRadius;
// Get current and initial positions of the reference object
Vector3 currentPosition = referenceObject != null ? referenceObject.transform.position : Vector3.zero;
// Format debug text with consistent colors and correct formatting
debugText.text = string.Format(
"<color=red><b>Debug Info:</b></color>\n\n" + // Header in red
"<color=white>Current Radii:</color> <color=green>X = {0:F2}, Y = {1:F2}, Both = {2:F2}</color>\n" +
"<color=blue>Initial Radii:</color> <color=green>X = {3:F2}, Y = {4:F2}, Both = {5:F2}</color>\n" +
"<color=yellow>Object Position:</color> <color=green>{6}</color>\n" +
"<color=orange>Initial Position:</color> <color=green>{7}</color>",
xradius, yradius, changeBothRadius,
initialXRadius, initialYRadius, initialBothRadius,
currentPosition.ToString("F2"), initialObjectPosition.ToString("F2")
);
// Adjust text size for better readability
debugText.fontSize = 18; // Smaller text size for better fit
}
}