2013-03-28 84 views
1

首先要避開,如果我錯過了某些非常明顯的東西,我很抱歉,我在這方面還是比較新的。XNA遊戲在非常奇怪的情況下不會啓動

無論如何,我一直在研究XNA中的小行星克隆,並且由於某些原因,如果點擊「開始調試」按鈕,它偶爾不會啓動。我將問題追蹤到了我的AsteroidsManager類,該類使用初始小行星的int來生成最小和最大速度和旋轉速度以及兩個用於小行星和粒子的紋理列表。現在的怪事:

temp = new AsteroidManager(1, 20, 50, 1, 2, asteroids, particles, true); //With this constructor, the game always starts fine... 

但如果我殺青初步的小行星數量:

temp = new AsteroidManager(10, 20, 50, 1, 2, asteroids, particles, true); //This seems to start about 1/3 times in the Visual Studio debugger, but if I launch it without debugging or from the bin folder, it works fine. 

最後,如果我設置的小行星超過〜20,它永遠不會發生在調試器,如果我嘗試從文件夾中啓動它,該進程將出現在任務管理器中,但是沒有任何事情發生。或者它只是在發佈時崩潰。老實說,我不知道是什麼導致了這一點,並在必要時會很樂意提供任何代碼,但在這裏就是我認爲是相關的:

完全AsteroidManager:

public class AsteroidManager 
{ 
    #region Declarations 

    public List<GameObject> Asteroids { get; set; } 
    public bool RegenerateAsteroids { get; set; } 

    public readonly int InitialAsteroids; 
    public readonly float MinVelocity; 
    public readonly float MaxVelocity; 
    public readonly float MinRotationalVelocity; //in degrees 
    public readonly float MaxRotationalVelocity; //in degrees 
    public readonly List<Texture2D> Textures; 
    public readonly List<Texture2D> ExplosionParticleTextures; 

    List<ParticleEmitter> emitters; 
    Random rnd; 

    const int MINPARTICLES = 50; 
    const int MAXPARTICLES = 200; 
    const int PARTICLEFTL = 40; 

    #endregion 

    public AsteroidManager(
     int initialAsteroids, 
     float minVel, 
     float maxVel, 
     float minRotVel, 
     float maxRotVel, 
     List<Texture2D> textures, 
     List<Texture2D> explosionParticleTextures, 
     bool regenAsteroids) 
    { 
     rnd = new Random(); 

     InitialAsteroids = initialAsteroids; 
     MinVelocity = minVel; 
     MaxVelocity = maxVel; 
     MinRotationalVelocity = minRotVel; 
     MaxRotationalVelocity = maxRotVel; 
     Textures = textures; 
     ExplosionParticleTextures = explosionParticleTextures; 
     RegenerateAsteroids = regenAsteroids; 

     Asteroids = new List<GameObject>(); 
     emitters = new List<ParticleEmitter>(); 

     for (int i = 0; i < InitialAsteroids; i++) 
      addAsteroid(); 
    } 

    public void Update(GameTime gameTime) 
    { 
     for (int i = 0; i < Asteroids.Count; i++) 
      Asteroids[i].Update(gameTime); 

     for (int i = 0; i < emitters.Count; i++) 
      emitters[i].Update(gameTime); 

     if (Asteroids.Count < InitialAsteroids && RegenerateAsteroids) 
      addAsteroid(); 
    } 

    public void Draw(SpriteBatch spriteBatch) 
    { 
     for (int i = 0; i < Asteroids.Count; i++) 
      Asteroids[i].Draw(spriteBatch); 

     for (int i = 0; i < emitters.Count; i++) 
      emitters[i].Draw(spriteBatch); 
    } 

    public void DestroyAsteroid(GameObject asteroid) 
    { 
     int x = rnd.Next(MINPARTICLES, MAXPARTICLES); 
     List<Color> colors = new List<Color>(); 
     colors.Add(Color.White); 

     emitters.Add(new ParticleEmitter(//TODO: Test 
      x, 
      asteroid.WorldCenter, 
      ExplosionParticleTextures, 
      colors, 
      PARTICLEFTL, 
      true, 
      1, 
      x, 
      1f, 
      0.3f, 
      0f, 
      180f)); 

     Asteroids.Remove(asteroid); 
    } 

