I am trying to minimize the amount of duplicate code my project has by using inheritance.
For example:
Every Character in my game whether they are Player, Enemy, Or NPC all have a member field HP.
They all also have a function to TakeDamage which effect HP.
In my game, this function is very elaborate comparing the attacker's stats, the attacking weapon stats against the attackee's stats and their equipment.
This function is adjusted frequently to get it so it feels right and I don't want it duplicated on the npc, enemy and player controller, and let us just imagine one-day "networkPlayer" too because hey, a guy can dream!
There are many more functions like this that are the same too and I really would like to have them all in one CharacterController class that PlayerController, EnemyController, etc inherit from.
Okay, so, is this the proper usage of inheritance?
There is a second layer here too.
My players, enemies and npcs are all built from an online Database that changes as new enemies and players are added.
So I have a CharacterBase class that builds the shared variables between characters like HP, Stats, Name, etc...
Then there is the derived classes like EnemyBase (inherits name, hp, stats from Character base) but extends upon this class with its own variables such as Rarety, MaxGoldHeMayCarry, XPGainedIfYouKillMe, etc...
NOW THE PROBLEM IS:
EnemyBase which extends CharacterBase Has two copies of HP! In the inspector it shows up as CharacterBase->HP and EnemyBase->HP
And when I call CharacterController.HP minus one it subtracts one from CharcterBase HP but there is this untouched EnemyBase HP!
This was really wordy. I am sorry. The following is some test code to demonstrate
public class TestingInheritance : MonoBehaviour
{
// set this to an empty prefab in the inspector
public GameObject TestObjectPrefab;
private void Start()
{
GameObject TestPlayer = Instantiate(TestObjectPrefab);
PlayerController pController = TestPlayer.AddComponent<PlayerController>();
pController.TakeDamage(); //calls the overridden version of TakeDamage() (which is good)
GameObject TestEnemy = Instantiate(TestObjectPrefab);
EnemyController eController = TestEnemy.AddComponent<EnemyController>();
eController.TakeDamage(); //calls the overrideden version in EnemyController (which is good)
}
}
[System.Serializable] //comes from db
public class CharacterBase
{
public int HP=100;
}
[System.Serializable] //comes from db
public class Enemy : CharacterBase
{
public string Name = "Enemy";
}
[System.Serializable] //comes from db
public class Player : CharacterBase
{
public string Name = "Player";
}
public class CharacterController : MonoBehaviour
{
//I want to be able to access the variables that all characters share in common, such as HP, Name, Stats, Inventory
public CharacterBase characterBase = new CharacterBase();
/// <summary>
/// Reduces HP by 1
/// TakeDamage() in my real game is actually much more complicated and I dont want to duplicate the code in Enemy, Player, and NPC
/// there are many more functions that I want to be able to call for any kind of character such as UseItem(potion), ChangeState(poisoned), Die()
/// All these functions share a ton of the same code and I dont want to duplicate it, especially because it changes often during my development
/// </summary>
public virtual void TakeDamage()
{
//here we just loose one hp
characterBase.HP -= 1;
}
}
public class PlayerController : CharacterController
{
public Player playerBase = new Player();
public override void TakeDamage()
{
//do the code that is shared for all Characters
base.TakeDamage();
Debug.Log(playerBase.Name + " was hit!--- HP now: " + playerBase.HP);
//Prints Player was hit! --- HP now: 100 and the inspector shows CharacterBase >> HP 99 AND PlayerBase >> HP: 100, Name: Player
//IF WE CHANGE THE ABOVE LINE TO SAY
Debug.Log(playerBase.Name + " was hit!--- HP now: " + characterBase.HP);
//Now we print 99, which is good. but we still have both CharacterBase >> HP 99
//AND the Wrong, ugly, bad, confusing PlayerBase >> HP: 100
}
}
public class EnemyController : CharacterController
{
public Enemy enemyBase = new Enemy();
public override void TakeDamage()
{
base.TakeDamage();
Debug.Log(enemyBase.Name + " was hit! --- HP now: " + enemyBase.HP);
//Prints Enemy was hit! --- HP now: 100 and the inspector shows CharacterBase >> HP 99 AND EnemyBase >> HP: 100, Name: Enemy
}
}

So, how do I restructure this so it only has one variable HP that both CharacterController and PlayerController access?
I am sorry this was so long, is anyone still reading? I dont know how to make this anymore concise...
public int HP=100;inEnemyclass too... (the sample shown here has really no way to behave the way you described)public int HP=100;this is copied and pasted. I think the linepublic Enemy enemyBase = new Enemy();creates the duplicate HP variable. ...I think it is weird toocharacterBase.HP -= 1;behavior wrong (which obviously not going to happen with code shown)... but instead you are expecting some magic in base controller to discover new properties from derived class... instead of using the same property... Indeed code you've shown is demonstrating error completely, you just have a lot of unrelated staff about serialization.