Unity C# Tutorial | Turret Control
In this tutorial, we will build a basic turret controller, This tutorial is made with Unity 2021.3.7f1. You can use any version you want. It’s going to be a turret control system that can be controlled from our camera view.
- Camera control script
- Turret control script
Camera control script
We’ll create a simple orbiting camera to follow our turret in third-person mode. Create a
CameraController.cs script and put it in the main camera gameobject. Let’s declare some variables.
turretControl:turret control script. This line is going to create an error, but don't worry it will be gone when we construct the
TurretControl.csin a bit
targetPos:vector3 target position. The position where the turret is going to aim
turretParent:the turret parent game object
distance:distance value from the barrel
heightPosition:height value from the barrel
smoothTime:smooth value for camera movement, A smaller value will make the transition faster.
rightRotationLimit:right rotation limit value in degree
leftRotationLimit:left rotation limit value in degree
upwardRotationLimit:upward rotation limit value in degree
downwardRotationLimit:downward rotation limit value in degree
rotationX:to store the player’s horizontal input value
rotationY:to store the player’s vertical input value
currentRotation:to store the current rotation value
velovity:vector3 value to store velocity value when smoothing the rotation
Start, Update & LateUpdate methods
Start method, we want to lock the cursor by setting the cursor lock state with this code,
Cursor.lockState = CursorLockMode.Locked, when Locked, the cursor is placed in the center of the view and cannot be moved. The cursor is invisible in this state.
Then we create the
Update method to call
SetAim and pass the
targetPos value to
turretControl.csscript. This line is going to create an error as well, it will be gone when we construct the
SetAim soon. We use
Update method because when the target is moving, its position will get updated every frame.
We use the
LateUpdate method to call the
CameraMovement which we are going to implement in a bit. LateUpdate is called after all Update functions have been called. This is useful to order script execution. For example, a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside
This is the method where all of the mechanics happen to the camera.
targetPos = transform.TransformPoint(Vector3.foward * 200.0f);: we set the target position 200 units away from the camera’s forward position(z-axis). We transform the camera's local forward position to world space and then assign it to the
targetPos. This is because our turret is going to aim
targetPosfrom world space, not from the camera’s forward local position.
float axisX = Input.GetAxis(“Mouse X”) * sensitivity;: Get the player’s horizontal input and multiply the input with the sensitivity value
float axisY = -Input.GetAxis(“Mouse Y”) * sensitivity;: Get the player’s vertical input and multiply the input with the sensitivity value. We have to make the value negative since the mouse input is inversed
rotationX += axisX;&
rotationY += axisY;: Accumulate the input value. Otherwise, the values will get reset to 0 when the player stops moving the mouse thus resetting the camera’s rotation.
rotationX = Mathf.Clamp(rotationX,-rightRotationLimit,leftRotationLimit);: Limit the horizontal rotation with
rotationY = Mathf.Clamp(rotationY, -upwardRotationLimit, downwardRotationLimit);: Limit the vertical rotation with
Vector3 newRotation = new Vector3(rotationY, rotationX,0);: Create a new vector3
newRotationvariable to store both vertical & horizontal values in it
currentRotation = Vector3.SmoothDamp(currentRotation, newRotation, ref velocity, smoothTime);: Smooth the rotation from
transform.localEulerAngles = currentRotation;: Apply the rotation value to this game object's rotation which is the camera
transform.position = (turretParent.position + transform.up * heightPosition) — transform.forward * distance;: Set the camera’s forward position away from the turret parent position with
We want to implement gizmos to draw spheres as a crosshair in our game view so we use
DrawWireSphere to do that. Don't forget to turn the Gizmos on in the Game tab.
Turret control script
Now we’ve got the camera working. It’s time to work on our turret and for that, we have to construct a
TurretControl.cs to get the turret working. Put this script in the Turret Parent game object.
Before we begin, our turret game object hierarchy should be like this: Turret Parrent 👉 Turret Base 👉 Turret Barrel.
turretBase: turret base game object
turretBarrel: turret barrel game object
rightRotationLimit: turret right rotation limit value in degree
leftRotationLimit: turret left rotation limit value in degree
elevationRotationLimit: turret barrel upward rotation limit value in degree
depressionRotationLimit: turret barrel downward rotation limit value in degree
turnSpeed: turret turning speed
aimPoint: turret aim point
Set Aim & Update method
SetAim will be called from
aimPoint will be set here.
Update method we call
VerticalRotation . These methods handle horizontal and vertical calculations respectively.
Vector3 targetPositionInLocalSpace = transform.InverseTransformPoint(aimPoint);: Get
aimPointin Turret Parrent’s local space in relation to
aimPoint‘s world space and store it in
targetPositionInLocalSpace.y = 0.0f;: Set
targetPositionInLocalSpaceY position to zero, since this is horizontal rotation and because we don't need it
Vector3 limitedRotation = targetPositionInLocalSpace;: Store limit value of the rotation
if(targetPositionInLocalSpace.x >= 0.0f) limitedRotation = Vector3.RotateTowards(Vector3.forward, targetPositionInLocalSpace, Mathf.Deg2Rad * rightRotationLimit, float.MaxValue); else limitedRotation = Vector3.RotateTowards(Vector3.forward, targetPositionInLocalSpace, Mathf.Deg2Rad * leftRotationLimit, float.MaxValue);
Limit turret horizontal rotation according to its rotation limit.
Quaternion whereToRotate = Quaternion.LookRotation(limitedRotation);: Get direction to the aim point and store it in
turretBase.localRotation = Quaternion.RotateTowards(turretBase.localRotation, whereToRotate, TurnSpeed * Time.deltaTime);: Rotate the Turret Base
This method is actually similar to
HorizontalRotation. These are the lines where they are different.
Vector3 targetPositionInLocalSpace = turretBase.InverseTransformPoint(aimPoint);: Instead of getting the
aimPointfrom Turret Parrent’s local space we get it from Turret Base’s local space because Turret Base is Turret Barrel’s parent.
OnDrawGizmos we draw a line 200 units long from Turret Barrel’s forward position(z-axis). This way we can figure out where the turret aims.
Don't forget to assign game objects in Inspector
That’s the end of the tutorial, Cheers!