    protected void addAsteroid() 
    { 
     GameObject tempAsteroid; 
     bool isOverlap = false; 

     do //Do-While to ensure that the asteroid gets generated at least once 
     { 
      Texture2D text = Textures.PickRandom<Texture2D>(); 

      float rot = MathHelper.ToRadians((float)rnd.NextDouble(0f, 359f)); 
      float rotVel = MathHelper.ToRadians((float)rnd.NextDouble(MinRotationalVelocity, MaxRotationalVelocity)); 

      int colRadius = (((text.Width/2) + (text.Height/2))/2); //Get the mean of text's height & width 

      Vector2 vel = Vector2.Multiply(//calculate a random velocity 
       rot.RotationToVectorFloat(), 
       (float)rnd.NextDouble(MinVelocity, MaxVelocity)); 

      Vector2 worldPos = new Vector2(
       rnd.Next(Camera.WorldRectangle.X, Camera.WorldRectangle.Width), 
       rnd.Next(Camera.WorldRectangle.Y, Camera.WorldRectangle.Height)); 

      tempAsteroid = new GameObject(//init a temporary asteroid to check for overlaps 
       text, worldPos, vel, Color.White, false, rot, rotVel, 1f, 0f, colRadius); 

      foreach (GameObject asteroid in Asteroids) 
      { 
       if (tempAsteroid.BoundingBox.Intersects(asteroid.BoundingBox)) 
       { 
        isOverlap = true; 
        break; 
       } 
      } 

     } while (isOverlap); //if overlapping, loop 

     Asteroids.Add(tempAsteroid); //add the temp asteroid 
    } 
} 

全部遊戲對象:

public class GameObject 
{ 
    #region Declarations 

    public Texture2D Texture { get; set; } 
    public Vector2 Origin { get; set; } 
    public Color TintColor { get; set; } 
    public float Rotation { get; set; } //radians 
    public float RotationalVelocity { get; set; } 
    public float Scale { get; set; } 
    public float Depth { get; set; } 
    public bool Active { get; set; } 
    public SpriteEffects Effects { get; set; } 

    public Vector2 WorldLocation { get; set; } 
    public Vector2 Velocity { get; set; } 

    public int CollisionRadius { get; set; } //Radius for bounding circle collision 
    public int BoundingXPadding { get; set; } 
    public int BoundingYPadding { get; set; } //Padding for bounding box collision 

    public int TotalFrames 
    { 
     get //simple get 
     { return totalFrames; } 
     set //check if given totalFrames is in possible range 
     { 
      if (value <= (Rows * Columns)) 
       totalFrames = value; 
      else 
       throw new ArgumentOutOfRangeException(); 
     } 
    } //Used in spritesheet animation 
    private int totalFrames; 

    public int CurrentFrame 
    { 
     get { return currentFrame; } 
     set 
     { 
      currentFrame = (int)MathHelper.Clamp(value, 0, totalFrames); 
     } 
    } 
    private int currentFrame; 

    public int Rows { get; set; } 
    public int Columns { get; set; } 
    public bool Animating { get; set; } 

    public float RotationDegrees 
    { 
     get { return MathHelper.ToDegrees(Rotation); } 
     set { Rotation = MathHelper.ToRadians(value); } 
    } 
    public float RotationVelocityDegrees 
    { 
     get { return MathHelper.ToDegrees(RotationalVelocity); } 
     set { RotationalVelocity = MathHelper.ToRadians(value); } 
    } 

    public const float VELOCITYSCALAR = 1.0f/60.0f; //Default to 60fps standard movement 

    #endregion 

    #region Properties 

    public int GetWidth { get { return Texture.Width/Columns; } } //Width of a frame 
    public int GetHeight { get { return Texture.Height/Rows; } } //Height of a frame 
    public int GetRow { get { return (int)((float)CurrentFrame/(float)Columns); } } //Current row 
    public int GetColumn { get { return CurrentFrame % Columns; } } //Current column 

    public Vector2 SpriteCenter 
    { get { return new Vector2(GetWidth/2, GetHeight/2); } } //Get this Sprite's center 

    public Rectangle WorldRectangle //get rectangle in world coords with width of sprite 
    { 
     get 
     { 
      return new Rectangle(
       (int)WorldLocation.X, 
       (int)WorldLocation.Y, 
       GetWidth, 
       GetHeight); 
     } 
    } 

    public Rectangle BoundingBox //get bounding box for use in collision detection 
    { 
     get 
     { 
      return new Rectangle(//Get bounding box with respect to padding values 
       (int)WorldLocation.X + BoundingXPadding, 
       (int)WorldLocation.Y + BoundingYPadding, 
       GetWidth - (BoundingXPadding * 2), 
       GetHeight - (BoundingYPadding * 2)); 
     } 
    } 

    public Vector2 ScreenLocation 
    { get { return Camera.GetLocalCoords(WorldLocation); } } //get screen coordinates 

