首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >需要C# OOP建议:什么是合适的数据结构?

需要C# OOP建议:什么是合适的数据结构?
EN

Stack Overflow用户
提问于 2011-06-24 06:17:46
回答 3查看 375关注 0票数 3

好吧,我需要一些可靠的OOP建议。设置是这样的:我有一个player对象,里面有处理移动、寻路逻辑等事情的代码。现在我需要给每个player分配一个大的变量和设置表。也就是说,每个玩家可以执行大约40个不同的武器动作,每个武器有6-8个与之相关的变量。我的问题是,哪种数据结构最合适。注意,我不想为每个武器创建一个类,因为在我的游戏中武器永远不会被实例化。

以下是细节:每个玩家都有40种不同的武器,需要按名称拉动。例如:

代码语言:javascript
复制
Weapon #1: Pistol
Weapon #2: Shotgun
Weapon #3: Rifle
Weapon #4: Bow
Weapon #5: RocketLauncher

然后,每个武器都有相同的一组变量分配给它。例如:

代码语言:javascript
复制
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个武器,并根据它们是否被特定玩家解锁来为它们生成按钮。这是我想要做的:

代码语言:javascript
复制
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
     }
}

不同武器的变量名称将是相同的。因此,和Weapons.Rifle.UIButtonState一样,Weapons.Pistol.UIButtonState也将存在。

那么组织这件事的最佳方式是什么呢?二维数组并不美观。一个结构似乎不够健壮。一个类看起来很奇怪。我从来没有使用过类来处理这类事情。我想要确保这与玩家有某种联系,所以当他被摧毁时,这个“物体”也是如此。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-24 06:38:19

定义一个包含所有不同武器所具有的所有属性的结构或类类型。创建此武器类型的array40,并将其存储为播放器类型的属性。定义一个into枚举,用作武器数组中的命名索引。在你的代码中使用这些枚举名称来索引武器数组。

在极少数情况下,当您确实需要通过字符串名称查找武器时,您只需扫描武器数组,直到找到与您要查找的武器名称相匹配的武器。捕获该武器的索引并丢弃字符串名,以便所有后续操作都通过索引数组进行。对40个项目进行线性扫描的成本将不会很明显。

如果您确实必须避免扫描列表以查找匹配的名称,则可以构造一个字典来提供按名称的快速查找。您希望字典条目返回特定玩家的武器,因此您需要为每个玩家提供一个不同的字典实例,并将其存储在player对象的一个字段中。如果简单的扫描就足够了(几乎可以肯定是这样),那么就不要费心使用字典方法。

无论您将武器类型定义为结构还是类,它都是结构化类型,并且每次使用它时都会创建此类型的实例。每个播放器40个实例。class和struct之间的主要区别在于内存是在哪里/如何分配的,以及赋值是否复制值。如果您非常小心,从不将数组中的武器赋值给本地武器变量,并且不使用上面的字典或执行任何其他需要共享对相同武器数据的引用的操作,那么struct应该没问题。如果有疑问,可以使用class。

你不需要担心当玩家离开时武器会被丢弃--只要武器数组是唯一长期参考武器的东西,那么当玩家被丢弃时,它们都会被丢弃。适当的封装和最小化不同对象之间的交叉引用在这里会有所帮助。

如果您确定您选择的武器将始终具有相同的变量和相同的操作(方法),那么您可以为所有武器使用单一的武器类型,该类型可以是结构或类。

如果您开始遇到该武器的此操作行为不同的特殊情况,或者此武器具有其他武器都不需要的额外数据,那么您应该考虑根据需要定义基本武器类及其后代以进行专门化。

票数 1
EN

Stack Overflow用户

发布于 2011-06-24 06:24:14

我认为类对于这个场景来说是很理想的。创建一个具有NameGetAmmoCount()IsEnabled等常见属性和方法的IWeapon接口,然后为每种类型的武器创建具有所有特定属性的类。(但如果您有8个不同的手枪,具有相同的方法和属性,则可以创建一个泛型Pistol类并相应地设置变量)。

Player对象中,有一个List<IWeapon>来保存玩家拥有的所有武器。

Player被销毁时,只需调用列表上的.Empty()方法即可将其全部删除。

