# Rotating around 3D cube Camera Controller for Unity

I am Unity game developer with more than 2 years experience. I am working in a personal project, a mobile game for Android in Unity.

I am trying to make a camera controller for a 3D Cube Game in Unity. I have a controller working, I can position the camera in the six faces of the cube. But The problem happens when I move the camera several times. (See the images for more explanation)

For example, I always start the game on the Top face, but after several moves, the controller starts to move West, East when it should move North, South. I understand what the problem is, that the camera depends on the previous movements since it is rotating spherically, but I don't know what data structures to use or how to fix this.

I know is a complex problem that requires 3D Math, but maybe some of you have faced this before or have a better aproach, Thank you.

Here is some relevant code I wrote (with the help of chatGPT) :

public class TiltControl : MonoBehaviour
{

// Define the faces of the cube
public enum CubeFace
{
Front,
Back,
Left,
Right,
Top,
Bottom
}

// Define the cardinal directions
public enum CardinalDirection
{
North,
East,
South,
West
}

// Dictionary to store adjacent faces for each face and direction

private CubeFace currentCameraFace = CubeFace.Top;

private void Start()
{
// Initialize the adjacent faces dictionary based on the current face
adjacentFaces[CubeFace.Front] = new List<CubeFace> { CubeFace.Bottom, CubeFace.Left, CubeFace.Top, CubeFace.Right };
adjacentFaces[CubeFace.Back] = new List<CubeFace> { CubeFace.Top, CubeFace.Right,CubeFace.Bottom, CubeFace.Left};
adjacentFaces[CubeFace.Left] = new List<CubeFace> { CubeFace.Front, CubeFace.Top,  CubeFace.Back, CubeFace.Bottom };
adjacentFaces[CubeFace.Right] = new List<CubeFace> { CubeFace.Front, CubeFace.Bottom,CubeFace.Back, CubeFace.Top };
adjacentFaces[CubeFace.Top] = new List<CubeFace> { CubeFace.Front,  CubeFace.Right,CubeFace.Back, CubeFace.Left};
adjacentFaces[CubeFace.Bottom] = new List<CubeFace> { CubeFace.Back,  CubeFace.Left, CubeFace.Front, CubeFace.Right };
}

private void LateUpdate()
{
if (cameraJoystick.Horizontal < -0.25)
{
ChangeFaceToDir(CardinalDirection.West);
}
else if (cameraJoystick.Horizontal > 0.25)
{
ChangeFaceToDir(CardinalDirection.East);
}
else if (cameraJoystick.Vertical > 0.25)
{
ChangeFaceToDir(CardinalDirection.North);
}
else if (cameraJoystick.Vertical < -0.25)
{
ChangeFaceToDir(CardinalDirection.South);
}
}

private void ChangeFace(CubeFace face)
{
currentCameraFace = face;
cameraText.SetText(currentCameraFace.ToString());
newPosition = cameraPoints[(int)face];
}

private void ChangeFaceToDir(CardinalDirection dir)
{

Debug.Log("toDir" + dir);
ChangeFace(currentCameraFace);

}

private CubeFace GetAdjacentFace(CubeFace face, CardinalDirection direction)
{
{

Vector2Int dirCard = GetCardinalDirection(direction);
Vector3 rotated = (-1 * myCamera.right * dirCard.x) + (myCamera.forward * dirCard.y);

Transform newTransform = Instantiate(cameraPoints[0]);
newTransform.position = myCamera.position;
newTransform.Rotate(myCamera.forward,Vector3.Angle(myCamera.right,rotated));

Debug.Log("newTransform" + newTransform.right.normalized);

int dir;

dir = (int)GetCardinalFromDirection(new Vector2Int((int)newTransform.right.normalized.x,(int)newTransform.right.normalized.z));

Destroy(newTransform.gameObject);

Debug.Log("dir" + dir);

}

Debug.LogWarning("Invalid face: " + face);
return face;
}

private Vector2Int GetCardinalDirection(CardinalDirection direction)
{
switch (direction)
{
case CardinalDirection.North: return new Vector2Int(1, 0);
case CardinalDirection.East: return new Vector2Int(0, 1);
case CardinalDirection.South: return new Vector2Int(-1, 0);
case CardinalDirection.West: return new Vector2Int(0, -1);
default: return new Vector2Int();
}
}

private CardinalDirection GetCardinalFromDirection(Vector2Int direction)
{
if (direction == new Vector2Int(1, 0))
{
return CardinalDirection.North;
}
else if (direction == new Vector2Int(0, 1))
{
return CardinalDirection.East;

}
else if (direction == new Vector2Int(-1, 0))
{
return CardinalDirection.South;

}
else if (direction == new Vector2Int(0, -1))
{
return CardinalDirection.West;

}
return CardinalDirection.North;
}


Code explanation:

1. I initialize the 4 possible neighbouring faces that one face can transition to (maybe this is the problem, as is fixed positions and the camera rotates spherically changing the orientation).

2. I check the input from the touch Joystick, that has just 4 valid directions (N,S,E,W)

3. Then in GetAdacentFace I should get the correct face depending on the Joystick direction, but here I get the wrong value in some cases. I do some calculations with the orientation of the main camera and the Joystick direction (and it sometimes returns the wrong face)

4. With this returned face, I move the camera to that face

• My approach to this would be to create a camera rig with the camera parented to a focus-point that is inside the cube and then rotate the camera around the cube by rotating the focus-point by 90° around its local x or y axis. Would refactoring your camera setup like that be an option for you? Jul 13, 2023 at 12:40
• Thanks, yes I can re-parent my camera. I'll give a try to this approach and let you know. I am struggling with this some days... Jul 13, 2023 at 13:23
• Oh no, just a little problem I want to the camera be static at top when I tilt the cube... I have to rotate a bit the cube to move the ball and the camera has to stay at position in this mechanic Jul 13, 2023 at 13:26
• But you give me an idea, maybe I can use the focus point... Jul 13, 2023 at 13:27
• Yeah It's working now, Thanks! Jul 13, 2023 at 13:45

I just needed the approach that https://gamedev.stackexchange.com/users/21890/philipp said

A rig inside the cube and a focus point inside the rig. and the following code solve this:

private void ChangeFaceToDir(CardinalDirection dir)
{
Debug.Log("toDir" + dir);
//cameraText.SetText(currentCameraFace.ToString());

switch (dir)
{
case CardinalDirection.North:
rigPoint.Rotate(Vector3.right, 90f,Space.Self);
break;
case CardinalDirection.South:
rigPoint.Rotate(Vector3.right, -90f, Space.Self);
break;
case CardinalDirection.East:
rigPoint.Rotate(Vector3.forward, -90f, Space.Self);

break;
case CardinalDirection.West:
rigPoint.Rotate(Vector3.forward, 90f, Space.Self);

break;
default:
break;
}
newPosition = focusPoint;

}