I have been trying to implement a third person camera syste: m in Unity, but not based on the default system. My goal is something more like Unreal Engine system, used also in Mass Effect or The Witcher 2/3. This system provides a camera free look, and then the character moves towards the camera direction.
My current approach consists of having a pivot GameObject, that follows the playecr GameObject. The pivot handles camera free look and other things like selecting objects in front of the camera (which right no, is not working well), and the crosshair (totally missing):
public class PivotControl : MonoBehaviour {
float rotationY = 0F;
Camera cam;
Text label;
// Use this for initialization
void Start () {
cam = gameObject.GetComponentInChildren<Camera> ();
label = GameObject.Find ("Label").GetComponent<Text>();;
}
// Update is called once per frame
void Update () {
if (Input.GetAxis ("Mouse X") != 0 || Input.GetAxis ("Mouse Y") != 0) {
float rotationX = gameObject.transform.localEulerAngles.y + Input.GetAxis("Mouse X") * 2f;
rotationY += Input.GetAxis("Mouse Y") * 5f;
gameObject.transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
cam.transform.LookAt(cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)));
RaycastHit hit;
Ray ray = cam.ViewportPointToRay(new Vector3(0.5F, 0.5F, 0));
if (Physics.Raycast (ray, out hit, 100)) {
if (hit.collider.tag=="Interactable")
label.text = "Press E to interact with "+hit.collider.name;
} else {
label.text = "";
}
}
}
}
The player script handles character movement and I have noticed that the rotatio towards camera direction works fine for small angles, when the difference between the player direction and the camera direction is not too large:
public class PlayerControl : MonoBehaviour {
public GameObject pivot;
Animator anim;
int direction = 0;
int FORWARD = 1;
int BACKWARD = 2;
int LEFT = 3;
int RIGHT = 4;
// Use this for initialization
void Start () {
//cam = gameObject.GetComponent<Camera> ();
//Cursor.visible = false;
//Cursor.lockState = CursorLockMode.Locked;
anim = gameObject.GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
Vector3 rot;
if (Input.GetKeyDown (KeyCode.W)) {
direction = FORWARD;
} else if (Input.GetKeyDown (KeyCode.S)) {
//go back
direction = BACKWARD;
} else if (Input.GetKeyDown (KeyCode.A)) {
direction = LEFT;
} else if (Input.GetKeyDown (KeyCode.D)) {
direction = RIGHT;
} else if (Input.GetKeyUp (KeyCode.W) || Input.GetKeyUp (KeyCode.S) || Input.GetKeyUp (KeyCode.A) || Input.GetKeyUp (KeyCode.D)) {
direction = 0;
}
switch (direction) {
case 0: //do nothing
anim.SetInteger("State",0);
break;
case 1: //forward
rot = gameObject.transform.localEulerAngles;
rot.y = pivot.transform.localEulerAngles.y;
gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
anim.SetInteger("State",1);
gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
break;
case 2: //
rot = gameObject.transform.localEulerAngles;
rot.y = pivot.transform.localEulerAngles.y+180f;
gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
anim.SetInteger("State",1);
gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
break;
case 3:
rot = gameObject.transform.localEulerAngles;
rot.y = pivot.transform.localEulerAngles.y-90f;
gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
anim.SetInteger("State",1);
gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
break;
case 4:
rot = gameObject.transform.localEulerAngles;
rot.y = pivot.transform.localEulerAngles.y+90f;
gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
anim.SetInteger("State",1);
gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
break;
}
}
}
Can somebody, please, suggest some improvements for this code? Im specially interested in solving the selection problem and implementing the crosshair.