【发布时间】:2019-09-10 09:36:52
【问题描述】:
我正在尝试通过使用继承来最小化我的项目中的重复代码量。
例如:
我游戏中的每个角色,无论是玩家、敌人还是 NPC,都有一个成员字段 HP。
它们都具有影响HP的TakeDamage功能。
在我的游戏中,这个功能非常精细,可以比较攻击者的属性、攻击武器的属性与被攻击者的属性和他们的装备。
这个功能经常调整以获得它,所以感觉不错,我不希望它在 npc、敌人和玩家控制器上重复,让我们想象一下有一天“networkPlayer”,因为嘿,一个人可以梦想!
还有更多类似的功能也是相同的,我真的很想将它们全部放在一个 CharacterController 类中,PlayerController、EnemyController 等都从该类继承。
好的,那么,这是继承的正确用法吗?
这里还有第二层。
我的玩家、敌人和 npc 都是从在线数据库构建的,该数据库会随着新敌人和玩家的添加而变化。
所以我有一个 CharacterBase 类,它在 HP、Stats、Name 等字符之间构建共享变量...
还有像 EnemyBase 这样的派生类(从 Character base 继承 name、hp、stats),但在这个类上扩展了它自己的变量,如 Rarety、MaxGoldHeMayCarry、XPGainedIfYouKillMe 等......
现在的问题是:
扩展 CharacterBase 的 EnemyBase 有两份HP! 在检查器中,它显示为 CharacterBase->HP 和 EnemyBase->HP
当我打电话时 CharacterController.HP 减一 它从 CharcterBase HP 中减去 1 但是有这个未动过的 EnemyBase HP!
这真的很罗嗦。对不起。下面是一些测试代码来演示
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 都可以访问?
抱歉,写了这么久,还有人在看吗?我不知道如何使这个更简洁......
【问题讨论】:
-
我很确定您没有发布实际代码 - 您的实际代码可能在
Enemy类中也有public int HP=100;...(此处显示的示例确实无法表现你描述的) -
@AlexeiLevenkov 感谢您的阅读!它没有
public int HP=100;这是复制和粘贴的。我认为public Enemy enemyBase = new Enemy();行创建了重复的 HP 变量。 ...我也觉得很奇怪 -
忽略之前的评论 - 我以为你只是在谈论
characterBase.HP -= 1;行为错误(这显然不会在显示的代码中发生)......但相反,你期待基本控制器中的一些魔法来发现新的派生类的属性...而不是使用相同的属性...确实,您显示的代码完全展示了错误,您只是有很多关于序列化的不相关人员。 -
正确,序列化是必要的,因为这些类(Enemy、Player 等)是通过读取由 DB 创建的 json 生成的。是序列化导致我出现问题吗?
-
另外,我不希望基类神奇地发现新属性。我根本不想要新房产!!!我希望派生类使用基类属性
标签: c# unity3d inheritance