Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't my random path code work?

Tags:

c#

xna

monogame

I have some code for an XNA tower defense. I have it set so that the enemy (bug) goes on a random path down from a certain side of the grid until it hits the house(destination) or the row on the side of the house.

I debugged this project and the bug gets drawn and starts moving in a diagonal (kind of) path. It's the same every time (it's not random). I don't no what I'm doing wrong. It also sometimes gives an OutOfMemory exception at the spot in the code where I specified it. I dunno if I explained it very well so feel free to ask questions. The grid is surrounded by a forest which is not part of the grid so that's what the forest means.

public class Bug : Sprite
{
    public float startHealth;
    protected float currentHealth;
    protected bool alive = true;
    protected float speed = 0.5f;
    protected int bountyGiven;
    public int startplace;
    public bool at_house;
    public Queue<Vector2> path = new Queue<Vector2>();
    Random random = new Random();
    int x;
    int y;
    public int end_row;
    public int end_column;

    //Defines the space where the house is
    Vector2 house1 = new Vector2(10, 13) * 91;
    Vector2 house2 = new Vector2(10, 12) * 91;
    Vector2 house3 = new Vector2(10, 11) * 91;
    Vector2 house4 = new Vector2(10, 10) * 91;
    Vector2 house5 = new Vector2(11, 13) * 91;
    Vector2 house6 = new Vector2(11, 12) * 91;
    Vector2 house7 = new Vector2(11, 11) * 91;
    Vector2 house8 = new Vector2(11, 10) * 91;
    Vector2 house9 = new Vector2(12, 13) * 91;
    Vector2 house10 = new Vector2(12, 12) * 91;
    Vector2 house11 = new Vector2(12, 11) * 91;
    Vector2 house12 = new Vector2(12, 10) * 91;

    public float CurrentHealth
    {
        get { return currentHealth; }
        set { currentHealth = value; }
    }

    public bool IsDead
    {
        get { return currentHealth <= 0; }
    }

    public int BountyGiven
    {
        get { return bountyGiven; }
    }

    public float DistanceToDestination
    {
        get { return Vector2.Distance(position, path.Peek()); }
    }

    public Bug(Texture2D texture, Vector2 position, float health,
        int bountyGiven, float speed)
        : base(texture, position)
    {

        this.startHealth = health;
        this.currentHealth = startHealth;
        this.bountyGiven = bountyGiven;
        this.speed = speed;
        int startq = random.Next(1, 4);
        set_start(ref startq);
        //end_row and end_column detremine the row or column at which the bug turns toward the house.
        end_row = random.Next(10, 13);
        end_column = random.Next(10, 12);
        set_path(ref startq);
    }

    public void set_start(ref int startq)
    {
        //here i am initializing the "0,0" point for the bug so it's 0,0 is't in the forest
        //startx and starty should equal the number of tiles between the forest edge and the grass edge
        //startx is the x co-ord in the start place and starty is the y co-ord in the start
        int startx = 4;
        int starty = 4;
        //This generates a random number which determines the start for the bug
        //Between 0 and 22 because that is the number of edge tiles on one side
        int start = random.Next(0, 22);
        //start determines what place on a side the buggie spawns at
        //startq is a random int (1-4)(defined in constructor) which determnes which side the bug spawns at

        if (startq == 1)
        {
            starty += 22;
            startx += start;
        }

        if (startq == 2)
        {
            startx += 22;
            starty += start;
        }

        if (startq == 3)
        {
            startx += start;
        }

        if (startq == 4)
        {
            starty += start;
        }
        x = startx;
        y = starty;
        path.Enqueue(new Vector2(startx, starty) * 91);
    }

    public bool check_for_path_end(ref int startq, ref bool at_house)
    {
        bool path_ends;
        //checks if the bug has reached the house and if so signals using at_house
        if (path.Peek() == house1 || path.Peek() == house2 || path.Peek() == house3 || path.Peek() == house4
            || path.Peek() == house5 || path.Peek() == house6 || path.Peek() == house7 || path.Peek() == house8
            || path.Peek() == house9 || path.Peek() == house10 || path.Peek() == house11 || path.Peek() == house12)
        {
            at_house = true;
            return true;
        }
        //Should i add at_house = true to the else ifs? 
        else if (startq == 1 || startq == 3 && path.Peek().Y == end_row)
        {
            path.Enqueue(new Vector2(11, end_row) * 91);
            return true;
        }

        else if (startq == 2 || startq == 4 && path.Peek().X == end_column)
        {
            path.Enqueue(new Vector2(end_column, 11) * 91);
            path_ends = true;
        }

        else
        {
            path_ends = false;
        }
        return path_ends;
    }

