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.
Content
- 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 theTurretControl.cs
in a bittargetPos:
vector3 target position. The position where the turret is going to aimsensitivity:
mouse sensitivityturretParent:
the turret parent game objectdistance:
distance value from the barrelheightPosition:
height value from the barrelsmoothTime:
smooth value for camera movement, A smaller value will make the transition faster.
rightRotationLimit:
right rotation limit value in degreeleftRotationLimit:
left rotation limit value in degreeupwardRotationLimit:
upward rotation limit value in degreedownwardRotationLimit:
downward rotation limit value in degree
rotationX:
to store the player’s horizontal input valuerotationY:
to store the player’s vertical input valuecurrentRotation:
to store the current rotation valuevelovity:
vector3 value to store velocity value when smoothing the rotation
Start, Update & LateUpdate methods
In the 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.cs
script. This line is going to create an error as well, it will be gone when we construct the TurretControl.cs
and 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 Update
.
CameraMovement method
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 thetargetPos
. This is because our turret is going to aimtargetPos
from 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 valuefloat 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 inversedrotationX += 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 withMathf.Clamp()
functionrotationY = Mathf.Clamp(rotationY, -upwardRotationLimit, downwardRotationLimit);
: Limit the vertical rotation withMathf.Clamp()
functionVector3 newRotation = new Vector3(rotationY, rotationX,0);
: Create a new vector3newRotation
variable to store both vertical & horizontal values in itcurrentRotation = Vector3.SmoothDamp(currentRotation, newRotation, ref velocity, smoothTime);
: Smooth the rotation fromcurrentRotation
tonewRotation
withVector3.SmoothDamp()
functiontransform.localEulerAngles = currentRotation;
: Apply the rotation value to this game object's rotation which is the cameratransform.position = (turretParent.position + transform.up * heightPosition) — transform.forward * distance;
: Set the camera’s forward position away from the turret parent position withdistance
&heightPosition
values
OnDrawGizmos method
We want to implement gizmos to draw spheres as a crosshair in our game view so we use OnDrawGizmos
and 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 objectturretBarrel
: turret barrel game object
rightRotationLimit
: turret right rotation limit value in degreeleftRotationLimit
: turret left rotation limit value in degreeelevationRotationLimit
: turret barrel upward rotation limit value in degreedepressionRotationLimit
: turret barrel downward rotation limit value in degreeturnSpeed
: turret turning speedaimPoint
: turret aim point
Set Aim & Update method
The SetAim
will be called from CameraController.cs
and aimPoint
will be set here.
In Update
method we call HorizontalRotation
& VerticalRotation
. These methods handle horizontal and vertical calculations respectively.
HorizontalRotation method
Vector3 targetPositionInLocalSpace = transform.InverseTransformPoint(aimPoint);
: GetaimPoint
in Turret Parrent’s local space in relation toaimPoint
‘s world space and store it intargetPositionInLocalSpace
targetPositionInLocalSpace.y = 0.0f;
: SettargetPositionInLocalSpace
Y position to zero, since this is horizontal rotation and because we don't need itVector3 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 inwhereToRotate
turretBase.localRotation = Quaternion.RotateTowards(turretBase.localRotation, whereToRotate, TurnSpeed * Time.deltaTime);
: Rotate the Turret Base
VerticalRotation method
This method is actually similar to HorizontalRotation
. These are the lines where they are different.
Vector3 targetPositionInLocalSpace = turretBase.InverseTransformPoint(aimPoint);
: Instead of getting theaimPoint
from Turret Parrent’s local space we get it from Turret Base’s local space because Turret Base is Turret Barrel’s parent.
OnDrawGizmos method
Here in 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!