[英]No option to add Visual C# class in models in 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");
笔记。
我没有介绍调用函数的返回值。 尝试了几分钟,但似乎比我愿意花时间多一些。 考虑到我的工作模型,我永远都不会期望返回值。 如果可以的话,这意味着我要将编辑器逻辑移到了不应有的位置,因此我放弃了这一方面。
您将注意到公开的方法使用“ Main.Editor”类。 这对于我的需求而言尤其如此,但是如果您需要处理多个任意类,则可以公开更广泛的invokeClassMethod实现。
谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.