简体   繁体   中英

Not sure how to fix this StackOverflow Exception was Unhandled error

First time posting here and I know I'll probably get flak for my coding, but I'm a Year 12 student and teaching myself this language for my Software Major, I only just started understanding classes today so I tried to re-do my game with this in-mind, game is far from done. sorry for long post of code but I really can't figure out whats wrong, in the game1.cs is just player.LoadContent(Content), player.Update(gameTime) and player.Draw(spriteBatch), with player being the Object for the Player_Main class.

namespace HonourInBlood
{
public class Player_Main //This class deals with updating all other classes
{
    public Player_Sprite psprite = new Player_Sprite();
    public Player_Movement pmove = new Player_Movement();
    public Player_Stats pstats = new Player_Stats();
    public Player_Abilities pabilities = new Player_Abilities();
    public Player_Controls pcontrols = new Player_Controls();

    public Player_Main()
    {

    }
    public void Update(GameTime gameTime)
    {
        psprite.Update(gameTime);
        pmove.Update(gameTime);
        pstats.Update(gameTime);
        pabilities.Update(gameTime);
    }
    public void LoadContent(ContentManager Content)
    {
        psprite.LoadContent(Content);
    }
    public void Draw(SpriteBatch spriteBatch)
    {
        psprite.Draw(spriteBatch);
    }
}

public class Player_Sprite //This class deals with drawing the players sprite and animations
{
    public Rectangle player;
    public Texture2D playerAttack, playerWalk; //PLAYER TEXTURES
    public Player_Main pmain = new Player_Main();

    public Player_Sprite()
    {

    }
    public void Update(GameTime gameTime)
    {

    }
    public void LoadContent(ContentManager Content)
    {
        player = new Rectangle(0, 0, 64, 64);
        playerAttack = Content.Load<Texture2D>("player_attack_large");
        playerWalk = Content.Load<Texture2D>("player_move_large");
    }
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(playerWalk, pmain.pmove.position, new Rectangle(0, 0, 64, 64), Color.White);
    }
}

public class Player_Movement //This class deals with all movement relating to the player ie sprinting 
{

    public Vector2 position, velocity, velocity_base, sprint;
    public Player_Main pmain = new Player_Main();
    Game1 gamecore = new Game1();

    public Player_Movement()
    {

    }
    public void Update(GameTime gameTime)
    {
        KeyboardState KS = Keyboard.GetState();
        //Player movement using arrow keys
        if (KS.IsKeyDown(Keys.Up))
            position.Y -= velocity.Y;
        if (KS.IsKeyDown(Keys.Down))
            position.Y += velocity.Y;
        if (KS.IsKeyDown(Keys.Right))
            position.X += velocity.X;
        if (KS.IsKeyDown(Keys.Left))
            position.X -= velocity.X;

        //Making edge of screen stop player movement to prevent going off-screen
        if (position.X < 0)
            position.X = 0;
        if (position.Y < 0)
            position.Y = 0;
        if (position.X + pmain.psprite.player.Width > gamecore.GraphicsDevice.Viewport.Width)
            position.X = gamecore.GraphicsDevice.Viewport.Width - pmain.psprite.player.Width;
        if (position.Y + pmain.psprite.player.Height > gamecore.GraphicsDevice.Viewport.Height)
            position.Y = gamecore.GraphicsDevice.Viewport.Height - pmain.psprite.player.Height;
        //


        //SPRINTING
        if (KS.IsKeyDown(pmain.pcontrols.sprintKey))
        {
            if (KS.IsKeyDown(Keys.Up) || KS.IsKeyDown(Keys.Down) || KS.IsKeyDown(Keys.Right) || KS.IsKeyDown(Keys.Left)) //You're only sprinting when you're moving, right?
            {
                if (pmain.pstats.currentStamina > 0) //Only when you have stamina can you run
                {
                    velocity.X += sprint.X;
                    velocity.Y += sprint.X;
                    pmain.pstats.currentStamina -= pmain.pstats.stamina; //Decreases stamina
                }
            }
        }
        //
        //
        //SPRINTING

        if (pmain.pstats.currentStamina > 0)
        {
            if (velocity.X > velocity_base.X) //When current velocity becomes greater than base velocity check whether space bar is released
            {
                if (KS.IsKeyUp(pmain.pcontrols.sprintKey))
                    velocity.X = velocity_base.X; //If it is, set current velocity back to base
            }

            if (velocity.Y > velocity_base.Y)
            {
                if (KS.IsKeyUp(pmain.pcontrols.sprintKey))
                    velocity.Y = velocity_base.Y;
            }

            if (velocity.X > velocity_base.X + sprint.X)
                velocity.X = velocity_base.X + sprint.X;

            if (velocity.Y > velocity_base.Y + sprint.Y)
                velocity.Y = velocity_base.Y + sprint.Y;
            //
        }

        if (pmain.pstats.currentStamina <= 0) //When you run out of stamina, set speed to normal
        {
            velocity.X = velocity_base.X;
            velocity.Y = velocity_base.Y;
            pmain.pstats.currentStamina = 0;
        }

    }
    public void LoadContent(ContentManager Content)
    {
        position = new Vector2(400, 300);
        velocity = new Vector2(4, 4); //Current velocity
        velocity_base = new Vector2(4, 4); //Base velocity
        sprint = new Vector2(6, 6); //Added velocity when sprinting
    }
    public void Draw(SpriteBatch spriteBatch)
    {

    }
}

