需要C#OOP建议:什么是适合这个的数据结构?
好的,我需要一些可靠的OOP建议。设置如下:我有一个播放器对象,其中包含处理移动、寻路逻辑等事情的代码。现在我需要为每个播放器分配一个大的变量和设置表。也就是说,每个玩家可以执行大约40种不同的武器动作,每种武器都有6-8个相关变量。我的问题是,哪种数据结构最合适。注意,我不想为每种武器创建一个类,因为我的游戏中从未实例化过武器 这里有一些细节:每个玩家都有40种不同的武器,需要按名字命名。例如:需要C#OOP建议:什么是适合这个的数据结构?,c#,oop,data-structures,C#,Oop,Data Structures,好的,我需要一些可靠的OOP建议。设置如下:我有一个播放器对象,其中包含处理移动、寻路逻辑等事情的代码。现在我需要为每个播放器分配一个大的变量和设置表。也就是说,每个玩家可以执行大约40种不同的武器动作,每种武器都有6-8个相关变量。我的问题是,哪种数据结构最合适。注意,我不想为每种武器创建一个类,因为我的游戏中从未实例化过武器 这里有一些细节:每个玩家都有40种不同的武器,需要按名字命名。例如: Weapon #1: Pistol Weapon #2: Shotgun Weapon #3: R
Weapon #1: Pistol
Weapon #2: Shotgun
Weapon #3: Rifle
Weapon #4: Bow
Weapon #5: RocketLauncher
Pistol.HasBeenUnlocked (true/false)
Pistol.Priority (1-40)
Pistol.AmmoQuantityMax (0-10)
Pistol.AmmoQuantityCurrent (0-10)
Pistol.UIButtonState ("Hidden", "Selected", "Deselected", "CoolOff")
Pistol.CoolOffTimerMax (0.0-5.0)
Pistol.CoolOffOn (true/false)
每个武器都有相同的变量集。例如:
Weapon #1: Pistol
Weapon #2: Shotgun
Weapon #3: Rifle
Weapon #4: Bow
Weapon #5: RocketLauncher
Pistol.HasBeenUnlocked (true/false)
Pistol.Priority (1-40)
Pistol.AmmoQuantityMax (0-10)
Pistol.AmmoQuantityCurrent (0-10)
Pistol.UIButtonState ("Hidden", "Selected", "Deselected", "CoolOff")
Pistol.CoolOffTimerMax (0.0-5.0)
Pistol.CoolOffOn (true/false)
现在我需要某种数据结构来组织所有这些变量,并使它们易于访问。例如,我希望能够遍历所有40件武器,并根据它们是否被特定玩家解锁生成按钮。以下是我想做的:
for (int i = 0; i < Player.Weapons.NumberOfWeaponsTotal(); i++) {
if (Player.Weapons.Weapon[i].UIButtonState == "Hidden"){
// don't create a UI button to fire weapon
}
else {
// create a UI button to fire weapon
}
}
for(int i=0;i
不同武器的变量名称将是相同的。所以武器。手枪。UIButtonState将存在,武器。步枪。UIButtonState也将存在
那么,组织这项活动的最佳方式是什么?二维数组并不漂亮。结构似乎不够坚固。一个班的学生看起来很奇怪。我从来没有用过类来做这类事情。我想确保这与玩家有某种联系,所以当他被摧毁时,这个“对象”也是如此。我认为类对于这个场景来说是理想的。创建一个
IWeapon
接口,该接口具有通用属性和方法,如Name
、getammoncount()
、IsEnabled
,等等。然后为每种类型的武器创建具有所有特定属性的类。(但是如果您有8个不同的Pistol,它们具有相同的方法和属性,那么您可以创建一个通用的Pistol
类,并相应地设置变量)
在玩家
对象中,拥有一个列表
来保存玩家拥有的所有武器
当播放器
被销毁时,只需调用列表中的.Empty()
方法即可将其全部删除
持有的武器将是玩家类的附加成员:IWeapon-activewearm
你可以这样做:
if(ActiveWeapon.GetAmmoCount() > 0) ActiveWeapon.Fire());
或:
这里的优势是,你的玩家在运行前不必确切知道他们可能拥有哪些类型的武器,你可以轻松地将它们换成其他武器
编辑:我找到了一个页面,其中给出了一个示例,使用:定义一个结构或类类型,该结构或类类型包含所有不同武器具有的所有属性。创建此武器类型的阵列[40],并将其存储为玩家类型的属性。定义一个整数枚举,用作武器数组中的命名索引。Pistol=0、Shotgun=1等。使用这些枚举名称在代码中索引到武器数组中
在极少数情况下,当您确实需要按字符串名称查找武器时,您只需扫描武器数组,直到找到与您要查找的名称匹配的武器。捕获该武器的索引并丢弃字符串名称,以便所有进一步的操作都由索引数组执行。通过40个项目进行线性扫描的成本将不明显
如果您确实必须避免在列表中扫描匹配的名称,那么可以构建一个字典来提供按名称快速查找。您希望字典条目返回特定玩家的武器,因此需要为每个玩家提供不同的字典实例,并将其存储在玩家对象的字段中。如果简单的扫描就足够了(几乎可以肯定),那么就不用麻烦使用字典方法
无论将武器类型定义为结构还是类,它都是结构化类型,每次使用时都会创建此类型的实例。每个玩家40个实例。类和结构之间的主要区别在于内存分配的位置/方式以及赋值是否复制值。如果您小心地从不将数组中的武器分配到局部武器变量中,并且不使用上面的字典或执行任何其他需要共享对同一武器数据的引用的操作,那么struct应该可以。如果有疑问,请使用类
当玩家离开时,你不必担心武器会被处理掉——只要武器阵列是唯一能长期参考武器的东西,那么当玩家被处理掉时,它们都会被处理掉。适当的封装和最小化不同对象之间的交叉引用将有助于实现这一点
如果你确定你选择的武器总是有相同的变量和相同的动作(方法),那么你可以用一种武器类型来对付所有的武器,这种类型可以是结构或类
如果您开始进入特殊情况,该操作对该武器的行为不同,或者该武器具有其他武器都不需要的附加数据,那么您应该根据需要定义基本武器类别及其后代,以便进行专门化。免责声明
你可以用这样的模型来设计你需要的东西。请记住,与任何设计一样,它可能包含缺陷。它旨在帮助您解决问题,而不是作为解决方案
武器
此类代表应用程序中的武器。
请注意重写方法,以便正确实现比较/搜索/索引
public class Weapon
{
public Weapon(WeaponName name)
{
Name = name;
}
public WeaponName Name { get; set; }
public int Priority { get; set; }
public int MaxAmmoQuantity { get; set; }
public int CurrentAmmoQuantity { get; set; }
public override string ToString()
{
return Enum.GetName(typeof(WeaponName), Name);
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var other = obj as Weapon;
if (other == null) return false;
return Name == other.Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
武器名称public IEnumerable<WeaponName> OwnedWeapons { get; set; }
public event EventHandler<WeaponEventArgs> WeaponGrabbed;
public event EventHandler<WeaponEventArgs> ActiveWeaponChanged;
public void InvokeActiveWeaponChanged()
{
var handler = ActiveWeaponChanged;
if (handler != null) handler(this, new WeaponEventArgs(ActiveWeapon));
}
public void InvokeWeaponGrabbed(Weapon weapon)
{
var handler = WeaponGrabbed;
if (handler != null) handler(this, new WeaponEventArgs(weapon));
}
public void SwitchWeapon(WeaponName weaponName)
{
ActiveWeapon = _ownedWeapons.Where(weapon => weapon.Name == weaponName).First();
InvokeActiveWeaponChanged();
}
public void Grab(Weapon weapon)
{
_ownedWeapons.Add(weapon);
InvokeWeaponGrabbed(weapon);
}
public Weapon Weapon { get; set; }
}
public WeaponRepository()
{
_availableWeapons.Add(WeaponName.Pistol, () => new Weapon(WeaponName.Pistol) );
_availableWeapons.Add(WeaponName.Shotgun, () => new Weapon(WeaponName.Shotgun) );
}
public Weapon Create(WeaponName name)
{
return _availableWeapons[name]();
}
public IEnumerable<WeaponName> AvailableWeapons()
{
return Enum.GetValues(typeof (WeaponName)).Cast<WeaponName>();
}
public IEnumerable<WeaponName> WeaponsNotOwnedBy(Player player)
{
return AvailableWeapons().Where(weaponName => !player.OwnedWeapons.Contains(weaponName));
}
public class WeaponToolbarBuilder
{
private readonly Player _player;
private readonly WeaponRepository _weaponRepository;
private List<WeaponButton> _buttons = new List<WeaponButton>();
public WeaponToolbarBuilder(Player player, WeaponRepository weaponRepository)
{
_player = player;
_weaponRepository = weaponRepository;
_player.ActiveWeaponChanged += _player_ActiveWeaponChanged;
_player.WeaponGrabbed += _player_WeaponGrabbed;
}
void _player_WeaponGrabbed(object sender, WeaponEventArgs e)
{
var weaponButton = _buttons.Where(button => button.WeaponName == e.Weapon.Name).First();
weaponButton.Enable();
}
void _player_ActiveWeaponChanged(object sender, WeaponEventArgs e)
{
var currentActiveButton = _buttons.Where(button => button.Highlighted).First();
currentActiveButton.Highlight(false);
var newActiveButton = _buttons.Where(button => button.WeaponName == e.Weapon.Name);
newActiveButton.Highlight(true);
}
public void BuildToolbar() { ... }
}