根据菜单中的选项实例化不同的 类

Instantiate different classes depending on option in menu

我正在开发一个 "simple" 游戏,有点像 Factorio,但不是基于网格的。 现在我需要某种系统来跟踪我所有不同的建筑类型并让玩家在菜单中选择一种类型。菜单由 UI class 处理,class 调用 Game class 中的方法来检查金钱和诸如此类的东西。 Game class 然后调用 World class 添加玩家选择的任何建筑物。我认为至少这是相关的部分。

正如我现在所拥有的,为了存储不同的建筑类型,我有一个名为 BuildInstruction 的 class 以及子 classes BuildingBuildInstructionConnectionBuildInstruction.这些 classes 仅包含 Action<> thingamabobs,即 returns 给定世界坐标/两个连接点时的建筑物/连接。

虽然在 Game- 和 IU-class 中,我 运行 遇到了一些问题。我似乎无法以合乎逻辑的方式在 class 之间划分工作...

我知道这是一个可笑的模糊问题,但我有点难以表述。基本上,如果有人知道这类事情的某种常见做法,那就太棒了……我愿意接受所有建议。

谢谢!

顺便说一句,这里有一些代码,如果它有助于理解的话:

这是我用来将某种层次结构中的选项传递给菜单的方式:

public class Category<T>
{
    public string Label { get; private set; }

    public T Me { get; private set; }

    List<Category<T>> children = new List<Category<T>>();

    public IEnumerable<Category<T>> Children => children;

    public bool HasChildren => children.Count() > 0;

    public Category(string label, List<Category<T>> _children)
    {
        Label = label;
        children = _children;
    }

    public Category(string label, T me)
    {
        Label = label;
        Me = me;
    }
}

这是 BuildInstruction class 与子 classes 和 BuildInstruction 对象的静态 List<> 然后我给菜单。

public abstract class BuildInstruction
{
    public static Category<BuildInstruction> BuildInstructions;

    static BuildInstruction()
    {
        BuildInstructions = new Category<BuildInstruction>("Build", new List<Category<BuildInstruction>>()
        {
            new Category<BuildInstruction>("Powergrid", new List<Category<BuildInstruction>>()
            {
                new Category<BuildInstruction>("Powerline", new ConnectionBuildInstruction(
                    (start, end) =>
                    new Powerline(start as IPowerlineConnectable, end as IPowerlineConnectable)
                ))
            }),
            new Category<BuildInstruction>("Logistics", new List<Category<BuildInstruction>>()
            {
                new Category<BuildInstruction>("Pipeline", new ConnectionBuildInstruction(
                    (start, end) =>
                    new Pipeline(start as IPipelineConnectable, end as IPipelineConnectable)
                )),
                new Category<BuildInstruction>("Stockpile", new BuildingBuildInstruction(
                    (worldPos) =>
                    new Stockpile(worldPos)
                ))
            })
        });
    }

    public string Name { get; protected set; }
}

public class BuildingBuildInstruction : BuildInstruction
{
    Func<PointF, Building> BuildFunction;

    public BuildingBuildInstruction(Func<PointF, Building> buildFunction)
    {
        BuildFunction = buildFunction;

    }

    public Building Build(PointF worldPos)
    {
        return BuildFunction(worldPos);
    }
}

public class ConnectionBuildInstruction : BuildInstruction
{
    Func<IConnectable, IConnectable, Connection> BuildFunction;

    public ConnectionBuildInstruction(Func<IConnectable, IConnectable, Connection> buildFunction)
    {
        BuildFunction = buildFunction;
    }

    public Connection Build(IConnectable start, IConnectable end)
    {
        return BuildFunction(start, end);
    }
}

最后,游戏 class:

public class Game
{
    World World = new World();

    public Game()
    {

    }

    public void Update()
    {

    }

    public void Draw(Graphics g)
    {
        World.Draw(g);
    }

    //-----------------------------------------------------

    public void BuyBuilding(Building building)
    {
        if (true) //Check money and whatnot...
        {
            if (ConstructBuilding(building))
            {
                //Success, use money and stuff
            }
            else
            {
                //Fail. Feedback!
            }
        }
        else
        {
            //Not enough money or whatnot. Feedback!
        }
    }

    bool ConstructBuilding(Building building)
    {
        return World.AddWorldObject(new ConstructionSite(building));
        //This ConstructionSite class is just a thing that makes it so that 
        //the actual building-process takes some time in-game
    }
}

我认为 UI class 会令人困惑,而且代码太多(已经太多了?)但它只是调用 Game 中的 BuyBuilding() 方法。现在,我有 BuyBuilding() 方法接受一个 Building 对象,但我真的不知道这是否是一个好方法...

PS。 如果这太含糊太可笑,请毫不犹豫地删除它,我只是想看看是否有人有任何建议或想法...

再次感谢! :D

有很多方法可以做到这一点

一个选项是构建 Class

public class BuildBuilding
{
    public Point Location{get;set;}
    public BuildingType Type{get;set;}

    public void Create(){
        ///logic for creation here
    }
}

这会让你连接 INotifyPropertyChanged 或其他一些监控功能,然后你的 UI 可以用来设置 class 的属性,比如说鼠标到位置和菜单到类型

如果您不需要那么复杂,一个简单的静态创建函数就可以工作,这就是您已经尝试过的方法

public abstract class BuildingType 
{

    public static Building Create(Point location, BuildingType type){
        ///logic for creation here
    }
}

此处 UI 必须一次输入所有参数,但只要您没有太复杂的东西,它是可行的

或者您可以定义接口或虚函数来完成子项的工作class

public abstract class BuildingType 
{
    public abstract Building Create(Point location);//logic in child
}

public interface IBuildable
{
    void Create(Point location)
}

其中任何一个都会强制执行一个抽象句柄,您可以使用它来定义一个没有行为的方法句柄,您可以将您的 UI 连接到每种类型,然后在激活时调用公共函数