public class Player_Stats //This class deals with all stats of the player
{

    public double stamina, maxStamina, currentStamina, staminaRate, staminaDisplay;
    public double mana, maxMana, currentMana, manaRate, manaDisplay;

    public Player_Stats()
    {

        //STAMINA
        maxStamina = 100f;
        stamina = 1f;
        currentStamina = maxStamina;
        staminaRate = 0.1f;
        staminaDisplay = maxStamina;
        //
        //MANA
        maxMana = 200f;
        mana = 0.5f;
        currentMana = maxMana;
        manaRate = 0.5f;
        manaDisplay = maxMana;
        //
    }
    public void Update(GameTime gameTime)
    {
        currentStamina += staminaRate; //Stamina regen
        currentMana += manaRate; //TEST STATEMENT

        if (currentStamina > maxStamina) //Cant have more stamina than the max now, can we?
            currentStamina = maxStamina;
        if (currentMana > maxMana)
            currentMana = maxMana;
    }
    public void LoadContent(ContentManager Content)
    {

    }
    public void Draw(SpriteBatch spriteBatch)
    {

    }
}

public class Player_Abilities //This class deals with all abilities the player has
{
    public double spellCD1, spell1Cost, spellDisplay1;
    Player_Controls pcontrols = new Player_Controls();
    Player_Stats pstats = new Player_Stats();
    Player_Movement pmove = new Player_Movement();
    HUD HUDmain = new HUD();

    public Player_Abilities()
    {
        spellCD1 = 150;
        spell1Cost = 120;
    }
    public void Update(GameTime gameTime)
    {
        KeyboardState KS = Keyboard.GetState();

        //MANA AND SPELL STUFF///////////////////////////////
        if (KS.IsKeyDown(pcontrols.spellKey1))
        {
            if (pstats.currentMana >= spell1Cost)
            {
                if (spellCD1 <= 0)
                {
                    if (KS.IsKeyDown(Keys.Up))
                        pmove.position.Y -= 300;
                    if (KS.IsKeyDown(Keys.Down))
                        pmove.position.Y += 300;
                    if (KS.IsKeyDown(Keys.Right))
                        pmove.position.X += 300;
                    if (KS.IsKeyDown(Keys.Left))
                        pmove.position.X -= 300;

                    pstats.mana = spell1Cost;
                    pstats.currentMana -= pstats.mana;
                    spellCD1 = 150;
                }
            }

        }

        spellCD1--;
        spellDisplay1 = spellCD1 / 60;
        spellDisplay1 = Math.Round(spellDisplay1, 1);

        if (spellCD1 <= 0)
            spellCD1 = 0;

    }
    public void LoadContent(ContentManager Content)
    {

    }
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.DrawString(HUDmain.HUDFont, "Ability: Cooldown", new Vector2(20, 40), Color.White);
        spriteBatch.DrawString(HUDmain.HUDFont, "Teleport: " + spellDisplay1 + "s", new Vector2(20, 60), Color.White);
    }
}

