Pyroglyph
Pyroglyph

Reputation: 179

XNA Sprite doesn't seem to be updating?

I've looked through some other questions and haven't found my answer so I'm asking you lovely people as you have helped me before :)

I have a main class (RPG.cs) and a player class (Player.cs) and I want the Player class to be as self-contained as possible (because I don't want a huuuge main class) but here is my problem.

Problem

My Player sprite draws fine but when I want it to move, it won't update! At the moment I'm attempting to make it act like a cursor to test movement but eventually I'll have it bound to WASD or the arrow keys. So I want my sprite to follow my mouse at the moment but it just stays at 50, 50 (it's preset starting position) Have I missed something obvious? I'm new to XNA and I've spent half an hour on this problem!

RPG.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TestGame
{
    public class RPG : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D PlayerTex;
        Rectangle playerPos = new Rectangle(
            Convert.ToInt32(Player.Pos.X), 
            Convert.ToInt32(Player.Pos.Y), 32, 32);
        public RPG()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }
        protected override void Initialize() { base.Initialize(); }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            PlayerTex = Content.Load<Texture2D>("testChar");
        }
        protected override void UnloadContent() { }
        protected override void Update(GameTime gameTime)
        {
            if 
            (
                GamePad.GetState(PlayerIndex.One)
                .Buttons.Back == ButtonState.Pressed
            )
                this.Exit();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            spriteBatch.Begin();
            spriteBatch.Draw(PlayerTex, playerPos, Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

Player.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TestGame
{
    /// This is a game component that implements IUpdateable.
    public class Player : Microsoft.Xna.Framework.GameComponent
    {
        public static Vector2 Pos = new Vector2(50, 50);
        MouseState ms = Mouse.GetState();
        public Player(Game game) : base(game) { }
        /// Allows the game component to perform 
        /// any initialization it needs to before 
        /// starting to run. This is where it can 
        /// query for any required services and load content.
        public override void Initialize() { base.Initialize(); }
        /// Allows the game component to update itself.
        public override void Update(GameTime gameTime)
        {
            Pos.X = ms.X;
            Pos.Y = ms.Y;
            base.Update(gameTime);
        }
    }
}

Hope you can help! :)

Upvotes: 0

Views: 243

Answers (2)

user1183961
user1183961

Reputation: 11

The key solution which Nico included is just that you using the original rectangle coordinates you made when you draw:

Rectangle playerPos = new Rectangle(
             Convert.ToInt32(Player.Pos.X), 
             Convert.ToInt32(Player.Pos.Y), 32, 32);

Here you make the rectangle using the players CURRENT starting time position. Then you ALWAYS draw based on this rectangle you made ages ago and never updated:

        spriteBatch.Draw(PlayerTex, playerPos, Color.White);

The right way as Nico mentioned is just to change the draw to this:

 playerPos = new Rectangle(
             Convert.ToInt32(Player.Pos.X), 
             Convert.ToInt32(Player.Pos.Y), 32, 32);

    spriteBatch.Draw(PlayerTex, playerPos, Color.White);

Now you will be drawing at a new place every time. There are better ways to do this (like what nico did) but here is the core idea.

Upvotes: 0

Nico Schertler
Nico Schertler

Reputation: 32597

As mentioned in the comment, I am not going to solve every problem. But the main errors.

Let the player be responsible for its position, not the game. Furthermore, I would make the player responsible for drawing itself, but that goes a bit too far for this answer.

The following code should at least work.

public class Player : Microsoft.Xna.Framework.GameComponent
{
    public Vector2 Pos { get; set; }

    public Player(Game game) : base(game)
    {
        this.Pos = new Vector2(50, 50);
    }

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

    public override void Update(GameTime gameTime)
    {
        var ms = Mouse.GetState();
        Pos.X = ms.X;
        Pos.Y = ms.Y;
        base.Update(gameTime);
    }
}

Then use the player in your game:

public class RPG : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D PlayerTex;

    Player player;

    public RPG()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        IsMouseVisible = true;
        player = new Player(this);
        Components.Add(player);
    }
    protected override void Initialize() { base.Initialize(); }
    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        PlayerTex = Content.Load<Texture2D>("testChar");
    }
    protected override void UnloadContent() { }
    protected override void Update(GameTime gameTime)
    {
        if 
        (
            GamePad.GetState(PlayerIndex.One)
            .Buttons.Back == ButtonState.Pressed
        )
            this.Exit();
        base.Update(gameTime);
    }
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.White);
        spriteBatch.Begin();
        spriteBatch.Draw(PlayerTex, player.Pos, Color.White);
        spriteBatch.End();
        base.Draw(gameTime);
    }
}

I have removed the texture's size. Don't know if you really need this. If so, you can let Player expose a Rectangle, not just a Vector2.

Upvotes: 2

Related Questions