A key functionality a lot of early play testers expressed a desire for was a way to control the camera, which previously had only been a static top down view. Instead of simply implementing a basic side to side movement of the top down camera (like many strategy games), I decided to take a que from games like City: Skylines and Divinity Original Sin 2 which both allow a very zoomed in perspective and a large overview style perspective.
To make the system programmatically decoupled and editable I decided to make a controller that only require three external inputs, specifically three object position references. Two positions to define the furthest and closest point the camera can get, and one position to define where the camera is supposed to be looking. In the editor these 3 positions are referenced as empty child objects of the player.
Next I had to create an intuitive way of defining a smooth camera path, that interpolates between a 3rd-person and a top down view. While I could have implemented a custom Bezier curve editor to define the path, I decided it was quicker and more editor friendly to use Unity's inbuilt animation curves functionality.
Using start and end position references, the controller finds the height difference and samples the curve at the current zoom (range between 0-1) and creates a position based on this height. Using this position, it creates a center positioned at the curve start position with the new height and determines the current radius. Using trigonometry and these three inputs the new camera position is determined, and then Slerped to based on a given rotation speed.
Here are the two key functions that enable this movement:
Vector3 ZoomCurvePositon(float _zoomAmount)
{ float heightDifferential = Mathf.Abs(offsetMax.position.y - offsetMin.position.y); Vector3 pos = offsetMin.position + (offsetDirection*maxZoomDistance * zoomCurve.Evaluate(_zoomAmount)); pos.y = offsetMax.position.y - heightDifferential* zoomCurve.Evaluate(1.0f - _zoomAmount); return pos; }
void CreateCameraTarget() { //retrieve position on zoom curve and define rotation center cameraTarget = ZoomCurvePositon(currentZoom); Vector3 center = new Vector3(target.position.x, cameraTarget.y, target.position.z); float radius = Vector3.Distance(cameraTarget, center);
//Defines the new target position using basic trig math
//Outputs result to class variable for Slerping elsewhere cameraTarget = new Vector3(center.x + Mathf.Cos(rotation) * radius, cameraTarget.y, center.z + Mathf.Sin(rotation) * radius); }
コメント