public class Player_Controls //This class deals with the controls
{
    public Keys sprintKey, spellKey1;

    public Player_Controls()
    {
        sprintKey = Keys.LeftShift;
        spellKey1 = Keys.D1;

    }
    public void Update(GameTime gameTime)
    {

    }
    public void LoadContent(ContentManager Content)
    {

    }
}
}

Here is the call stack:

HonourInBlood.exe!HonourInBlood.Player_Sprite.Player_Sprite() Line 45 + 0xffffffe6 bytes C# HonourInBlood.exe!HonourInBlood.Player_Main.Player_Main() Line 14 + 0x15 bytes C# HonourInBlood.exe!HonourInBlood.Player_Sprite.Player_Sprite() Line 45 + 0x15 bytes C# HonourInBlood.exe!HonourInBlood.Player_Main.Player_Main() Line 14 + 0x15 bytes C# HonourInBlood.exe!HonourInBlood.Player_Sprite.Player_Sprite() Line 45 + 0x15 bytes C# HonourInBlood.exe!HonourInBlood.Player_Main.Player_Main() Line 14 + 0x15 bytes C# HonourInBlood.exe!HonourInBlood.Player_Sprite.Player_Sprite() Line 45 + 0x15 bytes C#

It repeats in this fashion until:

The maximum number of stack frames supported by Visual Studio has been exceeded.    

Here is the new question(for Chris Ballard):

After changing the code in all the places I had too, I'm just more confused than before, I have a HUD.cs file that references the Player_Stats class in the Player.cs file for variables but I can't because:

'HonourInBlood.Player_Stats' does not contain a constructor that takes 0 arguments

If you skim through the code looking at the beginning of each class you can see there is just a web of references that now cause problems since I changed it to the way you showed me.

OK - I see the problem.

Everytime you create a Player_Main - it has a field which creates a new Player_Sprite

but

Player_Sprite itself has a field which creates another new Player_Main ,

this in turn creates a new Player_Sprite etc, forever (or at least until your stack overflows)

EDIT

I'm guessing you want ONE Player_Main which retains a reference to Player_Sprite and that Player_Sprite needs to remember the Player_Main which created it (not create a new one). Something like:

public class Player_Main 
{
    public Player_Sprite psprite;

    public Player_Main()
    {
        psprite = new Player_Sprite(this);
    }
}

public class Player_Sprite 
{
    public Player_Main _pmain;

    public Player_Sprite(Player_Main pmain)
    {
        _pmain = pmain;
    }
}

Regarding the second question. I suspect you have updated Player_Stats class to take in Player_Main in the constructor.

For Player_Stats this isn't necessary. That is because none of the code in Player_Stats needs to access methods or properties of Player_Main . The same is true of Player_Controls , Player_Abilities and Player_Movements

It is only needed in Player_Sprite because the Draw method accesses pmain.pmove.position

As I write this, it comes to mind that perhaps a better implementation would simply to be to pass the position into the Draw method, so:

public class Player_Sprite //This class deals with drawing the players sprite and animations
{
    public Rectangle player;
    public Texture2D playerAttack, playerWalk; //PLAYER TEXTURES

    public Player_Sprite()
    {

    }

    // .. methods removed for brevity

    public void Draw(SpriteBatch spriteBatch, Player_Movement pmove)
    {
        spriteBatch.Draw(playerWalk, pmove.position, new Rectangle(0, 0, 64, 64), Color.White);
    }
}

So therefore Player_Main.Draw becomes:

public void Draw(SpriteBatch spriteBatch)
{
    psprite.Draw(spriteBatch, pmove);
}

And you no longer have to pass this into the Player_Sprite constructor.

