First Person Auto Aim Rotation

Hi, I’m working on a first person game and I’m trying to implement a lock on feature similar to the lock on feature in Metroid Prime. Right now I’m using a basic character controller with a camera attached to it, so my basic aiming is done by rotating the character controller on the y axis and the camera on the x axis.

However, I’ve ran into some issues when I try to do a lock on. For the character’s movement/ x rotation, I do this:

Vector3 charLookPosition  = lockOnTarget.transform.position - transform.position;
charLookPosition.y = 0;
Quaternion charRotation = Quaternion.LookRotation(charLookPosition);
transform.rotation = originalCharacterRotation * charRotation;

Only using this, the character successfully rotates around the character if I move left/right and the target is always centered horizontally on the screen.
However, for the Camera I attempted the same thing, except setting the x to 0:

Vector3 camLookPosition = lockOnTarget.transform.position - viewCamera.transform.position;
camLookPosition.x = 0;
Quaternion camRotation = Quaternion.LookRotation(camLookPosition);
viewCamera.transform.localRotation = originalCameraRotation * camRotation;

With this in place the character object still does what I want when moving, but the camera only centers on the target if I keep the character and object lined up on the world’s z axis. Otherwise, the camera rotates up and down as the character object orbits around the target.

I’ve tried using Quaternion.LookAt() and a few other solutions using Euler angles, etc. and I always end up with this specific issue. I’m still wrapping my head around quaternions and that might be why I don’t see what I’m doing wrong here.

I got the behavior I wanted based on this solution http://answers.unity3d.com/comments/563502/view.html by @robertbu

This is what my code looks like now:

//perform calculation for character rotation
float distanceToPlane = Vector3.Dot(transform.up, lockOnTarget.transform.position - transform.position);
Vector3 planePoint = lockOnTarget.transform.position - transform.up * distanceToPlane;
    
Quaternion qCharacter = Quaternion.LookRotation(planePoint - transform.position, transform.up);
    	            transform.rotation = originalCharacterRotation * qCharacter;
    
//perform calculation for camera:
distanceToPlane = Vector3.Dot(transform.up, lockOnTarget.transform.position - viewCamera.transform.position);
planePoint = lockOnTarget.transform.position - viewCamera.transform.up * distanceToPlane;
                    
Vector3 v3 = new Vector3(0.0f, distanceToPlane, (planePoint - viewCamera.transform.position).magnitude);
Quaternion qCamera = Quaternion.LookRotation(v3);
    
viewCamera.transform.localRotation = originalCameraRotation * qCamera;

It seems to work as I wanted, I had to do a second calculation because my camera has a bit of an offset from the character.