我正在将SFML用于C#。我想创建一个BackgroundImage Sprite,然后开始在其顶部使用以圆圈表示的Agent进行绘制,如下所示:
Y = 21.18 + -.003x_1 + .43x_2 + .02x_3 + .0003x_4 + .002x_5 + .110x_6
启动时一切正常,但是几秒钟后,大约在进程内存达到70MB时,BackgroundImage变成了完全白色的精灵。如果我将BackgroundImage和GetBackground()的类型更改为RenderTexture,则返回“ render”对象,然后像这样更改DrawBackground()函数
static void Main(string[] args)
{
Window = new RenderWindow(new VideoMode((uint)map.Size.X * 30, (uint)map.Size.Y * 30), map.Name + " - MAZE", Styles.Default);
while (Window.IsOpen)
{
Update();
}
}
static public RenderWindow Window { get; private set; }
static Map map = new Map(string.Format(@"C:\Users\{0}\Desktop\Maze.png", Environment.UserName));
static public void Update()
{
Window.Clear(Color.Blue);
DrawBackground();
DrawAgent();
Window.Display();
}
static void DrawAgent()
{
using (CircleShape tempCircle = new CircleShape
{
FillColor = Color.Cyan,
Radius = 15,
Position = new Vector2f(30, 30),
Origin = new Vector2f(30, 30),
Scale = new Vector2f(.5f, .5f)
})
{
Window.Draw(tempCircle);
}
}
static private Sprite BackgroundImage { get; set; }
static void DrawBackground()
{
if (BackgroundImage == null)
BackgroundImage = GetBackground();
Window.Draw(BackgroundImage);
}
static Sprite GetBackground()
{
RenderTexture render = new RenderTexture((uint)map.Size.X * 30, (uint)map.Size.Y * 30);
foreach (var point in map.Grid.Points)
{
RectangleShape pointShape = new RectangleShape(new Vector2f(30, 30));
switch (point.PointType)
{
case PointType.Walkable:
pointShape.FillColor = Color.White;
break;
case PointType.NotWalkable:
pointShape.FillColor = Color.Black;
break;
case PointType.Start:
pointShape.FillColor = Color.Red;
break;
case PointType.Exit:
pointShape.FillColor = Color.Blue;
break;
}
pointShape.Position = new Vector2f(point.Position.X * 30, point.Position.Y * 30);
render.Draw(pointShape);
}
Sprite result = new Sprite(render.Texture);
result.Origin = new Vector2f(0, result.GetLocalBounds().Height);
result.Scale = new Vector2f(1, -1);
return result;
}
然后,背景精灵不会变白,而是存储整个RenderTexture而不是Sprite,然后每次我们调用RenderBackground()函数时不断创建新的Sprite对象似乎是一个坏主意。 GetBackground()函数有什么方法可以返回一个Sprite,一旦该函数的本地“ render”变量被破坏,该Sprite不会变白?
答案 0 :(得分:0)
您并没有完全摆脱假设。简化后,SFML知道两种资源:
轻资源是可以快速创建和销毁的小物体。放下它们并稍后重新创建并没有什么坏处。典型示例为Sprite
,Sound
,Text
,以及基本上大多数SFML类。
大量资源通常是大对象或需要文件访问权限才能创建或使用的对象。典型示例为Image
,Texture
,SoundBuffer
和Font
。您不应该重新创建它们,而是在需要它们时让它们保持活动状态。如果处理得太早,使用它们的轻型资源将在某种程度上失败。
一个精灵的纹理变成白色-正如您所发现的-分配/释放的纹理的典型标志。
有很多不同的方法,但是我建议您创建一种简单的资源管理器,该管理器将及时加载资源,或者如果已经加载,则将它们返回。
我还没有在C#中使用SFML,并且已经有一段时间没有真正接触过C#了,但是对于简单的实现,您只需使用Dictionary<string, Texture>
。当您想要加载texture.png
之类的纹理文件时,您会查看是否存在带有该键名的字典条目。如果有,则将其退回。如果没有,请创建新条目并加载纹理,然后将其返回。
我没有练习,所以请考虑使用此伪代码!
private Dictionary<string, Texture> mTextureCache; // initialized in constructor
public Texture getTexture(file) {
Texture tex;
if (mTextureCache.TryGetValue(file, out tex))
return tex;
tex = new Texture(file);
mTextureCache.add(file, tex);
return tex;
}
// Somewhere else in your code:
Sprite character = new Sprite(getTexture("myCharacter.png"));
如果您的繁重资源是RenderTexture
,则只需确保它一直有效就可以使用(例如,作为单独的成员)。
答案 1 :(得分:0)
原来,答案比我预期的要简单。我要做的就是创建一个新的Texture对象,然后用它制作一个Sprite。所以代替
Sprite result = new Sprite(render.Texture);
我写了
Sprite result = new Sprite(new Texture(render.Texture));
现在垃圾回收器不会处理Sprite的纹理