vdegenne
vdegenne

Reputation: 13270

Create an instance of a DrawableGameComponent later in the game in XNA

I've been struggling my mind for long now.

I have my main Game Class called Game1 and a DrawableGameComponent-inherited ShowUp Class called myShowUp

The usual way would be to add the component myShowUp to the Game1 Object so it be part of the game (directly in the Initialize method of Game1) as follow :

class Game1 : Microsoft.Xna.Framework.Game
{
    ShowUp myShowUp;

    ...

    protected override Initialize ()
    {
        this.myShowUp = new ShowUp(this);
        this.Components.Add(this.myShowUp);
    }
    ...
}

This method does work and myShowUp is shown and becomes an independant object in the game.

What I would like is to instanciate and add the object in the game-objects-list later (e.g. after a click in the window)

This is my try :

class Game1 : Microsoft.Xna.Framework.Game
{
    MouseState myMouseState;

    ...

    ...

    protected override void Update(GameTime gameTime)
    {
        myMouseState = Mouse.GetState();

        if (myMouseState.LeftButton == ButtonState.Pressed)
        {
            this.myShowUp = new ShowUp(this);   // Nothing
            this.Components.Add(this.myShowUp); // Happens..
        }

        base.Update(gameTime);
    }

    ...
}

I found a method so far, i just keep the first syntax (i.e. keep the instanciation into the Initialize method) and define a boolean into the ShowUp Class named activated. If activated is true I execute the instructions to show it up or else nothing. And in my Update method of my Game object i call activate() of myShowUp if my left button is pressed to change the activated variable to true.

This method works but I'm not quite satisfied, i wish it would have been as simple as to just instanciate the objects in my Game Object anywhere in the code to make them part of it. Is there a way to make that way be ?

Something like :

class Game1 : Microsoft.Xna.Framework.Game
{
    ShowUp myShowUp;
    MouseState myMouseState;

    ...

    ...

    protected override Initialize ()
    {
        this.Components.Add(this.myShowUp);
    }

    ...

    protected override void Update(GameTime gameTime)
    {
        myMouseState = Mouse.GetState();

        if (myMouseState.LeftButton == ButtonState.Pressed)
        {
            this.myShowUp = new ShowUp(this);
        }

        base.Update(gameTime);
    }

    ...
}

This would be nice.

Upvotes: 0

Views: 974

Answers (1)

Andrew Russell
Andrew Russell

Reputation: 27215

There is one minor bug in your code. You will be creating several instances of your component - one per update. This is because you don't check either that the previous mouse state is Released or that myShowUp is null, before creating the component. Here's some tested working code (that checks both conditions):

MouseState lastMouseState;

protected override void Update(GameTime gameTime)
{
    MouseState mouseState = Mouse.GetState();

    if(mouseState.LeftButton == ButtonState.Pressed
            && lastMouseState.LeftButton == ButtonState.Released
            && myShowUp == null)
    {
        Components.Add(myShowUp = new ShowUp(this));
    }

    lastMouseState = mouseState;

    base.Update(gameTime);
}

Of course - I'm not sure why this bug would cause ShowUp to not appear at all - as you are creating multiple instances of it - you'd expect to be able to see it. There may be a bug in your ShowUp component.

For what it's worth, here is the code that I tested with:

class ShowUp : DrawableGameComponent
{
    public ShowUp(Game game) : base(game) { }

    Texture2D texture;
    SpriteBatch sb;

    protected override void LoadContent()
    {
        sb = new SpriteBatch(GraphicsDevice);
        texture = this.Game.Content.Load<Texture2D>("test");
        base.LoadContent();
    }

    public override void Draw(GameTime gameTime)
    {
        sb.Begin();
        sb.Draw(texture, new Vector2(100), Color.White);
        sb.End();
        base.Draw(gameTime);
    }
}

Note that, adding a component after Game.Initialize is run will cause that component's Initialize and LoadContent methods to run as soon as it is added to the Components collection.

Note that, for your future reference, DrawableGameComponent already comes with Enabled and Visible properties - allowing you to skip over Update and Draw respectively for that instance.

Upvotes: 1

Related Questions