    public Rectangle ScreenRectangle 
    { get { return Camera.GetLocalCoords(WorldRectangle); } } //get screen rectangle 

    public Vector2 WorldCenter 
    { 
     get { return WorldLocation + SpriteCenter; } 
     set { WorldLocation = value - SpriteCenter; } 
    } //gets/sets the center of the sprite in world coords 

    public Vector2 ScreenCenter 
    { get { return Camera.GetLocalCoords(WorldLocation + SpriteCenter); } } //returns the center in screen coords 

    #endregion 

    public GameObject(//main constructor, /w added optional parameters and call to SpriteBase init 
     Texture2D texture, 
     Vector2 worldLocation, 
     Vector2 velocity, 
     Color tintColor, 
     bool animating = false, 
     float rotation = 0f, //default to no rotation 
     float rotationalVelocity = 0f, 
     float scale = 1f, //default to 1:1 scale 
     float depth = 0f, //default to 0 layerDepth 
     int collisionRadius = 0, //collision radius used in bounding circle collision, default to 0 or no bounding circle 
     int xPadding = 0, //amount of x padding, used in bounding box collision, default to 0, or no bounding box 
     int yPadding = 0, //amount of y padding, used in bounding box collision, default to 0, or no bounding box 
     SpriteEffects effects = SpriteEffects.None, 
     int totalFrames = 0, 
     int rows = 1, 
     int columns = 1) 

    { 
     if (texture == null) { throw new NullReferenceException("Null texture reference."); } 
     Texture = texture; //assign parameters 
     WorldLocation = worldLocation; 
     TintColor = tintColor; 
     Rotation = rotation; 
     RotationalVelocity = rotationalVelocity; 
     Scale = scale; 
     Depth = depth; 
     Effects = effects; 
     Velocity = velocity; 
     Animating = animating; 
     Active = true; 

     BoundingXPadding = xPadding; BoundingYPadding = yPadding; CollisionRadius = collisionRadius; //assign collision data 
     Rows = rows; Columns = columns; this.TotalFrames = totalFrames; //assign animation data 

     Origin = SpriteCenter; //assign origin to the center of a frame 
    } 

    #region Methods 

    public virtual void Update(GameTime gameTime) 
    { 
     if (Active) //if object is active 
     { 
      WorldLocation += Velocity * (1f/60f); 
      Rotation += RotationalVelocity; //Rotate according to the velocity 
      //Move by Velocity times a roughly 60FPS scalar 

      if (TotalFrames > 1 && Animating) 
      { 
       CurrentFrame++; 
       if (CurrentFrame >= TotalFrames) 
        CurrentFrame = 0; //Loop animation 
      } 

      if (Camera.IsObjectInWorld(this.WorldRectangle) == false) 
      { 
       if (Camera.LOOPWORLD) //if world is looping and the object is out of bounds 
       { 
        Vector2 temp = WorldCenter; //temporary Vector2 used for updated position 

        //X-Axis Component 
        if (WorldCenter.X > Camera.WorldRectangle.Width) 
         temp.X = Camera.WorldRectangle.X - (GetWidth/2); //If X is out of bounds to the right, move X to the left side 
        if (WorldCenter.X < Camera.WorldRectangle.X) 
         temp.X = Camera.WorldRectangle.Width + (GetWidth/2); //If X is out of bound to the left, move X to the right side 

        //Y-Axis Component 
        if (WorldCenter.Y > Camera.WorldRectangle.Height) 
         temp.Y = Camera.WorldRectangle.Y - (GetHeight/2); //If Y is out of bounds to the bottom, move Y to the top 
        if (WorldCenter.Y < Camera.WorldRectangle.Y) 
         temp.Y = Camera.WorldRectangle.Height + (GetHeight/2); //If Y is out of bounds to the top, move Y to the bottom 

        WorldCenter = temp; //Assign updated position 
       } 

       if (Camera.LOOPWORLD == false) 
       { 
        Active = false; //if the object is outside the world but the LOOPWORLD constant is false, set inactive 
       } 
      } 
     } 
    } 

