5

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);
            }
        }
    }
}
Jamal
  • 763
  • 7
  • 22
  • 32
Detinator10
  • 123
  • 1
  • 10

2 Answers2

7

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.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
2

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.

Loren Pechtel
  • 8,945
  • 3
  • 33
  • 45
  • So I'm not stopping the path generation? I will check that tomorrow. I've still got a lot to learn...(I'm a beginner programmer) – Detinator10 Oct 13 '13 at 03:57
  • @user2770939 In some case (but not all cases) you're not stopping path generation. That's why it doesn't always blow. I think the odds are very high there's some case that can leak through the termination condition. – Loren Pechtel Oct 13 '13 at 04:00
  • Ok I will check tomorrow when I'm back on my computer. Is it possible that the reason my enemy is taking the exact same path every time could be linked to the out of memory exception? By the way I'm user2770939 I changed my name thing – Detinator10 Oct 13 '13 at 04:06
  • I tried to fix up some things and now my game takes forever to debug. I waited about 2 minutes and it didnt debug – Detinator10 Oct 14 '13 at 00:37
  • @Detinator10 Then you're not debugging it the right way. Your code is running wild somehow, apparently it's not gobbling up tons of memory in the process anymore. Step through it, see where you are going. – Loren Pechtel Oct 14 '13 at 03:35
  • Could it be something wrong with my initialization cause i guess if i drew it in the corner then it might repeat that loop over and over – Detinator10 Oct 15 '13 at 01:48
  • I just realized im not setting any coords for it to be drawn at so it will be drawn at 0,0 – Detinator10 Oct 15 '13 at 01:51
  • I don't think that fixed it and now it keeps on building it won't even show the splash screen now. Any ideas where the problem may be @LorenPechtel ? – Detinator10 Oct 28 '13 at 22:37
  • @Detinator10 (Sorry for the delay, we were out of the country) Your post is still dated 10/13, where's the new version to look at? – Loren Pechtel Nov 16 '13 at 02:38
  • I re-posted the question and am currently working on the suggested solution. First of all I am moving my path code to the update function and refining my random path code. I will post the answer when done. – Detinator10 Nov 18 '13 at 04:22