与AS3/GML类似的C#语句
本文关键字:语句 AS3 GML | 更新日期: 2023-09-27 18:20:00
我正在使用Monogame制作一个游戏,我一直在尝试如何实现一个与AS3和GML的语句类似的函数。
到目前为止,我有一个可以工作的系统,但并不是完全按照我想要的方式。我将我的游戏对象存储在列表词典中。这样我就可以找到我想要访问的特定类型的对象,而不必遍历所有对象的列表。使用的键是类型的名称。
public static Dictionary<string, List<GameObject>> All =
new Dictionary<string, List<GameObject>>();
我使用AllOf访问所有特定类型的对象。如果字典中存在包含该类型的列表,则返回该列表,否则返回空列表。
public static List<GameObject> AllOf(Type type)
{
string key = type.Name;
if(All.ContainsKey(key))
{
return All[key];
}
return new List<GameObject>();
}
如何实现的示例
public override void Update(GameTime gameTime)
{
List<GameObject> list = Instance.AllOf(typeof(Dummy));
for(int i = 0; i < list.Count; i++)
{
list[i].Update(gameTime);
list[i].foo += bar;
}
}
但我宁愿使用类似于AS3/GML with语句的东西,它也允许执行其他非成员代码。
with(typeof(Dummy))
{
Update(gameTime);
foo += bar;
int fooBar = 2;
someObject.someMemberFunction(fooBar);
}
有办法做到这一点吗?我的最终目标只是让我的代码看起来更干净,并且更容易进行大量更改,而不必每次都键入for循环。
C#中不存在这样的语法,但可以访问for
中与集合无关的方法:
public override void Update(GameTime gameTime)
{
List<GameObject> list = Instance.AllOf(typeof(Dummy));
for(int i = 0; i < list.Count; i++)
{
list[i].Update(gameTime);
list[i].foo += bar;
int fooBar = 2;
someObject.someMemberFunction(fooBar);
}
}
请注意,如果您不需要索引器,也可以使用foreach
,这是一种小清洁器:
foreach(var item in list)
{
item.Update(gameTime);
item.foo += bar;
int fooBar = 2;
someObject.someMemberFunction(fooBar);
}
尝试
using(Object myObject = new Object()){
}
我想这可能是你想要用的?
我为这个用例提供了一个小的解决方案。这可能有点像死柱,但这是一个非常巧妙的解决方案。此外,我认为在提出这个问题时,所有需要的C#功能都已经存在了。
通过使用某种形式的委托作为静态方法的参数,并传递lambda作为该参数,可以执行与GMLwith(x){}
非常类似的操作。该函数甚至可以被泛型化,并且可以通过using static
语句在没有类名的情况下调用它。您需要显式提供类型化/命名参数,但是可能的。你需要将其连接到你自己的类型,但总体思路是:
namespace NiftyStuff {
public static class With {
public static void with<T>(Action<T> proc) where T : GameObj {
var typeName = typeof(T).Name;
foreach (var item in GameObj.AllOf(typeName)) { proc((T)item); }
}
}
public class GameObj {
private static Dictionary<string, List<GameObj>> All = new Dictionary<string, List<GameObj>>();
public static List<GameObj> AllOf(string name) {
return All.ContainsKey(name) ? All[name] : null;
}
public static void Add(GameObj foo) {
string typeName = foo.GetType().Name;
List<GameObj> foos = All.ContainsKey(typeName) ? All[typeName] : (All[typeName] = new List<GameObj>());
foos.Add(foo);
}
public float x, y, angle;
public GameObj() { x = y = angle = 0; }
public void Destroy() { AllOf(GetType().Name)?.Remove(this); }
}
public class Enemy : GameObj {
public float maxHealth, curHealth;
public Enemy() : base() { maxHealth = curHealth = 300; }
public Enemy(float health) : base() { maxHealth = curHealth = health; }
public bool Damage(float amt) {
if (curHealth > 0) {
curHealth -= amt;
return curHealth <= 0;
}
return false;
}
}
public class Pumpkin : GameObj {
public bool exists = false;
public Pumpkin() : base() { exists = true; }
public bool LookAt() { return (exists = !exists); }
}
}
实际使用上述代码的工作方式如下:
using NiftyStuff;
using static NiftyStuff.With;
//...
with ((Enemy e) => {
if (e.Damage(50)) {
Log("Made a kill!"); // Whatever log function you have...
}
});
with ((Pumpkin p) => {
if (p.LookAt()) {
Log("You see the pumpkin");
} else {
Log("You no longer see the pumpkin");
}
});
虽然与GML的with
语句不完全一样,但它至少可以让您针对某些类型的所有注册对象运行代码。
一个重要的注意事项是,不能用这种方式破坏集合内部的对象(因为在迭代集合时同时修改集合)。你需要收集所有要销毁的对象,然后在"全部"中将它们从列表中删除,通常在游戏循环中,这是在一帧结束时完成的。
希望这能有所帮助,尽管已经过时2年了。