繁体   English   中英

C#易于删除的类,MonoGame框架,Visual Studio 2013

[英]C# Easily removable class, MonoGame framework, Visual Studio 2013

我正在使用Visual Studio 2013在MonoGame中开发2D游戏。由于易于实现,我还选择将编辑器实现为包含所有编辑器功能(键/鼠标事件,绘制调用,其他逻辑)的静态类。 我使用Windows窗体是因为它很容易做到,并且我不太在意此任务的性能。

它的工作方式是:编辑器使用编辑器控件实例化一个窗体,并允许我针对每个绘制层直接对内存中的游戏数据执行操作,例如添加/移动/删除图块或其他元素。 我发现它非常方便,并且到目前为止,只要将最少的代码带到主游戏/渲染循环中,它就可以正常工作。 同时,我可以直接在游戏窗口上查看和工作。 要在任何时候排除编辑器,我要做的就是从项目中删除包含Editor类以及所有引用的类的文件夹,并注释掉几行代码,从而为我提供游戏的简洁版本。

但是,我最近发现我需要在绘制循环中添加更多的逻辑,第一个问题是我需要直观地指示选定的图块周围具有矩形边框。 如果我要干扰主要游戏绘制逻辑(Renderer类),这将很容易做到,但我当然不希望将代码保留在那里,因为它可能变得很复杂。

我可以查看绘制的结果(请参见下面的代码,位于Draw覆盖处)并进行绘制,但这将迫使我在编辑器中重新使用部分渲染代码。 而且,这将再次遍历所有图块和逻辑,我发现效率很低。 我想到的最好的实现方法是从游戏的DrawLayer()自己的方法(如果存在)中调用Editor.DrawLayer()。 如果不存在,则什么也不做。 这样,我不需要从代码中删除其他任何内容,只需删除Editor类。

namespace Main
{

    public class Main : Game
    {
        ...

        public Main()
        {
            ...
        }

        protected override void Initialize()
        {
            ...
            Editor.Initialize();    // TODO remove these on publish
        }

        protected override void LoadContent()
        {
            ...
            Editor.LoadContent();   // TODO remove these on publish
        }

        protected override void UnloadContent()
        {
            ...
            Editor.Unload();        // TODO remove these on publish
        }

        protected override void Update(GameTime gameTime)
        {


            Editor.Update();        // TODO remove these on publish
            ...
            Renderer.Instance.Update(gameTime);
            ...
        }

        protected override void Draw(GameTime gameTime)
        {
            Renderer.Instance.Draw(spriteBatch, gameTime);
            ...
            // Editor.Draw();       // I would avoid this
        }
    }
}

通过使用以下方法,我能够识别Editor类是否存在:

private static void GetAssemblies()
{
    Assembly projectAssemblies = Assembly.GetExecutingAssembly();
    namespaceList = new List<string>();

    foreach (Type type in projectAssemblies.GetTypes())
    {
        namespaceList.Add(type.FullName);
    }
}

public void TryStartingEditor()
{
    if (namespaceList.IndexOf("Main.Editor") > -1)
    {
        Config.EditorExists = true;

    }
}

但是,我不能添加任何可以将Editor类移除后仍保留的代码作为任何名称空间,例如:

Editor.whatever();

将不再合法。

我的主要问题是:在没有编译器发疯的情况下,调用此类的方法的好方法是什么?

对于任何其他建议,我都持开放态度,这样我就可以相对于主游戏循环以尽可能少的干扰实现编辑器。

注意。 我知道删除一个类很简单,也删除所有引用该类的代码,这没什么大不了的,也许在项目完成后的5分钟之内,所以知道我不确定要使用这种方法,我很好奇如果可以轻松完成。

以后编辑 我相信我可以简单地通过显示这两种情况来总结问题。 我希望场景2可以通过某种方式实现。

场景1 存在编辑器类

public static class Editor {
    ... everything about editor
}


public function AnyFunctionAnywhere() {
    ...
    if (EditorExists) {
        // Ok, we run this, class exists, no problem.
        Editor.callSomeMethod();
    }
    ....
}

方案2 编辑器类突然丢失,我们不一定要删除对其的所有调用。

public function AnyFunctionAnywhere() {
    ...
    if (EditorExists) {
        // Somehow don't throw "The name 'Editor' does not exist in the current context".
        Editor.callSomeMethod();
    }
    ...
}

谢谢,让我知道我是否应该更清楚地解释任何方面。

我相信我使用System.Reflection找到了一个很好的解决方案。 我创建了一个新的单例类,该类以所需的方式处理调用,并且看起来工作正常。 在这里。

using System;
using System.Collections.Generic;
using System.Reflection;

namespace Main
{
    public class LocalSystem
    {
        // Use this to store the list of classes/methods. bool is redundant
        public static Dictionary<Tuple<string, string>, bool> classMethods = new Dictionary<Tuple<string, string>, bool>();

        // Singleton
        private static LocalSystem instance;

        public static LocalSystem Instance
        {
            get
            {
                if (instance == null)
                {
                    GetAssemblies();    // We do this once. I suspect this to be slow.
                    instance = new LocalSystem();
                }

                return instance;
            }
        }

        // Editor specific callers
        public void InvokeEditorMethod(string methodName)                               // Call function
        {
            invokeClassMethod("Main.Editor", methodName, null);
        }

        public void InvokeEditorMethod(string methodName, params object[] values)       // Call function with some arguments
        {
            invokeClassMethod("Main.Editor", methodName, values);
        }

        // This tries to invoke the class.method
        private void invokeClassMethod(string className, string methodName, params object[] values)
        {
            if (!ClassHasMethod(className, methodName))     // We check if the class name and method exist. If not, we bail out.
                return;

            try
            {
                Type.GetType(className).GetMethod(methodName).Invoke(null, values);
            }
            catch(Exception e)
            {
                if (e is TargetParameterCountException)     // This error might be more common than others
                {
                    throw new Exception("Wrong number of parameters provided for method " + methodName + " within " + className);
                }
                throw;    // Something else went wrong
            }

        }

        private static void GetAssemblies()
        {
            Assembly asm = Assembly.GetExecutingAssembly();

            foreach (Type type in asm.GetTypes())
            {
                string discoveredClass = type.FullName;
                foreach (MethodInfo method in Type.GetType(discoveredClass).GetMethods())
                {
                    if (!classMethods.ContainsKey(new Tuple<string, string>(discoveredClass, method.Name)))
                        classMethods.Add(new Tuple<string, string>(discoveredClass, method.Name), true);
                }
            }
        }

        private static bool ClassHasMethod(string className, string methodName)
        {
            return classMethods.ContainsKey(new Tuple<string, string>(className, methodName));
        }

    }
}

用法:

LocalSystem.Instance.InvokeEditorMethod("Initialize");

要么

LocalSystem.Instance.InvokeEditorMethod("MethodWithParams", 1, "foo");

笔记。

  1. 我没有介绍调用函数的返回值。 尝试了几分钟,但似乎比我愿意花时间多一些。 考虑到我的工作模型,我永远都不会期望返回值。 如果可以的话,这意味着我要将编辑器逻辑移到了不应有的位置,因此我放弃了这一方面。

  2. 您将注意到公开的方法使用“ Main.Editor”类。 这对于我的需求而言尤其如此,但是如果您需要处理多个任意类,则可以公开更广泛的invokeClassMethod实现。

谢谢!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM