U
tab 02Character & Combat9 lessons — tap to open
09 / 09 · 24 min
Character & Combat★ exercise

Exercise: a fight you can lose

your project so far

Assets/

Scripts/

SkillShapeRespawner.cs

everything from tab 01–02

you already havethis lesson adds

exercise3–4 h

Stay in Arena.unity and make everything from this tab work together at once: the Knight moving and animating, three skills on cooldown, three dummies with health bars, two artifacts — and Mage and Archer still there on keys 2 and 3.

what you reuse

CharacterControllerAnimator + blend treeScriptableObject skillsCooldown + manaProjectile + poolEquipment → final statsEvents → health bar
animated diagram

Everything from tab 02 running at once in one scene.

Build it in four passes

Pass 1 — the character works

  • The Knight already has its model, CharacterController and CameraTarget from lesson 01 of this tab. Check it is still a prefab in Assets/Prefabs.

  • CharacterController sized to the body, PlayerMovement with walk / run / jump and gravity.

  • Animator with a Locomotion blend tree driven by Speed, plus Jump and Attack.

  • CharacterStats on the Knight with maxHealth 200, attack 25, defense 8, moveSpeed 5. Mage and Archer keep SimpleMover and no stats — they are scenery for now.

Pass 2 — three skills that feel different

Three ScriptableObject assets, three genuinely different jobs. If all three just deal damage in a sphere, you have one skill with three names.

the three assets you must create
Skill_Slash      Q   cooldown 1.5   mana  5   damage 30   range 3    melee sphere in front

Skill_Bolt       E   cooldown 4.0   mana 20   damage 55   projectile prefab

Skill_Nova       R   cooldown 12    mana 45   damage 90   range 6    hits everything around
one extra field makes the three behave differently
// in SkillData.cs
public enum SkillShape { MeleeArc, Projectile, Nova }
public SkillShape shape = SkillShape.MeleeArc;

// in SkillCaster.TryCast, replace the single ApplyDamage call
switch (s.shape)
{
    case SkillShape.MeleeArc:
        HitSphere(transform.position + transform.forward * s.range * 0.5f, s.range, s);
        break;

    case SkillShape.Projectile:
        GameObject go = Instantiate(s.projectilePrefab, castPoint.position, castPoint.rotation);
        go.GetComponent<Projectile>().Launch(gameObject, s.damage);
        break;

    case SkillShape.Nova:
        HitSphere(transform.position, s.range, s);
        break;
}

void HitSphere(Vector3 center, float radius, SkillData s)
{
    foreach (Collider hit in Physics.OverlapSphere(center, radius, enemyLayers))
        if (hit.TryGetComponent(out CharacterStats target))
            target.TakeDamage(s.damage);
}

Pass 3 — the dummies fight back (a little)

  • Three dummies on the Enemy layer, each with CharacterStats, a world-space health bar and HitFlash.

  • Give each a different maxHealth: 80, 120, 200 — so you can feel your damage numbers.

  • On death, disable the dummy and respawn it after 3 seconds so you can keep testing.

Respawner.cs — on each dummy
using System.Collections;
using UnityEngine;

public class Respawner : MonoBehaviour
{
    [SerializeField] private CharacterStats stats;
    [SerializeField] private float delay = 3f;
    [SerializeField] private GameObject[] toHide;

    void OnEnable() => stats.OnDied += HandleDeath;
    void OnDisable() => stats.OnDied -= HandleDeath;

    void HandleDeath() => StartCoroutine(Revive());

    IEnumerator Revive()
    {
        foreach (GameObject g in toHide) g.SetActive(false);
        yield return new WaitForSeconds(delay);

        stats.currentHealth = stats.finalMaxHp;
        foreach (GameObject g in toHide) g.SetActive(true);
    }
}

Pass 4 — two artifacts that visibly matter

  • Artifact_Ember: +40 flat Attack. Artifact_Swift: +25% MoveSpeed and +15% Attack.

  • Bind keys 7 and 8 to Equip / Unequip so you can toggle them while playing.

  • Skills must read finalAttack, not the base attack — otherwise equipping does nothing.

C# script
// in SkillCaster
float outgoing = s.damage * (myStats.finalAttack / 100f + 1f);
target.TakeDamage(outgoing);

Done when

  • ✓The Knight walks, runs with Shift, jumps, and the animation matches what it is doing — while keys 2 and 3 still hand control to the Mage and Archer.
  • ✓Q, E and R each do something visibly different, and each has its own cooldown ring in the UI.
  • ✓Casting with not enough mana, or on cooldown, is refused — and the player can tell why.
  • ✓Every hit shows a damage number, a white flash, and a health bar that drops.
  • ✓A dummy at 0 HP disappears and comes back 3 seconds later at full health.
  • ✓Equipping an artifact changes finalAttack in the Inspector AND changes the damage numbers on screen.
  • ✓Unequipping puts every number back exactly where it was — no drift.
  • ✓No errors in the Console after two minutes of mashing every key.

Numbers to hit

MetricTargetWhy
Time to kill a 120 HP dummy4–8 sUnder 4 s and skills feel pointless; over 8 s and it drags.
Input → visible reaction< 100 msAnything slower reads as a broken button.
Artifact effect on damage≥ 20%A bonus you cannot see is not a reward.
GC allocation per cast0 BPool the projectiles and popups; check in the Profiler.

If you want more

bonus 1

Give one dummy a Chase state: it walks towards you when you get within 8 m.

bonus 2

Add a fourth skill that heals instead of damaging — reuse the same SkillData with negative damage.

bonus 3

Make Nova knock the dummies back with AddExplosionForce.

bonus 4

Show a tooltip built by BuildTooltip when you hover an artifact icon.