Menu
CoddyTech

Weapon Stats

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 20 of 50.

A sword and a hammer do the same thing: they swing, wait, and swing again. What sets them apart is numbers. A sword hits for 4 and swings every 0.5 seconds, a hammer hits for 10 every 1.5 seconds. So one Weapon script serves both, and each weapon's numbers live in an asset:

[CreateAssetMenu(menuName = "Combat/Weapon Data")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public int damage;
    public float swingTime;
    public GameObject hitEffect;
}
public class Weapon : MonoBehaviour
{
    public WeaponData data;
    private float nextSwing;

    public void Swing(Health target)
    {
        if (Time.time < nextSwing) return;
        nextSwing = Time.time + data.swingTime;
        target.TakeDamage(data.damage);
        Instantiate(data.hitEffect, target.transform.position, Quaternion.identity);
    }
}

The project holds a Sword asset (4, 0.5, a spark prefab) and a Hammer asset (10, 1.5, a dust prefab). The knight and the ogre both carry the Weapon script; the knight's data field holds the Sword and the ogre's the Hammer. A spear is one more asset made from the Create menu, with no change to any script. An asset can point at prefabs and at other assets, as hitEffect does, but not at objects in a scene: it lives in the project, outside every scene.

The other ways to get different weapons each put the numbers in code. if (weaponName == "Sword") damage = 4; else if ... grows with every weapon, and a Sword subclass of Weapon that only sets numbers is a class per asset. Subclasses are for weapons that act differently, such as a bow that fires arrows. A weapon that only hits harder or swings faster needs an asset of its own and no code.

challenge icon

Challenge

Medium

The firing range has four guns: two pistols, a rifle and a new blaster. Holding Space fires them all. The Gun script picks its bullet, fire interval and damage with if/else on gunType, and the blaster is not in it, so it does not fire (look at the Console).

Make every gun read its numbers from an asset instead. GunData.cs is ready, and the project has a Pistol, a Rifle and a Blaster asset made from it, each with its own bullet prefab.

  • Give Gun a public field data of type GunData; the Inspector puts each gun's asset in it.
  • Fire data.bulletPrefab, wait data.fireInterval between shots, and give each bullet data.damage.
  • Remove gunType, the two bullet fields, the private copies and the if/else.

Press Play and hold Space, then Check.

Try it yourself

using UnityEngine;
using UnityEngine.InputSystem;

public class Gun : MonoBehaviour
{
    public string gunType = "Pistol";
    public GameObject pistolBullet;
    public GameObject rifleBullet;
    private GameObject bulletPrefab;
    private float fireInterval;
    private int damage;
    private float nextShot;

    void Start()
    {
        if (gunType == "Pistol")
        {
            bulletPrefab = pistolBullet;
            fireInterval = 0.25f;
            damage = 1;
        }
        else if (gunType == "Rifle")
        {
            bulletPrefab = rifleBullet;
            fireInterval = 0.6f;
            damage = 4;
        }
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.isPressed && Time.time >= nextShot)
        {
            nextShot = Time.time + fireInterval;
            GameObject bullet = Instantiate(bulletPrefab, transform.position + transform.forward, transform.rotation);
            bullet.GetComponent<Bullet>().damage = damage;
        }
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Game Architecture in Unity