Update a string based on key presses - c#

I hope this isn't a stupid question but I cannot figure this out.
I have a barebones game class:
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
String inputHolder;
public Game1()
: base()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
inputHolder = "Enter your keys: ";
}
protected override void Initialize()
{
base.Initialize();
InputManager.stringToUpdate = inputHolder;
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
{
Exit();
}
base.Update(gameTime);
InputManager.update(Keyboard.GetState());
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
Console.WriteLine(inputHolder);
}
}
I also have an InputManager class:
static class InputManager
{
public static string stringToUpdate;
public static void update(KeyboardState kbState)
{
if (stringToUpdate != null)
{
foreach (Keys k in kbState.GetPressedKeys())
{
stringToUpdate += k.ToString();
}
}
}
}
However no matter what keys I press the original string inputHolder is not affected even though strings are treated as reference types in C#.
I have tried changing
InputManager.stringToUpdate = inputHolder;
to
InputManager.stringToUpdate = ref inputHolder;
and nothing happens.
What am I missing here?

As has already been said, strings are immutable. Wrapping the inputHolder string in a class will give you the desired effect:
public class InputHolder
{
public string Input { get; set; }
}
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
InputHolder inputHolder = new InputHolder();
public Game1()
: base()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
inputHolder.Input = "Enter your keys: ";
}
protected override void Initialize()
{
base.Initialize();
InputManager.inputHolderToUpdate = inputHolder;
}
// etc
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
Console.WriteLine(inputHolder.Input);
}
}
static class InputManager
{
public static InputHolder inputHolderToUpdate;
public static void update(KeyboardState kbState)
{
if (inputHolderToUpdate != null)
{
foreach (Keys k in kbState.GetPressedKeys())
{
inputHolderToUpdate.Input = inputHolderToUpdate.Input + k.ToString();
}
}
}
}

Related

MonoGame project quits unexpectedly when run

I'm new to MonoGame and C#, so I might be doing something stupid, but I can't figure out what is wrong with my project for the life of me.
SharpEngine/SharpContext.cs:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SharpEngine.Utils;
namespace SharpEngine
{
public class SharpContext : Game
{
public Logger logger;
public GraphicsDeviceManager graphics;
public SpriteBatch spriteBatch;
public SharpContext()
{
logger = new Logger();
graphics = new GraphicsDeviceManager(this);
}
protected override void Initialize()
{
logger.Log("Initializing...", true);
Window.Title = "Sharp Engine";
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
graphics.ApplyChanges();
Content.RootDirectory = "Content";
base.Initialize();
logger.Log("Initialized.", true);
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
spriteBatch.End();
}
}
}
SharpGame/Main.cs:
using System;
using SharpEngine;
namespace SharpGame
{
class Game1 : SharpContext
{
public static Game1 game1;
public Game1() : base()
{
Program.game1 = this;
game1 = this;
}
}
class Program
{
public static Game1 game1;
[STAThread]
static void Main(string[] args)
{
using (Game1 game = new Game1())
{
game.logger.enableVerbose();
game.logger.Log("Starting up...", true);
game.logger.Log("Calling SharpContext.Run()...", true);
game.Run();
}
}
}
}
When the game is run, the only output is:
[ 9:56:13 AM Verbose Log ]: Starting up...
[ 9:56:13 AM Verbose Log ]: Calling SharpContext.Run()...
and then it immediately exits.
I'm clueless as to why this is happening.
I'm on Manjaro Linux.
If any more info is needed to help, just ask, and I'll provide it.
Update:
I was using MonoGame.Framework.Portable, which is just headers. I feel dumb.

C# ArgumentNullException was unhandled (SpriteBatch.Draw)

