2013-03-28 5 views
1

첫 번째로 빠져 나가야 할 것이 있습니다. 미안하지만 (매우) 분명하지 않은 점이 있다면, 나는 아직도 이것에 대해 조금 새로운 것입니다.아주 이상한 조건에서 XNA 게임을 실행하지 마십시오

어쨌든, 나는 XNA에서 소행성 복제본을 작성해 왔으며 어떤 이유로 디버깅 시작 버튼을 누르면 때때로 시작되지 않습니다. 나는 AsteroidsManager 클래스에이 문제를 추적했다.이 클래스는 소행성과 입자에 대한 최소 및 최대 속도와 회전 속도, 그리고 두 개의 텍스처 목록을 생성하기 위해 초기 소행성의 정수를 사용했다. 이제 불확실성 :

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); 
    } 

게임 1 업데이트 :

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 개로 끝납니다. –