代码之家  ›  专栏  ›  技术社区  ›  Sekhat

游戏项的类层次结构建议

  •  2
  • Sekhat  · 技术社区  · 16 年前

    我正在写一个泥引擎,我刚开始开发游戏对象模型,它需要可扩展性。

    我需要帮助主要是因为我所做的事情让人感觉很混乱,但我想不出另一个更好的解决方案。

    我有个班级叫 MudObject 和另一个类 Container ,一个容器可以包含多个 MudObjects ,但是是 泥靶 然而,它自己 泥靶 我们需要知道它们包含了什么。

    所以它们看起来像这样:

    public abstract class MudObject
    {
        Container containedBy;
    }
    
    public abstract class Container : MudObject
    {
        List<MudObject> Contains;
    }
    

    (请注意,这些只是示例,一些限定符和访问修饰符、属性等丢失)

    现在,这本身似乎很混乱,但让我们在组合中添加一些其他内容:

    Item 是一个 泥靶 所有的视觉物品(如武器)都将从中继承,但其中一些物品也必须是容器(如箱子)。但在C中不存在多重继承,因此归根结底是接口,最好的选择是使容器成为接口(据我所见),但是我不希望它是因为添加了 泥靶 到容器将导致容器更新 泥靶 S .containedBy 价值。

    有什么想法能使这一切奏效,或者我陷入了使事情变得过于复杂的陷阱?
    如果有的话,你还有什么建议?

    7 回复  |  直到 11 年前
        1
  •  1
  •   fizzer    16 年前

    你所要求的是合理的,并且 Composite Design Pattern

        2
  •  4
  •   Jason Z    16 年前

    我觉得你太复杂了。如果mudObjects可以包含其他mudObjects,则需要的单个基类应该沿着这些线:

    public abstract class MudObject
    {    
        MudObject containedBy; //technically Parent
        List<MudObject> Contains; //children
    }
    

    这类似于WinForms和ASP.NET的工作方式。许多容器控件都是控件,并且可以包含子控件的集合。

        3
  •  1
  •   Jon Limjap    16 年前

    您想要的是非常合理的:它与Windows窗体控件没有什么不同,Windows窗体控件本身可以是其他控件的容器。

    您需要做的是创建自己的 List<MudObject> :

    public class MudObjectList : List<MudObject>
    

    其中实现了添加功能:

    public void new Add(MudObject obj)
    {
        obj.ContainedBy = this;
        base.Add(obj);
    }
    

    注意:此方法隐藏了旧的添加功能,而不是覆盖

    通过这种方式,您可以在添加时立即填充containedby属性。当然,这意味着你所包含的 null 这意味着它是顶级对象。

    最后,我认为没有必要分开 MudObject Container 类,因为作为容器看起来是 泥靶 (FF使用C 3.0自动属性):

    public abstract class MudObject
    {
        MudObject ContainedBy { get; set; }
        MudObjectList Contains { get; set; }
    }
    
        4
  •  0
  •   Jon Grant    16 年前

    为什么不把所有的泥巴都做成容器呢?…或者至少,根据类代码,能够包含其他对象。例如。

    public abstract class MudObject
    {
        MudObject containedBy;
        List<MudObject> contains;
    }
    

    然后,您可以在对象本身设置某种标志,以确定参与者是否能够真正地将事物放入或移出对象本身,而不是使用对象的类型来确定它。

        5
  •  0
  •   Marc Gravell    16 年前

    事实上,把某件东西同时作为一件物品是个坏主意 一个容器。这打破了许多对IList进行假设的绑定场景;因此对于一个胸部,我可能会有一个items属性 胸部就是收藏,但让胸部只是一个胸部。

    然而,对于被问到的问题…

    我想让mudobject成为界面…通过这种方式,您可以使用类似以下内容的内容,它为您提供了一个包含任何具体对象的通用容器,以及自动设置父对象:

    public interface IMudObject
    {
        IMudObject Container { get; set; }
        /* etc */
    }
    
    public class MudContainer<T> : Collection<T>, IMudObject
        where T : IMudObject
    {
    
        public IMudObject Container { get; set; }
    
        protected override void ClearItems()
        {
            foreach (T item in this)
            {
                RemoveAsContainer(item);
            }
            base.ClearItems();
        }
    
        protected override void InsertItem(int index, T item)
        {
            SetAsContainer(item);
            base.InsertItem(index, item);
        }
    
        protected override void RemoveItem(int index)
        {
            RemoveAsContainer(this[index]);
            base.RemoveItem(index);            
        }
        protected override void SetItem(int index, T item)
        {
            RemoveAsContainer(this[index]);
            SetAsContainer(item);
            base.SetItem(index, item);
        }
    
        void RemoveAsContainer(T item)
        {
            if (item != null && ReferenceEquals(item.Container, this))
            {
                item.Container = null;
            }
        }
        void SetAsContainer(T item)
        {
            if (item.Container != null)
            {
                throw new InvalidOperationException("Already owned!");
            }
            item.Container = this;
        }
    }
    
        6
  •  0
  •   Sekhat    16 年前

    在继承的基础上进行组合的想法,答案似乎已经消失了。

    也许我可以做些像这样的事

    public class Container<T> where T : MudObject
    {
        List<T> Contains;
        MudObject containerOwner;
    
        public Container(MudObject owner)
        {
            containerOwner = owner;
        }
        // Other methods to handle parent association
    }
    
    public interface IMudContainer<T> where T : MudObject
    {
        Container<T> Contains { get; }
    }
    
    public class MudObjectThatContainsStuff : IMudContainer
    {
        public MudObjectThatContainsStuff()
        {
            Contains = new Container<MudObject>(this);
        }
    
        public Contains { get; }
    }
    
        7
  •  0
  •   yfeldblum    16 年前

    按照马克的回答,写几个班级,在这个班级里保持一种双向的父子关系。