shm*_*eps 8 c# xna game-engine
我想实现我所知道的CVAR系统,我不完全确定它的正式名称(如果有的话).
它本质上是一些程序和视频游戏中使用的系统,用户可以拉下控制台并输入命令,例如"变量500"将该变量设置为500.可以在任何半条命游戏中找到此实例,Doom和Quake游戏等等.一般的想法似乎是隐藏底层架构,但仍允许受保护的访问,例如,人们可能能够查看重力的值,但不能更改它.这些值中的一些也可以是函数,例如,用户可能能够输入"创建"以在其位置或指定的某个其他位置创建敌人类型.
通过Half Life 2 SDK,以及我在GoldSrc SDK上记得的内容,看起来他们至少实现了"标记"类别,其中某些命令只能在某些条件下工作,例如,如果设置了其他值,或者如果用户具有某种权限级别.
我最初的想法是创建一个Dictionary或类似的对象,并使用它来将字符串值绑定到函数委托,以及保持"保护"级别的排序,以限制某些命令的使用.但是,这看起来相当麻烦,因为我认为我必须通过手动为我想要实现的每个值或函数添加一个新条目.我也不知道这是否会给我我正在寻找的控制水平.
我理所当然地认为我想要的是一个CVAR System类,以及一个可以接受它的Register函数,一个变量/函数委托,一个访问它的字符串,以及我需要的任何保护级别.这样我可以添加我需要的东西,因为我看到它们,所以一切都仍然在它的相关类和文件中.
我真的只是在寻找一些想法,所以我的问题是:
我并不是在寻找具体的代码,只是更多的结构化设计.而且它不一定是"商业"或工作就像另一个,我只需要一些东西让我去.
您可以编写一个解析器来查找类似的命令
/object_property value
/object_method arg1 arg2
Run Code Online (Sandbox Code Playgroud)
正如您所建议的,字典可以将这些字符串映射到属性和函数。字典的创建可以使用反射动态完成,方法是循环遍历合格的对象,获取它们的公共方法和访问器,并为它们生成一个字符串。
然后可以将字典映射到类中以方便和错误检查。
对于方法,字典值可以是接受 0..n 个参数的委托,对于属性/字段,您将需要能够在实际字段和字典值之间进行一些数据绑定。除非您的对象本身引用字典来获取它们的值,在这种情况下,这些值仅存在于适当的位置。
为此,您可以简单地在对象构造函数中使用反射注册属性,然后在属性中调用字典。
[Flags]
public enum CVarAccessibilities
{
Settable,
Gettable
}
public class CVar<T>
{
public CVarAccessibilities Accessibility { get; set; }
T val;
public T Value {
get { return val; }
set
{
if (!Accessibility.HasFlag(CVarAccessibilities.Settable))
return; // just don't set it, maybe print some warning
val = value;
}
}
}
public static class CVarRegistry
{
static Dictionary<string, Object> CVars;
static CVarRegistry { /* use reflections to initialize the dictionary */ }
public static T GetValue<T>(Type owner, string paramName)
{
CVar cvar;
if (!CVars.TryGetValue(owner.Name + "_" + paramName, out cvar)
throw new MyCustomException();
return (T)cvar.Value;
}
public static void SetValue<T>(Type owner, string paramName, T value)
{
CVar cvar;
if (!CVars.TryGetValue(owner.Name + "_" + paramName, out cvar)
throw new MyCustomException();
cvar.Value = value;
}
}
public class MyObject
{
public static int MyRegisteredValue
{
get { return Global.CVarRegistry.GetValue<int>(typeof(MyObject), "MyRegisteredValue"); }
set { Global.CVarRegistry.SetValue(typeof(MyObject), "MyRegisteredValue"); }
}
}
Run Code Online (Sandbox Code Playgroud)
希望有帮助!