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 Dictionary<CubeFace, List<CubeFace>> adjacentFaces;
private CubeFace currentCameraFace = CubeFace.Top;
private void Start()
{
// Initialize the adjacent faces dictionary based on the current face
adjacentFaces = new Dictionary<CubeFace, List<CubeFace>>();
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);
currentCameraFace = GetAdjacentFace(currentCameraFace, dir);
ChangeFace(currentCameraFace);
}
private CubeFace GetAdjacentFace(CubeFace face, CardinalDirection direction)
{
if (adjacentFaces.ContainsKey(face))
{
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);
return adjacentFaces[face][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:
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).
I check the input from the touch Joystick, that has just 4 valid directions (N,S,E,W)
Then in
GetAdacentFaceI 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)With this returned face, I move the camera to that face

