2012-04-05 101 views
3

我正在開展一個個人項目,我對XNA和C#仍然很感興趣(我在Visual Basic和C++方面有一些經驗)。這個項目只是在我開始真正的遊戲之前測試代碼和算法。XNA 4.0查找房間算法問題

我遇到的問題是,我想在地圖上產生一個球體,但是我不想讓球體產生在另一個球體或球員之上,因爲我有一個球體非常基本的碰撞檢測系統。

這個問題具體是查找房間返回一些奇怪的矩形,即使它應該能夠在原點找到空間。有時候它也會在另一個之上產生球體。如果我將玩家移動到球體中,那麼會導致崩潰。

這裏是哪裏出了問題應該在於 -

 if (currentKeyState.IsKeyDown(Keys.Enter) && newBallDelay == 0) 
     { 
      Npcs newBall = new Npcs(); 
      //find room 
      Rectangle rect; 
      if (findRoom(newBall, ref rect)) 
      { 
       newBall.postion = new Vector2(rect.X, rect.Y); 
       characters.Add(newBall); //adds to a list of Npcs which is drawn in a foreach loop 
       newBallDelay = 1; //prevents from adding too many spheres at once 
      } 
     } 

這就要求

bool findRoom(Npcs newObject, ref Rectangle rectObject) 
    { 
     Rectangle player = new Rectangle((int)spritelocation.X, (int)spritelocation.Y, (int)sprite.Bounds.Width/4, (int)sprite.Bounds.Height/4); 
     Rectangle check; 
     for (int i = 0; i < characters.Count; i++) 
     { 
      check = new Rectangle((int)characters[i].postion.X, (int)characters[i].postion.Y, (int)characters[i].size.X, (int)characters[i].size.Y); 
      for (int j = 0; j < 50; j++) 
      { 
       rectObject = new Rectangle(i * (int)newObject.size.X * 2, j * (int)newObject.size.Y * 2, (int)newObject.size.X, (int)newObject.size.Y); //size.X and size.Y are the height and width of the object, this creates rectangular grid to check through. 
       if (!rectObject.Intersects(player) && !rectObject.Intersects(check)) 
        return (true); 
      } 
     } 

     return (false); 
    } 

我懷疑它的相關,但對於newballdelay,我有這個在更新

 if (newBallDelay > 0) 
     { 
      newBallDelay++; 
      if (newBallDelay == 50) 
       newBallDelay = 0; 
     } 

感謝花時間看看。再次,我是新來的網站,我想我應該認爲自己在編碼方面是新的,所以任何提示或建議,將不勝感激。

編輯:固定內循環。正在檢查和增加我而不是j。不過同樣的問題。

編輯2:FindRoom算法似乎返回兩個位置之一,無論現場是否有東西。

編輯3:發現輕微問題精靈的長方形的高度和寬度必須除以4才能正確檢測精靈。

這裏是我的全部代碼,如果它有助於(抱歉,如果它的混亂和不符合正確的約定,我還在學習)

public class Game1 : Microsoft.Xna.Framework.Game 
{ 
    GraphicsDeviceManager graphics; 
    SpriteBatch spriteBatch; 

    Texture2D sprite; 
    Texture2D background; 
    Texture2D sphere; 

    bool walking = false; 
    int walkSpeed = 2; 
    int newBallDelay = 0; 
    //bool jump = false; 

    int runSpeed = 5; 
    int frame = 0; 
    Random rand = new Random(); 

    int walkdir = 3; //0 = down, 1 = left, 2 = right, 3 = up 
    Vector2 spritelocation = new Vector2(0,0); 

    int imageH = 0; 
    int imageW = 0; 
    float elapsed = 0; 

    private const int Frames = 4; 
    private float frameSpeed = 0.15f; 

    List<Npcs> characters = new List<Npcs>(); 
    Npcs ball = new Npcs(); 
    Npcs ball2 = new Npcs(); 
    Camera2d cam = new Camera2d(); 

    private SpriteBatch batch; 
    SpriteFont Font1; 
    Vector2 FontPos; 

    public Game1() 
    { 

     graphics = new GraphicsDeviceManager(this); 
     Content.RootDirectory = "Content"; 
    } 

    protected override void Initialize() 
    { 
     // TODO: Add your initialization logic here 
     IsMouseVisible = true; 
     Window.AllowUserResizing = true; 
     base.Initialize(); 
    } 

    protected override void LoadContent() 
    { 
     // Create a new SpriteBatch, which can be used to draw textures. 
     ball.size = (new Vector2(50, 50)); 
     ball.postion = (new Vector2(50, 50)); 
     characters.Add(ball); 

     ball2.size = (new Vector2(50, 50)); 
     ball2.postion = (new Vector2(160, 80)); 
     characters.Add(ball2); 
     spriteBatch = new SpriteBatch(GraphicsDevice); 
     sprite = Content.Load<Texture2D>("sprite\\scaled"); 
     background = Content.Load<Texture2D>("sprite\\grass"); 
     sphere = Content.Load<Texture2D>("sprite\\ball"); 
     imageW = sprite.Bounds.Width; 
     imageH = sprite.Bounds.Height; 
     cam.Pos = new Vector2(350, 50); 
     //cam.Rotation = 0.5f; 
     // cam.Zoom = 2.0f // Example of Zoom in 
     // cam.Zoom = 0.5f // Example of Zoom out 

     spriteBatch = new SpriteBatch(GraphicsDevice); 
     Font1 = Content.Load<SpriteFont>("LucidaConsole"); 

     batch = new SpriteBatch(this.graphics.GraphicsDevice); 

     FontPos = new Vector2(graphics.GraphicsDevice.Viewport.Width - 90, 20); 
    } 

    protected override void UnloadContent() 
    { 
     // TODO: Unload any non ContentManager content here 
    } 

    protected override void Update(GameTime gameTime) 
    { 
     // Allows the game to exit 
     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
      this.Exit(); 
     getInput(); 
     // TODO: Add your update logic here 

     elapsed += (float)gameTime.ElapsedGameTime.TotalSeconds; 

     //Delay for ball 
     if (newBallDelay > 0) 
     { 
      newBallDelay++; 
      if (newBallDelay == 50) 
       newBallDelay = 0; 
     } 

     checkCollsion(); 

     base.Update(gameTime); 
    } 

    protected override void Draw(GameTime gameTime) 
    { 
     graphics.PreferredBackBufferWidth = 1366; 
     graphics.PreferredBackBufferHeight = 728; 
     graphics.GraphicsDevice.Clear(Color.CornflowerBlue); 

     // TODO: Add your drawing code here 
     //// if using XNA 4.0 
     spriteBatch.Begin(SpriteSortMode.BackToFront,BlendState.AlphaBlend,null,null,null,null, cam.get_transformation(null)); 

     //spriteBatch.Draw(background, new Vector2(-2000,-2000), new Rectangle(0,0,4000,4000), Color.White); 

     for (int i = 0; i < characters.Count(); i++) 
     { 
      spriteBatch.Draw(sphere, characters[i].postion, new Rectangle(0, 0, (int)Math.Round(characters[i].size.X), (int)Math.Round(characters[i].size.Y)), Color.White); 
     } 

     elapsed += (int)gameTime.ElapsedGameTime.TotalSeconds; 
     while (elapsed > frameSpeed && walking) 
     { 
      frame++; 
      elapsed = 0; 
      frame = frame % Frames; 
     } 

     if (!walking) 
      spriteBatch.Draw(sprite, spritelocation, new Rectangle(0, walkdir * (imageH/4), (imageW/4), (imageH/4)), Color.White); 
     else 
      spriteBatch.Draw(sprite, spritelocation, new Rectangle(frame * (imageW/4), walkdir * (imageH/4), (imageW/4), (imageH/4)), Color.White); 

     spriteBatch.End(); 

     base.Draw(gameTime); 

    } 


    protected void getInput() //Recieves keyboard input 
    { 
    KeyboardState currentKeyState = Keyboard.GetState(); 
     if (currentKeyState.IsKeyDown(Keys.Up)) 
     { 
      walkdir = 3; 
      walking = true; 
      if ((currentKeyState.IsKeyDown(Keys.LeftShift))) 
      { 
       frameSpeed = 0.05f; 
       spritelocation.Y -= runSpeed; 
       cam.Move(new Vector2(0, -runSpeed)); 
      } 
      else 
      { 
       frameSpeed = 0.15f; 
       spritelocation.Y -= walkSpeed; 
       cam.Move(new Vector2(0, -walkSpeed)); 
      } 
     } 
     else if (currentKeyState.IsKeyDown(Keys.Down)) 
     { 
      walkdir = 0; 
      walking = true; 
      if ((currentKeyState.IsKeyDown(Keys.LeftShift))) 
      { 
       frameSpeed = 0.05f; 
       spritelocation.Y += runSpeed; 
       cam.Move(new Vector2(0, runSpeed)); 
      } 
      else 
      { 
       frameSpeed = 0.15f; 
       spritelocation.Y += walkSpeed; 
       cam.Move(new Vector2(0, walkSpeed)); 
      } 
     } 
     else if (currentKeyState.IsKeyDown(Keys.Right)) 
     { 
      walkdir = 2; 
      walking = true; 
      if ((currentKeyState.IsKeyDown(Keys.LeftShift))) 
      { 
       frameSpeed = 0.05f; 
       spritelocation.X += runSpeed; 
       cam.Move(new Vector2(runSpeed, 0)); 
      } 
      else 
      { 
       frameSpeed = 0.15f; 
       spritelocation.X += walkSpeed; 
       cam.Move(new Vector2(walkSpeed, 0)); 
      } 
     } 
     else if (currentKeyState.IsKeyDown(Keys.Left)) 
     { 
      walkdir = 1; 
      walking = true; 
      if ((currentKeyState.IsKeyDown(Keys.LeftShift))) 
      { 
       frameSpeed = 0.05f; 
       spritelocation.X -= runSpeed; 
       cam.Move(new Vector2(-runSpeed, 0)); 
      } 
      else 
      { 
       frameSpeed = 0.15f; 
       spritelocation.X -= walkSpeed; 
       cam.Move(new Vector2(-walkSpeed, 0)); 
      } 
     } 
     else 
     { 
      walking = false; 
      frameSpeed = 1f; 
     } 

     if (currentKeyState.IsKeyDown(Keys.Enter) && newBallDelay == 0) 
     { 
      Npcs newBall = new Npcs(); 
      //find room 
      Rectangle rect = new Rectangle(0,0,(int)newBall.size.X,(int)newBall.size.Y); 
      if (findRoom(newBall, ref rect)) 
      { 
       newBall.postion = new Vector2(rect.X, rect.Y); 
       characters.Add(newBall); 
       newBallDelay = 1; 
      } 
     } //if enter key is hit 
    } //get input 


bool findRoom(Npcs newObject, ref Rectangle rectObject) 
{ 
    Rectangle player = new Rectangle((int)spritelocation.X, (int)spritelocation.Y,  (int)sprite.Bounds.Width/4, (int)sprite.Bounds.Height/4); 
    Rectangle check; 
    for (int i = 0; i < characters.Count; i++) 
    { 
     check = new Rectangle((int)characters[i].postion.X, (int)characters[i].postion.Y, (int)characters[i].size.X, (int)characters[i].size.Y); 
     for (int j = 0; j < 50; j++) 
     { 
      rectObject = new Rectangle(i * (int)newObject.size.X * 2, j * (int)newObject.size.Y * 2, (int)newObject.size.X, (int)newObject.size.Y); //size.X and size.Y are the height and width of the object, this creates rectangular grid to check through. 
      if (!rectObject.Intersects(player) && !rectObject.Intersects(check)) 
       return (true); 
     } 
    } 

    return (false); 
} 


    void checkCollsion(Npcs character, int index) 
    { 
     Rectangle char1 = new Rectangle((int)character.postion.X, (int)character.postion.Y, (int)character.size.X, (int)character.size.Y); 
     Rectangle char2 = new Rectangle(); 
     for (int i = 0; i < characters.Count(); i++) 
     { 
      if (i != index) 
      { 
       char2 = new Rectangle((int)characters[i].postion.X, (int)characters[i].postion.Y, (int)characters[i].size.X, (int)characters[i].size.Y); 
       if (char1.Intersects(char2)) 
       { 
        characters[i].hit(walkdir, (int)character.speed); 
        checkCollsion(characters[i], i); 
       } 
      } 
     } 
     character.speed = 0.0f; 
    } 

    void checkCollsion() 
    { 
     Rectangle char1 = new Rectangle((int)spritelocation.X, (int)spritelocation.Y, (int)sprite.Bounds.Width/4 - 10, (int)sprite.Bounds.Height/4 - 15); 
     Rectangle char2 = new Rectangle(); 
     for (int i = 0; i < characters.Count(); i++) 
     { 
       char2 = new Rectangle((int)characters[i].postion.X, (int)characters[i].postion.Y, (int)characters[i].size.X, (int)characters[i].size.Y); 
       if (char1.Intersects(char2)) 
       { 
        characters[i].hit(walkdir, runSpeed); 

        checkCollsion(characters[i], i); 
       } 

     } 
    } 
} 

回答

3

我沒有看到任何可能存在的錯誤了,但我不知道上下文。

我想跟着將調試一步一步,或許記錄的重要數據到一個文件,所以你可以很快看到一些奇怪的行爲,最好的辦法......

+0

這只是矩形開始和檢查位置的X,Y部分,應該不會引起問題。 – Denora 2012-04-05 22:14:47

+0

你內在的循環正在初始化int j = 0,但使用i++。這不會超過characters數組大小嗎? – kailoon 2012-04-05 22:25:16

+0

我相信湯姆的評論可能仍然是問題。 – kailoon 2012-04-05 23:08:33

0

你內部的循環初始化int j = 0,但使用i++。這不會超過characters數組大小嗎?這可能是問題。

+0

哎呦,愚蠢的錯誤。同樣的問題,雖然當我修好了.. – Denora 2012-04-05 22:41:25

0

好吧,我將自己的碰撞代碼從頭開始改造爲一個關於渲染findRoom毫無意義的工作。我也使用隨機變量來確定球體的重生點。感謝你幫助每個人。我很感激。