我正在尝试通过使用继承来减少项目中重复代码的数量。
例如:
我游戏中的每个角色,无论是玩家,敌人还是NPC,都拥有HP成员字段。
它们还具有TakeDamage功能,可以影响HP。
在我的游戏中,此功能非常详尽地比较了攻击者的统计信息,攻击武器的统计数据与被攻击者的统计数据及其装备。
此功能经常调整以获得它,这样感觉就对了,我不希望它在npc,敌人和玩家控制器上重复出现,而让我们也只想象一个“ networkPlayer”,因为嘿,一个人可以梦想!
还有很多类似的功能,我真的很想把它们全部放在一个PlayerController,EnemyController等继承的CharacterController类中。
好吧,这是继承的正确用法吗?
这里也有第二层。
我的玩家,敌人和NPC都是通过在线数据库构建的,该数据库随着添加新的敌人和玩家而变化。
所以我有一个CharacterBase类,该类在HP,Stats,Name等字符之间构建共享变量。
然后有诸如EnemyBase之类的派生类(继承名称,hp,来自Character基数的统计信息),但在该类上扩展了自己的变量,例如Rarety,MaxGoldHeMayCarry,XPGainedIfYouKillMe等...
现在的问题是:
EnemyBase扩展了CharacterBase 有两份惠普! 在检查器中,它显示为CharacterBase-> HP和EnemyBase-> HP
当我打电话时 CharacterController.HP减一 从CharcterBase HP减去1 但是,这是没有动过的EnemyBase HP!
这真的很罗word。对不起。以下是一些测试代码来演示
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
}
}
那么,我该如何重组它,使其只有一个变量HP可供CharacterController和PlayerController访问?
很抱歉,这么长时间了,有人还在读书吗?我不知道如何使它变得更加简洁...
答案 0 :(得分:4)
public CharacterBase characterBase = new CharacterBase();
所有继承自它的类都将与它们的自己代码(例如public Enemy enemyBase = new Enemy();
)分开调用。
这就是为什么您同时看到两者。结果,每个控制器都有两个单独的统计信息。如果要访问它,则需要在字符控制器中创建一个get
方法:
public CharacterBase stats { get; protected set; }
然后在其子类中用值填充该字段。
答案 1 :(得分:0)
感谢Draco18的回答使它奏效了。
为了避免重复的字段,我们绝对需要删除:
public CharacterBase characterBase = new CharacterBase();
但是我们仍然需要对characterBase的引用,所以我添加了:
protected CharacterBase characterBase;
public void Init(CharacterBase _characterBase)
{
characterBase = _characterBase;
}
现在Start()看起来像这样
private void Start()
{
GameObject TestPlayer = Instantiate(TestObjectPrefab);
TestPlayer.name = "p";
PlayerController pController = TestPlayer.AddComponent<PlayerController>();
pController.Init(pController.playerBase);
pController.TakeDamage();
}
做到了!没有更多重复的字段!并在Debug.Log中正确输出-谢谢大家!