持有的武器将是Player类的另一个成员:IWeapon ActiveWeapon

你可以这样做:

代码语言:javascript
复制
if(ActiveWeapon.GetAmmoCount() > 0) ActiveWeapon.Fire());

或者:

代码语言:javascript
复制
this.ActiveWeapon = new Pistol("LaserPistol");
this.Weapons.Add(this.ActiveWeapon);

this.ActiveWeapon = new AssaultRifle();

这样做的好处是,在运行时之前,您的Player不必确切知道它们可能拥有哪些类型的武器,您可以轻松地将它们替换为其他类型的武器。

编辑:我找到一个页面,它使用Strategy design patternhttp://hnaser.blogspot.com/2009/07/abc-of-design-patterns.html提供了一个示例

票数 4
EN

Stack Overflow用户

发布于 2011-06-24 13:03:21

免责声明

您可以使用这样的模型来获取您需要的内容。请记住,与任何设计一样,它也可能包含缺陷。它的目的是帮助您解决问题,而不是作为一种解决方案。

武器

这个类代表了你的应用中的一个武器。注意覆盖方法,以便正确地实现比较/搜索/索引。

代码语言:javascript
复制
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();
    }
}

WeaponName

修正了武器名称的选项(假设,如你所说,它们的选项有限)

代码语言:javascript
复制
public enum WeaponName
{
    Pistol,
    Shotgun,
    Rifle,
    Bow,
    RocketLauncher
}

播放器

请注意:

  • 在内部,您可以将武器存储在您喜欢的结构中,但对于外部世界,只有IEnumerable实例发布
  • 它表示玩家可以抓取武器或更改活动的武器(在这里您可以添加所需的任何操作)。通过事件,玩家与外界交流他的动作。
  • 你给对象的方法赋予了语义。而不是player.Weapons.Add,而是显式地显示玩家的行为。

公有类播放器{私有只读IList _ownedWeapons =新列表();受保护武器ActiveWeapon { get;私有集合;}

public IEnumerable OwnedWeapons { get;set;} public event EventHandler WeaponGrabbed;public event EventHandler ActiveWeaponChanged;public void (){ var handler = ActiveWeaponChanged;if (handler != null) handler(this,new WeaponEventArgs( ActiveWeapon ));} public void (武器){ var handler = WeaponGrabbed;if (handler != null) handler(this,new WeaponEventArgs(武器));} public void (WeaponName weaponName) {ActiveWeapon=_ownedWeapons.Where(en22 => )();InvokeActiveWeaponChanged();} public void Grab(武器武器){_ownedWeapons.Add(武器);InvokeWeaponGrabbed(武器);}

}

公共类武器: EventArgs {公共WeaponEventArgs (武器武器){WeaponEventArgs=武器;}

公共武器{ get;set;} }

WeaponsRepository

  • 集中了玩家可以在你的应用程序中使用的所有关于武器的知识,在constructor.
  • Also,中注册可用的武器名称及其创建它提供了创建和查询可用武器的方法。
  • 您可以通过使用WeaponsNotOwnedBy方法来判断玩家还没有哪些武器。

公共类WeaponRepository { readonly Dictionary> _availableWeapons =新Dictionary>();

公共武器() { _availableWeapons.Add(WeaponName.Pistol,() => new Weapon(WeaponName.Pistol) );_availableWeapons.Add(WeaponName.Shotgun,() => new Weapon(WeaponName.Shotgun) );}公共武器创建(WeaponName name) { return _availableWeaponsname;}公共IEnumerable AvailableWeapons() { return Enum.GetValues(typeof (WeaponName)).Cast();}公有IEnumerable播放器(播放器){WeaponsNotOwnedBy AvailableWeapons().Where(weaponName => !player.OwnedWeapons.Contains(weaponName));}

}

使用

  • 你可以在BuildToolbar方法中使用AvailableWeapons in WeaponRepository的方法,让一个类负责构建和更新玩家的,每个武器一个按钮。
  • 在这个类中,订阅玩家的事件。通过这种方式,您可以根据需要启用/禁用/突出显示活动武器。

注意:为简洁起见,我省略了WeaponButton

代码语言:javascript
复制
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() { ... }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6461268

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档