    public virtual void Draw(SpriteBatch spriteBatch) 
    { 
     if (Active) 
     { 
      if (TotalFrames > 1 && Camera.IsObjectVisible(WorldRectangle)) //if multi-frame animation & object is visible 
      { 
       Rectangle sourceRectangle = new Rectangle(GetWidth * GetColumn, 
        GetHeight * GetRow, GetWidth, GetHeight); //get source rectangle to use 

       spriteBatch.Draw(
        Texture, 
        ScreenCenter, 
        sourceRectangle, //use generated source rectangle 
        TintColor, 
        Rotation, 
        Origin, 
        Scale, 
        Effects, 
        Depth); 
      } 
      else //if single frame sprite 
      { 
       if (Camera.IsObjectVisible(WorldRectangle)) //check if sprite is visible to camera 
       { 
        spriteBatch.Draw(
         Texture, 
         ScreenCenter, //center of the sprite in local coords 
         null, //full sprite 
         TintColor, 
         Rotation, 
         Origin, 
         Scale, 
         Effects, //spriteeffects 
         Depth); //layerdepth 
       } 
      } 
     } 
    } 

    public bool IsBoxColliding(Rectangle obj) //bounding box collision test 
    { 
     return BoundingBox.Intersects(obj); 
    } 

    public bool IsBoxColliding(GameObject obj) //overload of previous which takes a GameObject instead of a rectangle 
    { 
     if (BoundingBox.Intersects(obj.BoundingBox)) 
      return true; 
     else 
      return false; 
    } 

    public bool IsCircleColliding(Vector2 objCenter, float objRadius) 
    { 
     if (Vector2.Distance(WorldCenter, objCenter) < 
      (CollisionRadius + objRadius)) //if the distance between centers is greater than the sum 
      return true;     //of the radii, collision has occurred 
     else 
      return false; //if not, return false 
    } 

    public bool IsCircleColliding(GameObject obj) //overload of previous which takes a GameObject instead of loose values 
    { 
     if (Vector2.Distance(this.WorldCenter, obj.WorldCenter) < 
      (CollisionRadius + obj.CollisionRadius)) 
      return true; 
     else 
      return false; 
    } 

    public void RotateTo(Vector2 point) //rotates the GameObject to a point 
    { 
     Rotation = (float)Math.Atan2(point.Y, point.X); 
    } 

    protected Vector2 rotationToVector() 
    { 
     return Rotation.RotationToVectorFloat(); 
    } //local version of extension method 

    #endregion 
} 

Game1 Draw:

protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(Color.CornflowerBlue); 
     spriteBatch.Begin(); //BEGIN SPRITE DRAW 

     fpsDisplay.Draw(spriteBatch); 
     temp.Draw(spriteBatch); 

     spriteBatch.End(); //END SPRITE DRAW 
     base.Draw(gameTime); 
    } 

Game1更新:

protected override void Update(GameTime gameTime) 
    { 
     InputHandler.Update(); //update InputHandler 

     if (InputHandler.IsKeyDown(Keys.Left)) 
      Camera.Position += new Vector2(-3f, 0f); 
     if (InputHandler.IsKeyDown(Keys.Right)) 
      Camera.Position += new Vector2(3f, 0f); 
     if (InputHandler.IsKeyDown(Keys.Up)) 
      Camera.Position += new Vector2(0f, -3f); 
     if (InputHandler.IsKeyDown(Keys.Down)) 
      Camera.Position += new Vector2(0f, 3f); 

     fpsDisplay.Value = (int)Math.Round(1/gameTime.ElapsedGameTime.TotalSeconds, 0); 
     //calculate framerate to the nearest int 

     temp.Update(gameTime); 

     base.Update(gameTime); 
    } 

回答

4

我想你的重疊代碼是從來沒有找到一個地方放置小行星。它進入一個幾乎無限的(或者如果空間被正確覆蓋的話可能是無限的)循環,永遠不會退出。你可能使用一個計數器,給出了一些嘗試,它只是「放棄」。或者你可以增加它們可以產卵的遊戲區域的最大尺寸,或者減小它們的尺寸;這將減少發生這種無限循環的可能性,但不會給予足夠的小行星不可能。

int attempts = 0; 

do //Do-While to ensure that the asteroid gets generated at least once 
{ 
    attempts++; 
    ... 
    foreach (GameObject asteroid in Asteroids) 
    { 
     if (tempAsteroid.BoundingBox.Intersects(asteroid.BoundingBox)) 
     { 
      isOverlap = true; 
      break; 
     } 
    } 

} while (isOverlap && attempts < 20); //if overlapping, loop, give up after 20 tries 

if (attempts == 20) 
{ 
    //log it! Or fix it, or something! 
} 

即使你通過增加遊戲的大小或減少小行星大小「解決」這個問題,我還是建議你把它運行的最大次數,以避免無限循環。

+0

現在很好用,謝謝!我甚至沒有考慮到一個無限循環是問題。 – Lexusjjss

+0

當然要注意,如果它找不到小行星的地方,它將被踢出。因此,如果您指定了20個小行星,則最終只能有16個。 –

相關問題