Search code examples
c#classmonogamestress

C# - how do I get the code to work in different classes?


I'm making a new game (in Visual Studio, using MonoGame template), and I figured that classes make everything tidier and easier to find/work with - my one problem is that I have no idea how to link one class to another.

Lemme go more into depth - I'm just working with moving the player in the direction corresponding to WASD keys. I've got code that works fine when in the normal Game1 class, but I want it to be in a class specifically for keyboard input.

Note - I haven't touched any of the "using" stuff at the top of the classes.

here's my code:

Keyboard Input class:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace rpg_game
{
   internal class KeyboardInput
   {
      public int player_X;
      public int player_Y;

      KeyboardState keyboardState = Keyboard.GetState();

      public void Update(GameTime gameTime)
      {
         if (keyboardState.IsKeyDown(Keys.W)) { player_Y -=1; }
         if (keyboardState.IsKeyDown(Keys.A)) { player_X -= 1; }
         if (keyboardState.IsKeyDown(Keys.S)) { player_Y += 1; }
         if (keyboardState.IsKeyDown(Keys.D)) { player_X += 1; }
      }
   }
}

just to clarify, if theres /* ... */ within the classes, it just means that I've not added or taken anything from them - those classes are untouched :)

Game1 class:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace rpg_game
{
   public class Game1 : Game
   {
      private GraphicsDeviceManager _graphics;
      private SpriteBatch _spriteBatch;
      
      private Texture2D player;

      private int player_X = 100;
      private int player_Y = 38;

      KeyboardInput input = new KeyboardInput();

      public Game1() { /* ... */ }

      protected override void Initialize() { /* ... */ }

      protected override void LoadContent()
      {
         player = Content.Load<Texture2D>("player");
      }

      protected override void Update(GameTime gameTime)
      {
         input.player_X = player_X;
         input.player_Y = player_Y;

         input.Update(gameTime);
      }

      protected override void Draw(GameTime gameTime)
      {
         GraphicsDevice.Clear(Color.CornflowerBlue);
         
         _spriteBatch.Begin();
         _spriteBatch.Draw(player, new Rectangle(player_X, player_Y, 25, 25), Color.White);
         _spriteBatch.End();

         base.Draw(gameTime);
      }
   }
}

I've provided pretty much everything in each class, but in the Game1 class, the problem (I think), is in the Update.

My question, in short, is how can I get it so that the keyboard input is in another class, yet works the same way as when it was all in the Game1 class?

With it now in a different place, the player doesn't move when I run the code. What do I need to do in order to use classes and still get the code to do what it's supposed to do??


Solution

  • In your keyboard class, you have defined a new variable of player_X and player_Y.
    Those are different from the player_X and player_Y you used in Game1, so it doesn't make a connection between them.

    Adding a parameter to the KeyboardInput.Update() could work, but those will only update if you use ref, like this:

    public void Update(GameTime gameTime, ref int Player_Y, ref int Player_X) 
    

    Additionally, you can also update variables if you bring a class as a parameter, you could still use ref as an easy way out, but I think that'll be messy with many ref parameters.

    I think you're on the right path to use classes, but I'll also recommend to make a Player class as well. and place the player_X and player_Y there. From there, you either add the Player class to the parameter of KeyboardInput.Update(), or you could place the Update() code in the Player class instead. (the latter would be my preference)

    Example of a Player class:

    namespace rpg_game
    {
       public class Player
       {
          public int X;
          public int Y;
    
          private Texture2D playerSprite;
    
          KeyboardState keyboardState = null; //can also work fine with just "KeyboardState keyboardState;", but I prefer defining them with '= null'
          
          public void Load(Texture2D sprite)
          {
              player.playerSprite = sprite;
          }
    
          public void Update()
          {
             keyboardState = Keyboard.GetState()
             if (keyboardState.IsKeyDown(Keys.W)) { Y -=1; }
             if (keyboardState.IsKeyDown(Keys.A)) { X -= 1; }
             if (keyboardState.IsKeyDown(Keys.S)) { Y += 1; }
             if (keyboardState.IsKeyDown(Keys.D)) { X += 1; }
          }
          
          //While at it, you could also add a draw Method, and call the player.Draw in the Game1.cs
          public void Draw(SpriteBatch spriteBatch)
          {
             spriteBatch.Draw(playerSprite, new Rectangle(X, Y, 25, 25), Color.White);
          }
       }
    }
    

    Then, in the Game1.cs, you could define the Player class there:

    //right underneath the KeyboardInput input = new KeyboardInput(); You'll need to remove the player_X, player_Y and Texture2D variables afterwards
    Player player = new Player() {playerSprite = player, X = 100, Y = 38}
    
    //In the LoadContent(), underneath the 'player = Content.Load<Texture2D>("player");'
    player.load(player); //might want to rename the Texture2D 'player' to something else to work.
    
    //In the Update()
    player.Update(); //gameTime parameter is only necessary if you're going to use it.
    
    //In the Draw(), should still be between the spritebatch.Begin and spritebatch.End
    player.Draw(_spriteBatch); //replaces the _spriteBatch.Draw(player /*...*/ ); 
    

    (You'll need to remove the X and Y variables in the Game1 class, as those will no longer be relevant)

    If you still wish to use the KeyboardInput.Update instead of the Player.Update, then you could remove the Player.Update() method, and add the parameter to KeyboardInput.Update (The player_x/player_Y needs to be changed as well):

      public void Update(GameTime gameTime, Player player)
      {
         if (keyboardState.IsKeyDown(Keys.W)) { player.Y -=1; }
         if (keyboardState.IsKeyDown(Keys.A)) { player.X -= 1; }
         if (keyboardState.IsKeyDown(Keys.S)) { player.Y += 1; }
         if (keyboardState.IsKeyDown(Keys.D)) { player.X += 1; }
      }