    public void set_path(ref int startq)
    {
        bool path_ends;
        bool legal = true;
        int X = x;
        int Y = y;
        do
        {
            //determines which way the bug turns at it's different waypoints 1 = left, 2 = right, 3 = forward
            int turn = random.Next(1, 3);
            do
            {
                if (startq == 1)
                {
                    switch (turn)
                    {
                        case 1:
                            x += 1;
                            break;
                        case 2:
                            x -= 1;
                            break;
                        case 3:
                            y += 1;
                            break;
                    }
                }

                else if (startq == 2)
                    switch (turn)
                    {
                        case 1:
                            y -= 1;
                            break;
                        case 2:
                            y += 1;
                            break;
                        case 3:
                            x -= 1;
                            break;
                    }

                else if (startq == 3)
                {
                    switch (turn)
                    {
                        case 1:
                            x -= 1;
                            break;
                        case 2:
                            x += 1;
                            break;
                        case 3:
                            y += 1;
                            break;
                    }
                }

                else if (startq == 4)
                {
                    switch (turn)
                    {
                        case 1:
                            y += 1;
                            break;
                        case 2:
                            y -= 1;
                            break;
                        case 3:
                            x += 1;
                            break;
                    }
                }

                if (y > 3 && y < 28 && x > 3 && x < 28)
                {
                    //sets up a backup in case the bug goes off track
                    X = x;
                    Y = y;

Here is where the exception is:

                        //Right here is where it gives the out of memory exception 
                        path.Enqueue(new Vector2(x, y) * 91);
                        legal = true;
                    }

                    else
                    {
                        //restores x and y to backups X and Y
                        x = X;
                        y = Y;
                        //adds to turn and repeats without randomizing turn or adding waypoints
                        turn += 1;
                        legal = false;
                    }
                } while (legal == false);
                path_ends = check_for_path_end(ref startq, ref at_house);
            } while (path_ends == false);
        }

        public bool check_corners()
        {
            bool start_is_corner;
            if (x == 2 && y == 24 || x == 24 && y == 24 || x == 24 && y == 2 || x == 2 && y == 2)
            {
                start_is_corner = true;
                int X = x;
                int Y = y;
                if (x == 4 && y == 27)
                {
                    bool z = true;
                    for (int i = 0; i < 13; ++i)
                    {
                        if (z == true)
                        {
                            Y -= 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = false;
                        }
                        if (z == false)
                        {
                            X += 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = true;
                        }
                    }
                }
                if (x == 27 && y == 27)
                {
                    bool z = true;
                    for (int i = 0; i < 13; ++i)
                    {
                        if (z == true)
                        {
                            Y -= 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = false;
                        }
                        if (z == false)
                        {
                            X -= 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = true;
                        }
                    }
                }
                if (x == 27 && y == 4)
                {
                    bool z = true;
                    for (int i = 0; i < 13; ++i)
                    {
                        if (z == true)
                        {
                            Y += 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = false;
                        }
                        if (z == false)
                        {
                            X -= 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = true;
                        }
                    }
                }
                if (x == 4 && y == 4)
                {
                    bool z = true;
                    for (int i = 0; i < 13; ++i)
                    {
                        if (z == true)
                        {
                            Y += 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = false;
                        }
                        if (z == false)
                        {
                            X += 1;
                            path.Enqueue(new Vector2(X, Y) * 91);
                            z = true;
                        }
                    }
                }
            }
            else
            {
                start_is_corner = false;
            }
            return start_is_corner;
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            if (path.Count > 0)
            {
                if (DistanceToDestination < speed)
                {
                    position = path.Dequeue();
                }

                else
                {
                    Vector2 direction = path.Peek() - position;
                    direction.Normalize();

                    velocity = Vector2.Multiply(direction, speed);

                    position += velocity;
                }
            }
            else
                alive = false;

            if (currentHealth <= 0)
                alive = false;
        }

        public override void Draw(SpriteBatch spriteBatch)
        {
            if (alive)
            {
                float healthPercentage = (float)currentHealth / (float)startHealth;

                base.Draw(spriteBatch);
            }
        }
    }
}
like image 376
Detinator10 Avatar asked Oct 13 '13 02:10

Detinator10


2 Answers

This method is your constructor. This is where the problem comes from:

public Bug(Texture2D texture, Vector2 position, float health, int bountyGiven, float speed)
    : base(texture, position)
{

    this.startHealth = health;
    this.currentHealth = startHealth;
    this.bountyGiven = bountyGiven;
    this.speed = speed;
    int startq = random.Next(1, 4);
    set_start(ref startq);
    //end_row and end_column detremine the row or column at which the bug turns toward the house.
    end_row = random.Next(10, 13);
    end_column = random.Next(10, 12);
    set_path(ref startq); // <<<<<<<<<<< HERE!
}

What you're doing here, is that you're predetermining the bug's path at initialization. And you're storing the entire path in some Queue. And eventually the queue gets so large you run out of memory.

The solution is simple. Instead of initializing a Bug that knows every single step he's going to make towards home at birth, make a Bug that starts somewhere and, at each update, determines what the next step towards home is going to be. Don't queue anything.

Your mistake is that you're doing stuff in your constructor that belongs in your Update method. Get rid of your set_path method. A bug isn't brilliant enough to know the way home from the start. That's what's stalling your game. Use the Update method to calculate the next move instead of pulling it from a queue: you don't need that queue either.

It's like you're playing chess and before you even know what you opponent's first move is going to be, you're computing the entire game in your head. Your nose will bleed before the game even starts.

like image 121
Mathieu Guindon Avatar answered Oct 05 '22 11:10

Mathieu Guindon


I don't really have the time right now to puzzle out the whole thing but I can tell you what's happening with your out of memory error--it's running wild building an infinite path to somewhere because the termination condition didn't catch it.

like image 25
Loren Pechtel Avatar answered Oct 05 '22 09:10

Loren Pechtel