I am actually a new student in XNA, finding this library very interesting, but I still lack some knowledge to go further as I felt on a issue I can't fix on my own :(
The spriteBatch.Draw() method says my texture is null, however I have loaded it in a Resources.cs class and passed the texture in MainMenu.cs, so I don't really know where the problem resides, if anybody could help me about that I would be very thankful !
Resources.cs
class Resources
{
public static Texture2D pixel;
public static Texture2D startButton, loadButton, quitButton;
public static SpriteFont consoleFont;
public static void LoadContent(ContentManager Content)
{
pixel = Content.Load<Texture2D>("Pixel");
consoleFont = Content.Load<SpriteFont>("Console");
// UI Ressources :
startButton = Content.Load<Texture2D>("UI/StartButton");
loadButton = Content.Load<Texture2D>("UI/LoadButton");
quitButton = Content.Load<Texture2D>("UI/QuitButton");
}
}
MainMenu.cs
class MainMenu
{
// Fields
List<Button> buttons = new List<Button>();
// Constructors
public MainMenu()
{
this.buttons.Add(new Button(new Vector2(480, 132), 256, 48, Resources.startButton));
this.buttons.Add(new Button(new Vector2(480, 212), 256, 48, Resources.loadButton));
this.buttons.Add(new Button(new Vector2(480, 292), 256, 48, Resources.quitButton));
}
// Methods
// Update
public void Update()
{
}
// Draw
public void Draw(SpriteBatch spriteBatch)
{
foreach (Button button in buttons)
{
button.Draw(spriteBatch);
}
}
}
Button.cs
class Button : UIElement
{
int width, height;
Texture2D texture;
public Button()
{
}
public Button(Vector2 b_position, int b_width, int b_height, Texture2D b_texture)
{
this.position = b_position;
this.width = b_width;
this.height = b_height;
this.texture = b_texture;
}
public void Update()
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Simple realy
You just have to know the calling order of functions of Game1. First, Game1 constructor is called. That's where you've put mainMenu = new MainMenu();. After that go Initialize, Load and so on. You have to move mainMenu = new MainMenu(); from Game1 constructor to Load function, after the Resources.LoadContent(Content);, so the resources can be loaded before they are used in MainMenu. Your Game1.cs code should look like this:
public class GameMain : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
MainMenu mainMenu;
public GameMain()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.IsMouseVisible = true;
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
Resources.LoadContent(Content);
mainMenu = new MainMenu();
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
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.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
mainMenu.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
While I do not see your Game class my first assumption is that your never calling the public static void LoadContent(ContentManager Content) method inside your Resources class. Since this function is instantiating your textures perhaps this isn't being called.
Thank you for your reply !
Indeed I forgot to include the Game class, is this the right way to call the resources ?
public class GameMain : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
MainMenu mainMenu;
public GameMain()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.IsMouseVisible = true;
mainMenu = new MainMenu();
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
Resources.LoadContent(Content);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
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.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
mainMenu.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}

C# XNA Add a GameComponent from within a GameComponent

