Weapon Stats
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 24 of 64.
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
MediumMake every gun read its numbers from its GunData asset.
- In
Gun, addpublic GunData data;. - Fire
data.bulletPrefab, waitdata.fireIntervalbetween shots and give each bulletdata.damage. - Delete
gunType, the two bullet fields, the three private copies andStart().
Press Play and hold Space: the blaster fires too. 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;
}
}
}
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 Reach5ScriptableObjects
Data AssetsWeapon StatsShared SettingsSave the WindWaves as DataRecap: Item DatabaseRecap: Buy from the ShopPractice on your own: Unity playground