I am building an inventory system that creates a ring GameObject containing one or more child 3d objects around the main camera, offset so that the the camera is closest to the object directly in front of it. I am looking to be able to take the position of the “active” object in the ring and rotate the ring around its X axis so that the active object is directly in front of the camera, but I cannot figure out the math. I assume the object’s local position and radians will have something to do with it?
This is the code for populating my “ring” object;
float y = mainCam.transform.position.y;
for (int i = 0; i < wares.Count; i++) {
float angle = i * Mathf.PI * 2f / wares.Count;
Vector3 newPos = new Vector3(Mathf.Cos(angle) * radius, y, Mathf.Sin(angle) * radius);
GameObject thing = wares*.gameObject;*
GameObject go = Instantiate(thing, newPos, Quaternion.identity, ring.transform);
inventory.Add(go);
}
ring.transform.position = mainCam.transform.position - transform.forward * (radius - 3);
ring.transform.position = new Vector3(ring.transform.position.x, -.5f, ring.transform.position.z);
ring.transform.SetParent(transform);
This creates an empty GameObject, “ring,” takes the inventory objects I’ve populated, and places them equidistant from one another in a circle around the ring object, at a set radius, as children of the ring object. It then offsets the ring’s position so that whatever object is directly in front of the camera is closer to it (and offsets the ring’s y position just to center the object a little better.)
Now I Just want to be able to look at any one of the child objects and use its position to rotate the ring object so that particular child is directly in front of the camera. Can someone help me with the mathematical algorithm I would use to accomplish that?
Hi @ellisju, below is a solution that I wrote. Its not been properly tested yet, but give it a go and let me know. You control the item select by calling the NextItem() or PreviousItem() functions. Or in this case pressing Q and E.
public class CircleDisplay : MonoBehaviour {
public List<Transform> obejctList;
public int selectedIndex;
public Transform center;
public float radius = 5f;
public float speed = 3f;
void Start () {
// First assume that everything is rotating around this object
// to change center simple remove code below and assign manually
center = transform;
}
public void Update () {
// Arrange all the items in a circle
PositionAll ();
/* TEST CODE START: 1.0 */
if (Input.GetKey(KeyCode.Q))
PreviousItem ();
if (Input.GetKey(KeyCode.E))
NextItem ();
/* TEST CODE END: 1.0 */
}
void PositionAll () {
// Count the number of objects
var count = obejctList.Count();
// Get the angle between each items
var angle = (Mathf.PI * 2) / count;
// Now position each object in the circle and add a index offset
for (int i = 0; i < count; i ++ ){
// Get the X and Y Position - Not the 'angle * selectedIndex' is what controls the offset
var x = Mathf.Cos(angle * i + angle * selectedIndex) ;
var y = Mathf.Sin(angle * i + angle * selectedIndex);
var position = new Vector3(x, 0, y) * radius;
obejctList.position = Vector3.MoveTowards (transform.position, position, Time.deltaTime * speed);
}
}
void NextItem () {
selectedIndex++;
if (selectedIndex >= obejctList.Count())
selectedIndex = 0;
}
void PreviousItem () {
selectedIndex--;
if (selectedIndex < 0)
selectedIndex = obejctList.Count() - 1;
}
// Get the Item in the current index
public Transform GetSelectedItem () => obejctList[selectedIndex];
}
As a final note play around with rather subtracting the angle index offset if its displaying the wrong items.
Thank you for the code! I ended up getting it to work a little differently but your stuff got me thinking about it in a different way. I appreciate the help!