【问题标题】:SpriteBatch: "Begin cannot be called again until End has been successfully called."SpriteBatch:“在成功调用 End 之前,无法再次调用 Begin。”
【发布时间】:2021-07-23 14:33:35
【问题描述】:

所以我启动了我当前的项目,我做的第一件事就是运行它,它给了我上面的异常。昨晚运行良好。这是我的 Draw 事件中的所有代码。 spriteBatch.Begin 不会出现在项目的其他任何地方。在此处删除 Begin 会导致 spriteBatch.Draw 引发异常,将 spriteBatch.End 放在 begin 之前也会引发异常。我不知道出了什么问题以及如何解决这个问题。

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();
spriteBatch.Draw(background, Vector2.Zero, Color.White);

player.Draw(spriteBatch);
level1.Draw(spriteBatch);

spriteBatch.End();

base.Draw(gameTime);

【问题讨论】:

  • 完整的故事,能否提供player和level1的绘制方法?因为问题可能是由这些方法引起的。
  • 2 可能性:1|在 player.draw 或 level1.draw 你调用 spritebatch.begin() 2| spirteBatch.End() 没有被调用,因为你没有到达它。

标签: c# exception xna spritebatch


【解决方案1】:

好吧,我需要查看您的 levek1.Draw 和 player.Draw 以获取我的信息,但我对此有何期待。在其中一种方法中,您正在调用spriteBatch.Begin(),您必须在调用此之前调用End()

所以如果你的播放器类的绘制方法是这样的

Draw(Spritebatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(PlayerSprite,PlayerPosition, etc);
spriteBatch.End();
}

您需要删除 BeginEnd 调用,因为它们已被父方法调用。

编辑:没看清楚,我看你相信这不是问题,但我们需要看看其他方法来找出问题。

【讨论】:

    【解决方案2】:

    您的某个绘图调用可能引发了异常。这将使您在不调用spriteBatch.End() 的情况下退出该方法,然后在下一次通过时,您将在spriteBatch.Begin() 上得到一个异常。 (虽然我想知道为什么第一个异常没有结束你的程序,但第二个却结束了。)

    如果这是问题所在,一种解决方案是将绘图调用包装在 try/finally 块中:

    spriteBatch.Begin();
    spriteBatch.Draw(background, Vector2.Zero, Color.White);
    
    try {
       player.Draw(spriteBatch);
       level1.Draw(spriteBatch);
    } finally {
       spriteBatch.End();
    }
    

    另一种可能是您实际上不小心调用了两次spriteBatch.Begin()。就我个人而言,我通过将 SpriteBatch 对象包装在不同的类中来避免这样做。

    例如:

    internal sealed class DrawParams
    {
       private SpriteBatch mSpriteBatch;
       private bool mBegin;
    
       /// <summary>Calls SpriteBatch.Begin if the begin value is true. Always call this in a draw method; use the return value to determine whether you should call EndDraw.</summary>
       /// <returns>A value indicating whether or not begin was called, and thus whether or not you should call end.</returns>
       public bool BeginDraw()
       {
          bool rBegin = mBegin;
    
          if (mBegin)
          {
             mSpriteBatch.Begin();
             mBegin = false;
          }
    
          return rBegin;
       }
    
       /// <summary>Always calls SpriteBatch.End. Use the return value of BeginDraw to determine if you should call this method after drawing.</summary>
       public void EndDraw()
       {
          mSpriteBatch.End();
       }
    }
    

    【讨论】:

      【解决方案3】:

      ctrl+F 并选择Entire Solution,查找spriteBatch.Begin() 并将其删除到不属于它的位置。我怀疑您的playerlevel 抽奖调用中可能有额外的副本。

      还要确保您为精灵批次使用了正确的变量,它可能被称为SpriteBatch,首字母大写。

      无论如何,您可以尝试从您的项目中删除(用// 评论它们)所有 spritebatch 调用,看看它是否仍然引发异常。

      【讨论】:

        【解决方案4】:

        我自己也遇到过这个问题,但没有任何建议在这里奏效。最后,我意识到在我的开始/结束部分中,我await正在使用异步方法。

        意识到这可能会在完成之前重新启动该方法,我只是添加了一个bool isDrawing 变量并在绘制之前检查它。

        HTH

        【讨论】:

          【解决方案5】:

          如果您在 spritebatch 忙于绘图时退出它,您将遇到同样的问题。例如,当您从另一个事件(例如计时器)离开屏幕时。

          在我的例子中,我声明了一个私有变量来存储 SpriteBatch 是否被中断,

          private bool _spriteBatchInterrupted = false;
          

          并在 SpriteBatch 持续绘制时检查它,

              Game.SpriteBatch.Begin();
              if (_spriteBatchInterrupted)
              {
                  Game.SpriteBatch.End();
                  return;
              }...
          

          然后在其他事件中设置变量,例如定时器超时事件

          private void CountdownTimer_Elapsed(object sender, ElapsedEventArgs e)
          {
             _spriteBatchInterrupted = true;
             NavigateTask();
          }
          
               
          

          【讨论】:

            猜你喜欢
            • 2011-04-07
            • 2018-11-24
            • 2022-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-30
            • 2023-04-01
            • 1970-01-01
            相关资源
            最近更新 更多