4
votes

I'm trying to encapsulate my game objects by having them extend Mircosoft.Xna.Framework.GameCompenent, then merely constructing them and managing them in the Update() method of Game1. I have my Game1 class, a Player class, and an Animation class. Animations are supposed manage the Texture2D changes of an object, in this instance Player.

My problem is that even though I have successfully extended everything, have no syntax errors, no exceptions thrown, and have checked and re-checked what little code I have written, the override functions are not called and I end up with a black screen.

Game1.cs: (note that the only two lines changed are for the Player declaration)

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    Player player;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        player = new Player(this);

        base.Initialize();
    }

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
    }

    protected override void UnloadContent()
    {

    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);
        base.Draw(gameTime);
    }
}

Player.cs:

class Player : Microsoft.Xna.Framework.DrawableGameComponent
{
    Rectangle bounds;
    Texture2D t;
    Animation[] animations = new Animation[4];
    String path = @"..\..\..\Content\player.png";

    #region Animation Constants
    private const int WALK_RIGHT = 0;
    #endregion

    SpriteBatch spriteBatch;

    public Player(Game game) : base(game)
    {
        //should only ever be one player, all value defaults set in Initialize()
    }

    public Texture2D T
    {
        get { return t; }
    }

    public Rectangle Bounds
    {
        get { return bounds; }
    }

    public override void Initialize()
    {
        base.Initialize();

        bounds = new Rectangle(0, 0,
            System.Drawing.Image.FromFile(path).Width,
            System.Drawing.Image.FromFile(path).Height
        );

        t = Game.Content.Load<Texture2D>("player");
        animations[0] = new Animation(this.Game, "player", "walking", 3);
    }

    protected override void LoadContent()
    {
        base.LoadContent();

        spriteBatch = new SpriteBatch(this.Game.GraphicsDevice);
    }

    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);

        KeyboardState k = Keyboard.GetState();

        if (k.IsKeyDown(Keys.Right)) //walk right
        {
            bounds.X += 3;
            if (animations[WALK_RIGHT].Playing)
            {
                t = animations[WALK_RIGHT].getTexture();
            }
            else
            {
                animations[WALK_RIGHT].Play();
            }
        }
        else if (animations[WALK_RIGHT].Playing)
            animations[WALK_RIGHT].Stop();

    }

    public override void Draw(GameTime gameTime)
    {
        base.Draw(gameTime);

        spriteBatch.Begin();
        spriteBatch.Draw(t, bounds, Color.White);
        spriteBatch.End();
    }
}

Animation.cs:

class Animation : Microsoft.Xna.Framework.GameComponent
{
    Game game;
    String name; //name of default sprite; standing, unmoving, neutral, etc. The rest of the animation sprite names should derive from this
    String keyword;
    int frameCount;
    int delay; //frames between texture change


    String[] paths; //texture pathnames generated by the MakePaths() function
    int currentFrame = 0;
    int delayCount = 0;
    bool playing = false;

    public Animation(Game associatedGame, String nameVal, String keywordVal, int frameCountVal)
        : base(associatedGame)
    {
        name = nameVal;
        keyword = keywordVal;
        frameCount = frameCountVal;
        paths = MakePaths();
        delay = 10;
    }

    public Animation(Game associatedGame, String nameVal, String keywordVal, int frameCountVal, int delayVal)
        : base(associatedGame)
    {
        name = nameVal;
        keyword = keywordVal;
        frameCount = frameCountVal;
        paths = MakePaths();
        delay = delayVal;
    }

    private String[] MakePaths()
    {
        //format: name_keyword_anim[i]
        //format example: player_walking_anim1

        String[] temp = new String[frameCount];
        for (int i = 0; i < frameCount; i++)
        {
            temp[i] = name + "_" + keyword + "_" + "anim" + i.ToString();
        }

        return temp;
    }

    public Texture2D getTexture()
    {
        return Game.Content.Load<Texture2D>(paths[currentFrame]);
    }

    public void Play()
    {
        playing = true;
    }

    public void Stop()
    {
        currentFrame = 0;
        delayCount = 0;
        playing = false;
    }

    public bool Playing
    {
        get { return playing; }
    }

    public override void Update(GameTime gameTime)
    {
        if (playing)
        {
            if (delayCount == delay)
            {
                delayCount = 0;

                if ((currentFrame + 1) == frameCount) currentFrame = 0;
                else currentFrame++;
            }
            else delayCount++;
        }
        base.Update(gameTime);
    }

    public override string ToString()
    {
        return "params: " + name + "," + keyword + "," + frameCount.ToString() + "\nUsing paths: " + paths;
    }
}

The only LoadContent, Initialize, Update, and Draw methods that are called are the ones in Game1. What really baffles me is that I was able to use this technique before without issue. These functions would be called naturally by the Xna update process.

So... why is this?

1
Too much code, too laborious to read. Provide a small, isolated example of your problem.Timwi

1 Answers

14
votes

You need to add game Components to the Components collection to have them called automatically

protected override void Initialize()
{
    player = new Player(this);
    Components.Add(player);

    base.Initialize();
}

See http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.components.aspx