public class Menu : DrawableGameComponent
{
ContentManager Content;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Audio MenuMusic;
public Menu(Game game) : base(game)
{
spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
graphics = Game.Services.GetService(typeof(GraphicsDeviceManager)) as GraphicsDeviceManager;
Content = game.Content;
Content.RootDirectory = #"Content\Menu\";
*MenuMusic = new Audio(game);* // Instantiate the new DrawableGameComponent
Game.Components.Add(this);
MenuMusic.PauseTune = false;
}
public override void Initialize()
{
Menustate = MenuState.LoadContent;
base.Initialize();
}
protected override void LoadContent()
{
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
}
public class Audio : DrawableGameComponent
{
public bool PauseTune
{
get { return PauseTune; }
set { PauseTune = value; }
}
SoundEffect Tune = null;
SoundEffectInstance SFXInstance;
public Audio(Game game) : base(game)
{
*game.Components.Add(this)*;// This is the problem. It adds an entirely new Game object. :(
}
public override void Initialize()
{
PauseTune = true;
base.Initialize();
}
protected override void LoadContent()
{
switch (Game1.Gamestate)
{
case GameState.Menu:
string AudioPath = #"Audio\";
Tune = Game.Content.Load<SoundEffect>(AudioPath + "Tune");
break;
case GameState.InitialiseGame:
break;
case GameState.PlayGame:
break;
default:
break;
}
if (Tune != null) SFXInstance = Tune.CreateInstance();
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
public override void Update(GameTime gameTime)
{
if (Tune != null)
{
if (PauseTune)
{
if (SFXInstance.State == SoundState.Playing)
SFXInstance.Pause();
}
else
{
if (SFXInstance.State != SoundState.Playing)
SFXInstance.Play();
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
}
The probelem comes when I use the Menu to add a new Audio class instance.
The Audio constructor attempts to add the new GameCompent but fails.
What it actually does is create an entirely new Game instance, which then goes on to instantiate a new Menu that attempts to add a new Audio class instance..... Until I eventually get a - would you beleive? - stackoverflow error.
What am I doing wrong? / How can I add one component from within another?
DOH! Some days I should never turn on my computer :)
Or better yet - after a long, tiring day do NOT mess with mycode.
A self-referencing PauseTune property.

C# XNA - Background music logic

So I'm working with the XNA game states sample. I have 2 different songs that play and loop in the game states. That means:
mainMenu.mp3 goes to the mainMenu game state
backgroundMusic.mp3 goes to the Playing game state
So this works. But I also have the Escape key logic, which returns you from any state to the mainMenu state (when Esc is pressed). The song from Playing stops and the song from mainMenu begins playing. But if I click the Start Game button which moves me to Playing the background music is not being played. Where could be the problem?
Here's my code:
// Main Menu game state
if (Game1.g_CurrentGameState == Game1.g_GameStates.g_MainMenu && !m_SongStart)
{
MediaPlayer.Play(m_MainMenuTheme);
m_SongStart = true; // bool
}
if (Game1.g_CurrentGameState != Game1.g_GameStates.g_MainMenu)
{
MediaPlayer.Stop();
m_SongStart = false; // bool
}
// Playing game state
if (Game1.g_CurrentGameState == Game1.g_GameStates.g_GamePlaying && !m_SongStart)
{
MediaPlayer.Play(m_GamePlayingMainTheme);
m_SongStart = true;
}
if (Game1.g_CurrentGameState != Game1.g_GameStates.g_GamePlaying)
{
MediaPlayer.Stop();
m_SongStart = false;
}
The following code will play a song according current game state:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace WindowsGame1
{
public class Game1 : Game
{
private GameState _gameState;
private GraphicsDeviceManager _graphicsDeviceManager;
private KeyboardState _keyboardState;
private Song _song1;
private Song _song2;
public Game1() {
_graphicsDeviceManager = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent() {
_song1 = Content.Load<Song>("song1");
_song2 = Content.Load<Song>("song2");
}
protected override void UnloadContent() {
if (_song1 != null) _song1.Dispose();
if (_song2 != null) _song2.Dispose();
}
protected override void Update(GameTime gameTime) {
GameState gameState = _gameState;
var keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.A) && _keyboardState.IsKeyUp(Keys.A)) {
gameState = GameState.Menu;
}
else if (keyboardState.IsKeyDown(Keys.B) && _keyboardState.IsKeyUp(Keys.B)) {
gameState = GameState.InGame;
}
else if (keyboardState.IsKeyDown(Keys.C) && _keyboardState.IsKeyUp(Keys.C)) {
gameState = GameState.Undefined;
}
_keyboardState = keyboardState;
if (gameState != _gameState) {
switch (gameState) {
case GameState.Undefined:
MediaPlayer.Stop();
break;
case GameState.Menu:
MediaPlayer.Stop();
MediaPlayer.Play(_song1);
break;
case GameState.InGame:
MediaPlayer.Stop();
MediaPlayer.Play(_song2);
break;
default:
throw new ArgumentOutOfRangeException();
}
_gameState = gameState;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
internal enum GameState
{
Undefined,
Menu,
InGame
}
}
Why not just write a wrapper class to wrap both a song and game state member in it and play the song when the current game state is equal to that one? An oop version of #Aybe's answer. Credit to him!
Here is what I've come up with. Should be easy to use and manage. Pretty simple.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Collections.Generic;
namespace WindowsGame1
{
public class GameStateManager
{
private static List<GameState> GameStates = new List<GameState>();
private static GameState CurrentGameState = null;
public static void AddState(GameState gameState)
{
GameStates.Add(gameState);
}
public static GameState GetState(string name)
{
return GameStates.Find(gameState => gameState.Name == name);
}
public static void SwitchStates(GameState gameState)
{
if (CurrentGameState != null)
{
if (MediaPlayer.State == MediaState.Playing)
MediaPlayer.Stop();
}
CurrentGameState = gameState;
if (CurrentGameState != null)
MediaPlayer.Play(CurrentGameState.Song);
}
public static void SwitchStates(string gameState)
{
SwitchStates(GetState(gameState));
}
public static void Dispose()
{
foreach (var gameState in GameStates)
{
gameState.Song.Dispose();
}
GameStates.Clear();
}
}
public class GameState
{
public Song Song;
public string Name;
public GameState(string name, Song song)
{
Name = name;
Song = song;
}
}
public class Game1 : Game
{
private GraphicsDeviceManager _graphicsDeviceManager;
private KeyboardState _keyboardState;
public Game1()
{
_graphicsDeviceManager = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
GameStateManager.AddState(new GameState("InGame", Content.Load<Song>("song1")));
GameStateManager.AddState(new GameState("Menu", Content.Load<Song>("song2")));
}
protected override void UnloadContent()
{
GameStateManager.Dispose();
}
protected override void Update(GameTime gameTime)
{
var keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.A) && _keyboardState.IsKeyUp(Keys.A))
{
GameStateManager.SwitchStates("Menu");
}
else if (keyboardState.IsKeyDown(Keys.B) && _keyboardState.IsKeyUp(Keys.B))
{
GameStateManager.SwitchStates("InGame");
}
else if (keyboardState.IsKeyDown(Keys.C) && _keyboardState.IsKeyUp(Keys.C))
{
GameStateManager.SwitchStates("Undefined");
}
_keyboardState = keyboardState;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}

I am getting a null error

I am getting an error message in this line:
player = new Player(this.Content.Load<Texture2D>("Player"),
actor.position,
this.spriteBatch,
enemyManager);
which tells me the actor object is null. How can I overcome this situation?
The exact error is:
Field Shmup.MyGame.actor is never assigned to, and will always have its default value null.
Here is my code:
class MyGame // [edit:] added based on below constructor
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Player player;
EnemyManager enemyManager;
Actor actor;
public MyGame()
{
graphics = new GraphicsDeviceManager(this);
IsMouseVisible = true;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
startTheGame();
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
this.player.Update(gameTime);
this.enemyManager.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Maroon);
this.spriteBatch.Begin();
this.player.Draw(gameTime);
this.enemyManager.Draw(gameTime);
this.spriteBatch.End();
base.Draw(gameTime);
}
void startTheGame()
{
enemyManager = new EnemyManager(this.Content.Load<Texture2D>("Enemy"), new Vector2(16), this.spriteBatch);
player = new Player(this.Content.Load<Texture2D>("Player"),actor.position, this.spriteBatch, enemyManager);
enemyManager.StartTheGame(10);
}
}
public class Actor
{
public Texture2D texture;
public Vector2 origin;
public SpriteBatch spriteBatch;
public Vector2 position;
public Rectangle boundingRectangle;
public Vector2 Position
{
get { return position; }
set
{
position = value;
boundingRectangle = new Rectangle((Int32)(position.X - origin.X), (Int32)(position.Y - origin.Y), texture.Width, texture.Height);
}
}
public Rectangle BoundingRectangle
{
get { return boundingRectangle; }
}
public Actor(Texture2D texture, Vector2 origin, SpriteBatch spriteBatch, Vector2 initialPosition)
{
this.texture = texture;
this.origin = origin;
this.spriteBatch = spriteBatch;
this.position = initialPosition;
boundingRectangle = new Rectangle((Int32)(initialPosition.X - origin.X), (Int32)(initialPosition.Y - origin.Y), texture.Width, texture.Height);
}
public virtual void Update(GameTime gameTime)
{ }
public virtual void Draw(GameTime gameTime)
{
this.spriteBatch.Draw(texture, position - origin, Color.White);
}
}
Like error says, you need to create an instance of Actor class.
In game constructor or in startTheGame Method(before creating an instance of Player class) you should create an instance of Actor class, something like :
this.actor = new Actor(variables...);

Categories