The Hero
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 50 of 64.
This chapter builds Arena Survivor, the last game of the course. Waves of enemies pour into a walled arena and you fight them off with a sword: grunts that walk at you, and orbs that wait and then dash. A defeated wave leaves a power-up, a HUD shows your health and the wave, and when your health runs out the run ends and your best run is saved. The game uses this section's tools where they fit: an abstract Enemy with two kinds, IDamageable for everything that can be hurt, the waves as a ScriptableObject asset, pickups behind an interface, a HUD that only listens to C# events, and a JSON save. All twelve scripts are in the project from the start. Only Hero works yet; the others hold the fields a later lesson needs, and each lesson fills in more.
The hero's sword hits what is in front of it, so the swing needs a test for "in front". Vector3.Dot(a, b) multiplies the matching parts of two vectors and adds them up: a.x * b.x + a.y * b.y + a.z * b.z. For two directions of length 1, that is the cosine of the angle between them: 1 when they point the same way, 0.866 at 30 degrees, 0.707 at 45, 0 at right angles and -1 when they point opposite ways. So "within 30 degrees of where I face" becomes "a dot of at least 0.866", with no angle to work out. This sentry robot raises the alarm when the player is within 10 units and inside its 30-degree field of view:
public Transform player;
public float range = 10f;
void Update()
{
Vector3 toPlayer = player.position - transform.position;
toPlayer.y = 0f;
bool near = toPlayer.magnitude <= range;
bool inView = Vector3.Dot(transform.forward, toPlayer.normalized) >= 0.866f;
if (near && inView)
{
Debug.Log("Alarm!");
}
}Both directions need length 1. transform.forward always has it, but toPlayer is as long as the distance, so it is normalized first; otherwise a player twice as far away would give twice the dot. Its y is set to 0 before that, so a player on a higher walkway counts by where it stands on the map, not by how high it is. The sign tells front from back: a dot above 0 is anywhere in the front half, below 0 anywhere behind.
Challenge
MediumGive the hero a sword.
- In
Update(), when Space or a left click is pressed andTime.time >= nextSwing, setnextSwing = Time.time + swingCooldown;and callSwing(). - In
Swing(), loop overPhysics.OverlapSphere(transform.position, reach). - Destroy each hit tagged
Enemywhose flat directiontoHit(y set to 0) givesVector3.Dot(transform.forward, toHit.normalized) >= 0.5f.
Press Play and swing: the dummies in front vanish. Then Check.
Try it yourself
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
public class Hero : MonoBehaviour
{
[SerializeField] private float speed = 5f;
[SerializeField] private float reach = 2f;
[SerializeField] private float swingCooldown = 0.5f;
[SerializeField] private GameObject slash;
private CharacterController controller;
private InputAction moveAction;
private float nextSwing;
void Start()
{
controller = GetComponent<CharacterController>();
moveAction = InputSystem.actions.FindAction("Move");
}
void Update()
{
Vector2 input = moveAction.ReadValue<Vector2>();
Vector3 move = new Vector3(input.x, 0f, input.y);
controller.SimpleMove(move * speed);
if (move != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(move);
}
// Space or a left click swings, at most once every swingCooldown seconds
}
void Swing()
{
StartCoroutine(ShowSlash());
// destroy everything tagged Enemy within reach and in front of the hero
}
IEnumerator ShowSlash()
{
slash.SetActive(true);
yield return new WaitForSeconds(0.1f);
slash.SetActive(false);
}
}
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in ReachPractice on your own: Unity playground