我正在用MonoGame写一个2D益智游戏。我刚刚将第一个移动的精灵添加到程序中,并发现我的速度大约是10fps,而且我还没有得到最简单的想法。我不知道我是否能够提供足够的信息来获得帮助,但我认为值得一试。作为参考,移动物体是一个球。
主要更新例程:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
MouseState newState = Mouse.GetState();
if (newState.LeftButton == ButtonState.Pressed && oldState.LeftButton == ButtonState.Released)
{
MouseLeftClicked(newState.X, newState.Y);
}
oldState = newState;
if (gameState == GameState.Playing)
{
try
{
foreach (Ball ball in ballList)
{
ball.Update(gameTime);
}
}
catch(NullReferenceException)
{
}
}
// TODO: Add your update logic here
base.Update(gameTime);
}
球更新程序:
public void Update(GameTime gameTime)
{
this.pos += this.motion * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
主要抽奖例程:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 6; y++)
{
if (gameGrid[x, y] != null)
{
spriteBatch.Draw(backgroundTile, gameGrid[x, y].rect, Color.White);
}
}
}
//Draw menu
if (gameState == GameState.StartMenu)
{
spriteBatch.Draw(startButton, orbPosition, Color.White);
}
//Draw game while playing
if (gameState == GameState.Playing)
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 6; y++)
{
try
{
gameGrid[x, y].pipe.Draw(spriteBatch);
}
catch (NullReferenceException)
{
continue;
}
}
}
foreach (Wheel wheel in wheelList)
{
wheel.Draw(spriteBatch);
}
foreach (Ball ball in ballList)
{
ball.Draw(spriteBatch);
}
}
spriteBatch.End();
base.Draw(gameTime);
}
Ball Draw例程:
public void Draw(SpriteBatch spriteBatch)
{
int sprite = (int)color;
Rectangle sourceRect = new Rectangle(sprite * spriteSize, 0, spriteSize, spriteSize);
Rectangle ballRect = new Rectangle((int)this.pos.X, (int)this.pos.Y, spriteSize * scale, spriteSize * scale);
//spriteBatch.Begin();
spriteBatch.Draw(this.texture, ballRect, sourceRect, Color.White);
//spriteBatch.End();
}
答案 0 :(得分:3)
我测试了你的代码,它在提供纹理时没有滞后。我不得不对你的代码做一些修改,以便在你省略部分之后使其工作。我想省略的部分可能是负责任的,但不太可能。我不知道您正在测试这种机器的类型,但我会提供一些建议以解决您在本地遇到的问题。
在编写高性能代码时,忘记你所知道的关于面向对象行为的所有内容&#39;并思考数据。面向数据的设计就是将数据一起粘贴到大块中并立即处理它们。这要快得多。在许多情况下,对于游戏设计,当有一个时,有很多。使用它对您有利,并传递整个阵列并直接在现场采取行动。
尽可能避免嵌套异常和迭代循环。异常在发生时很昂贵,它们只应在异常时使用,或者如果非常不寻常情况确实发生,并且您希望处理这个边缘&#39;通过抛出异常来强制代码的消费者来处理它。
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 6; y++)
{
try
{
gameGrid[x, y].pipe.Draw(spriteBatch);
}
catch (NullReferenceException)
{
continue;
}
}
}
捕获Null引用嵌套在两个for循环中的异常可能是一个坏主意。如果你需要从其中一个中抛出,那么你可以绘制下一个,如果你希望保持代码原样,那么为什么抛出是必要的。如果它在游戏网格或管道中捕获空,请考虑构造函数应始终将项目置于有效状态,并且列表应始终“完成”#39;如果元素停止存在,则它不应再在列表中。否则,如果一个失败意味着所有失败都将try块移到外面。这种情况比较常见。
分析您的应用程序是一种机制,可以帮助您找到比预期慢的地方,有时甚至为什么。以下是有关如何在visual studio中执行此操作的参考。 Beginners Guide to Performance Profiling以及Walkthrough: Profiling Applications。
也就是说,这些都不会使你的应用程序降低到你所描述的程度。因此,我建议您编辑您的问题,并包括可能是原因的代码的其他相关部分。我在下面附上了一个由您的小例子构建的示例,并进行了一些小的修改,以便以更加极端的方式模拟您的环境。这个例子绘制了100个矩形,每个矩形都是50x50,它们都像你的应用程序一样重新缩放和移动。这些是100个磁贴,如果你自己很慢,你应该查看上面的探查器主题,如果你使用visual studio或尝试从Mono Game's official website或最新的显卡驱动程序获取最新的二进制文件。
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
public IList<Ball> Balls { get; private set; }
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
var rand = new Random();
Balls = new List<Ball>(5);
for(var iii = 0; iii < 100; ++iii)
Balls.Add(new Ball(GraphicsDevice, new Vector2(rand.Next(50, 500), rand.Next(50, 500))));
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
foreach (var ball in Balls)
ball.Update(gameTime);
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
foreach (var ball in Balls)
ball.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
public class Ball
{
public Texture2D Texture { get; }
public Vector2 Position { get; private set; }
public double Scale { get; private set; }
public Ball(GraphicsDevice gd, Vector2 initialPosition)
{
Texture = new Texture2D(gd, 50, 50);
Position = initialPosition;
var data = new Color[100*100];
for (var iii = 0; iii < data.Length; ++iii) data[iii] = Color.YellowGreen;
Texture.SetData(data);
}
private bool _increaseScale, _increaseX, _increaseY;
public void Update(GameTime gameTime)
{
if (Scale < 1)
_increaseScale = true;
else if (Scale > 4)
_increaseScale = false;
if (Position.X < 50)
_increaseX = true;
else if (Position.X > 500)
_increaseX = false;
if (Position.Y < 50)
_increaseY = true;
else if (Position.Y > 500)
_increaseY = false;
Scale += (_increaseScale ? 1.5 : -1.5) * gameTime.ElapsedGameTime.TotalSeconds;
Position += new Vector2((float)((_increaseX ? 100 : -100)*gameTime.ElapsedGameTime.TotalSeconds), (float)((_increaseY ? 100 : -100)*gameTime.ElapsedGameTime.TotalSeconds));
}
public void Draw(SpriteBatch spriteBatch)
{
var source = new Rectangle(0, 0, Texture.Height, Texture.Width);
var dest = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width * (int)Scale, Texture.Height* (int)Scale);
spriteBatch.Draw(Texture, dest, source, Color.White);
}
}