Classes in a strategy game

My project is a 2d turn-based strategy game in a tile map, but I think that my question is the same for RTS or RPGs.
I’m trying to find a way to implement the class of the units of the game (infantry, cavalry, etc).
So far, I have made a “Unit” class (which doesn’t derive from MonoBehaviour) with various variables like H.P., Defence, Attack etc and a Gameobject variable (named “UnitImage”) to hold the UnitPrefab which is a cube with a texture and shows how the unitl looks like.
This approach works pretty well to instantiate the units in the map and move them around, but I have problems to access it’s variables like H.P., Attack etc.

I tried to make a Unit Class that derives from MonoBehaviour and attach it to the Unitprefab, so to access its non-gameobject variables like H.P. and attack easier, but I failed to make it work and I’m not sure if it’s the right way to do this.

What do you think is the best approach for Units? Shall I have a general non-MonoBehaviour Unit class script or a MonoBehaviour script with every info for my units (h.p., attack, defence etc) attached to a prefab?

Thanks for your answers and I would appreciate a detailed approach.

public class Unit : MonoBehaviour
{	
	public string UnitName = "Unamed Unit";

	public float MaxHealth;
	public float myHealth = 0;

	public UnitType unitType;
	
	public UnitMaterial madeOf = UnitMaterial.Metal;
	public Vector3 moveTo;
        virtual public void Awake ()
	{
		moveTo = transform.position;
...etc...

And then

public class PropBuilding : Unit {

	private DestructableBuilding _myBuilding;
	public override void Awake()
	{
		base.Awake();
		_myBuilding = this.GetComponent<DestructableBuilding>();
	}
	public override void ApplyDamage(float dmg) { 
		base.ApplyDamage(dmg);
		_myBuilding.UpdateState(myHealth);
	}
}

public class TankVehicle : Unit
{
        private float firingSpeed;
	public bool testAim = false;

...etc..

public class InfantryUnit : Unit
{

	public enum UnitSubType { Infantry, MG, Mortar, Sniper }
	public UnitSubType unitSubType;

....etc...

Does that help? If you want it more modular you can make a very simple Unit base class and improve as you go. I went with a fat Unit class that has most stuff that EVERY unit should have. In buildings I use the move to as goto marker for units exiting the building, in dynamic units like infantry and tanks, the moveto is also a marker but that the movement modules seek.

One problem with this way of doing things is that there are many many “hidden” variables. You can make a very simple class that is in fact using a ton of other stuff, and if you are not careful you end up having to configure in the editor connections for stuff you dont need.

Another solution, one that I am thinking about implementing is use Components like unity does. Each unit has internal UnitComponents, each of those has only the stuff that you want to add, like Position, Movement, etc. All those could “require” specific components such that Movement will only work if theres a Position component added.
Why use this instead of unitys components? Well, first you dont have the Monobehavior stuff attached, next, you can create very specific components with execution priorities and execution timeouts, frequency, etc. Applying this model you can even make components that retreave their info based on Behavior Trees, SituationalAwareness, TaticalMemory, etc, without ever touching your base unit and keeping it simple.

Thank you for your time.
Both your approaches look very interesting. In the first solution, do you attach the scripts to unit prefabs?

Hey, yes. If I attach the infantry one, it will automatically also be a Unit and have its properties, because… well infantry is a unit.

However beware that if you are building a game with a ton of units, making every property public (and accesible from unity and from extended classes) then unity editor will save those variables on a per asset basis, so, if you down the line want to change something that affects all the units your change (in code) will be overriden because the editor has already a different value saved. You can prevent this by using the static tag.

Also, attaching stuff via editor is good at start, but it gets incredibly ugly and unmanageable once you get a good sized unit in terms of properties.

If you want to go the route of not deriving from MonoBehaviour (not saying you should one way or the other, both are equally valid) then you should probably invert your object model. What you have is a “stats” class that has a GameObject that has a MonoBehaviour that has the same “stats” class so you get this weird circular thing going.

I would have a GameObject that has a MonoBehaviour that has a “stats” class. Then the MonoBehaviour basically acts as a wrapper for the “stats” class so its values can interact with stuff in the engine.

Thank you both for your time, your answers were very helpfull