EDIT Revised Player_Movement

public class Player_Movement //This class deals with all movement relating to the player ie sprinting 
{
    public Vector2 position, velocity, velocity_base, sprint;
    public Player_Main pmain = null;
    Game1 gamecore = new Game1();

    public Player_Movement(Player_Main pmain)
    {
        this.pmain = pmain;
    }
    public void Update(GameTime gameTime)
    {
        KeyboardState KS = Keyboard.GetState();
        //Player movement using arrow keys
        if (KS.IsKeyDown(Keys.Up))
            position.Y -= velocity.Y;
        if (KS.IsKeyDown(Keys.Down))
            position.Y += velocity.Y;
        if (KS.IsKeyDown(Keys.Right))
            position.X += velocity.X;
        if (KS.IsKeyDown(Keys.Left))
            position.X -= velocity.X;

        //Making edge of screen stop player movement to prevent going off-screen
        if (position.X < 0)
            position.X = 0;
        if (position.Y < 0)
            position.Y = 0;
        if (position.X + pmain.psprite.player.Width > gamecore.GraphicsDevice.Viewport.Width)
            position.X = gamecore.GraphicsDevice.Viewport.Width - pmain.psprite.player.Width;
        if (position.Y + pmain.psprite.player.Height > gamecore.GraphicsDevice.Viewport.Height)
            position.Y = gamecore.GraphicsDevice.Viewport.Height - pmain.psprite.player.Height;
        //


        //SPRINTING
        if (KS.IsKeyDown(pmain.pcontrols.sprintKey))
        {
            if (KS.IsKeyDown(Keys.Up) || KS.IsKeyDown(Keys.Down) || KS.IsKeyDown(Keys.Right) || KS.IsKeyDown(Keys.Left)) //You're only sprinting when you're moving, right?
            {
                if (pmain.pstats.currentStamina > 0) //Only when you have stamina can you run
                {
                    velocity.X += sprint.X;
                    velocity.Y += sprint.X;
                    pmain.pstats.currentStamina -= pmain.pstats.stamina; //Decreases stamina
                }
            }
        }
        //
        //
        //SPRINTING

        if (pmain.pstats.currentStamina > 0)
        {
            if (velocity.X > velocity_base.X) //When current velocity becomes greater than base velocity check whether space bar is released
            {
                if (KS.IsKeyUp(pmain.pcontrols.sprintKey))
                    velocity.X = velocity_base.X; //If it is, set current velocity back to base
            }

            if (velocity.Y > velocity_base.Y)
            {
                if (KS.IsKeyUp(pmain.pcontrols.sprintKey))
                    velocity.Y = velocity_base.Y;
            }

            if (velocity.X > velocity_base.X + sprint.X)
                velocity.X = velocity_base.X + sprint.X;

            if (velocity.Y > velocity_base.Y + sprint.Y)
                velocity.Y = velocity_base.Y + sprint.Y;
            //
        }

        if (pmain.pstats.currentStamina <= 0) //When you run out of stamina, set speed to normal
        {
            velocity.X = velocity_base.X;
            velocity.Y = velocity_base.Y;
            pmain.pstats.currentStamina = 0;
        }

    }
    public void LoadContent(ContentManager Content)
    {
        position = new Vector2(400, 300);
        velocity = new Vector2(4, 4); //Current velocity
        velocity_base = new Vector2(4, 4); //Base velocity
        sprint = new Vector2(6, 6); //Added velocity when sprinting
    }
    public void Draw(SpriteBatch spriteBatch)
    {

    }
}

And in your Player_Main constructor, do this:

public class Player_Main //This class deals with updating all other classes
{
    public Player_Sprite psprite = new Player_Sprite();
    public Player_Movement pmove = null;
    public Player_Stats pstats = new Player_Stats();
    public Player_Abilities pabilities = new Player_Abilities();
    public Player_Controls pcontrols = new Player_Controls();

    public Player_Main()
    {
         pmove = new Player_Movement(this);
    }

    // ... rest removed for brevity
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM