XNA 4.0 Finding Room Algorithm issue

Go To StackoverFlow.com

3

I'm working on a personal project and I'm still very to XNA and C# (I have some experience in visual basic and C++). This project is just testing code and algorithms before I start my real game.

The issue I'm having is, I'm trying to spawn a sphere on the map when I hit enter, however I don't want the sphere's to spawn on top of one another or the player because I have a very basic collision detection system.

The issue specifically is the find room returns some strange rectangles even when it should just be able to find room at the origin. Also sometimes it'll just spawn the sphere on top of another one. Which will then cause a crash if I move the player into the spheres.

Here's where the problem should lie -

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

which calls

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

I doubt it's relevant but for the newballdelay, I have this in update

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

Thanks for taking the time to look. Again I'm new to the site and I guess I should consider myself new at coding, so any tips or advice would be appreciated.

Edit: Fixed inner for loop. Was checking and incrementing i rather then j. Still same issue though.

Edit 2: The FindRoom algorithm seems to return one of two positions regardless if there is something in the spot or not.

Edit 3: Found slight issue the Height and width of the rectangle of the sprite has to be divided by 4 for proper detection of sprite.

Here's my whole code if it helps(sorry if it's messy and doesn't conform to proper conventions, I'm still learning)

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

        }
    }
}
2012-04-05 22:06
by Denora


3

I don't see any possible mistakes anymore, but I don't know the context.

I think the best approach to follow would be debugging step by step, perhaps logging the important numbers to a file so you can quickly see something that behaves odd...

2012-04-05 22:10
by Tom Wijsman
That's just for the X,Y portion of where the rectangle starts and where it checks, that shouldn't cause a problem - Denora 2012-04-05 22:14
You're inner for loop is initializing int j = 0 but using i++. Won't this go over the characters array size - kailoon 2012-04-05 22:25
I believe Tom's comment might be the issue still - kailoon 2012-04-05 23:08
@Denora: The left and right should be X and the top and bottom should be Y, but you have three of them X and only one of them Y. Hence your rectangle is incorrect.. - Tom Wijsman 2012-04-05 23:41
Those are merely the coordinates for where to check, it doesn't matter if there the same. One is multiplied by i and the other by j, making sort of a grid to go through to check. I use size.X (width of the object) as a default. For the sake of argument I changed it to size.Y and the problem remains the same - Denora 2012-04-05 23:48


0

You're inner for loop is initializing int j = 0 but using i++. Won't this go over the characters array size? This might be the issue.

2012-04-05 22:26
by kailoon
Whoops, stupid mistake. Same problem though when I fixed it. - Denora 2012-04-05 22:41


0

Okay, I revamped my collision code from ground up as a work around rendering findRoom pointless. I also used random variables to determine the spawn point for the sphere. Thanks for you help everyone. I appreciate it.

2012-04-07 23:53
by Denora
Ads