I am a relative beginner in XNA and am trying to create a screenManager for an C# XNA game. Everything in my code seems to work fine until I reach the LoadContent method in my MainMenu class which derives from Screen which is a custom standalone class. This is where I get my GraphicsDevice component not found ContentLoad exception.
This is on the the statement: texture = c.Load<Texture2D>("Textures/Start");
where c is a ContentManager.
This statement and the program works okay if I put it in the Update method of my class. However, I only want to load this texture once, not with each call to Update(GameTime). I think I must be calling load before some Content info is being initialized but I'm not sure what. There are some commented out statements in MainMenu.LoadContent that do pretty much the same thing and all produce the same error. I'm posting my entire code here. Hope it isn't flooding the forum.
Here's Game1.cs:
namespace RoomGame
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
public static GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
GameController gameController;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
gameController = new GameController(this,this.Content);
this.Components.Add(gameController);
}
}
}
GameController.cs:
namespace RoomGame
{
public class GameController : DrawableGameComponent
{
public Game game;
public ContentManager content;
public ScreenController screenController;
public MainMenu menu;
public GameController(Game game,ContentManager c)
: base(game)
{
this.game = game;
content = c;
screenController = new ScreenController(this);
menu = new MainMenu(this,this.content);
screenController.AddScreen(menu);
}
public override void Initialize()
{
base.Initialize();
screenController.Initialize();
}
protected override void LoadContent()
{
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
public override void Update(GameTime gameTime)
{
screenController.Update(gameTime);
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
screenController.Draw(gameTime);
}
}
}
screenController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace RoomGame
{
public class ScreenController
{
public List<Screen> screens = new List<Screen>();
GameController gameController;
SpriteBatch spriteBatch;
public ScreenController(GameController gc)
{
this.gameController = gc;
}
public void Initialize()
{
spriteBatch = new SpriteBatch(this.gameController.GraphicsDevice);
}
public void Update(GameTime gameTime)
{
foreach (Screen screen in screens)
{
if (screen.isUpdating)
screen.Update(gameTime);
}
}
public void Draw(GameTime gameTime)
{
foreach (Screen screen in screens)
{
if (screen.isDrawn)
{
spriteBatch.Begin();
screen.Draw(gameTime,spriteBatch);
spriteBatch.End();
}
}
}
public void AddScreen(Screen screen)
{
if (!screens.Contains(screen))
{
screen.LoadContent(this.gameController.game.Content);
screens.Add(screen);
//screen.Initialize();
}
}
}
}
Screen.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace RoomGame
{
public class Screen
{
public ScreenController screenController;
public bool isUpdating=true;
public bool isDrawn=true;
public GraphicsDeviceManager graphics;
/*public Screen(ScreenController sc)
{
this.screenController = sc;
this.isActive = true;
}*/
public virtual void Initialize()
{ }
public virtual void LoadContent(ContentManager c)
{ }
public virtual void Update(GameTime gameTime)
{ }
public virtual void Draw(GameTime gameTime,SpriteBatch sb)
{ }
}
}
MainMenu.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace RoomGame
{
public class MainMenu : Screen
{
GameController gameController;
Texture2D texture;
Vector2 position;
ContentManager content;
//public GraphicsDeviceManager graphics;
public MainMenu(GameController gc,ContentManager c)
{
this.gameController = gc;
this.content = c;
this.isUpdating = true;
this.isDrawn = true;
//this.graphics = this.gameController.game.graphics;
}
public override void LoadContent(ContentManager c)
{
texture = c.Load<Texture2D>("Textures/Start");
//texture = this.gameController.game.Content.Load<Texture2D>("Textures/Start");
//texture=this.gameController.content.Load<Texture2D>("Textures/Start");
//texture = this.gameController.Game.Content.Load<Texture2D>("Textures/Start");
}
public override void Update(GameTime gameTime)
{
//texture = this.gameController.content.Load<Texture2D>("Textures/Start");
position = new Vector2(100, 100);
}
public override void Draw(GameTime gameTime,SpriteBatch sb)
{
sb.Draw(texture, position, Color.White);
}
}
}
Thanks in advance....
EDIT
I found my error. I was calling ScreenController.Add before the LoadContent in GameController. I put it after the base.LoadContent in gameController and it works now. I hope this can help somebody but if anyone know a better way of approaching this please let me know.
You call MainMenu.LoadContent from the constructor of the ScreenController which in turn is called by the Game's constructor. LoadContent should be called at the appropriate time. So move the call to AddScreen to the LoadContent method of the GameController.
Related
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.
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'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! :)
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.
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.
I have been trying to create a collision for a "top down view" like game. I have made a player class and a block class, in my Game1 class I have checked for the collision, don't know if this is a right way, but it's only a test right now. So if I intersect them I don't know what to do next.
This is my Game1.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 Collision_Testing {
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Player player = new Player(100, 100);
Block block = new Block(500, 500);
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
block.LoadContent(Content);
player.LoadContent(Content);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
block.Update(gameTime);
player.Update(gameTime);
base.Update(gameTime);
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos.X -= player.speed;
player.playerPos.Y -= player.speed;
}
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
player.Draw(spriteBatch);
block.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
} }
This is my Player.cs
using System; using System.Collections.Generic; using System.Linq;
using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;
namespace Collision_Testing {
class Player
{
public Vector2 playerPos;
public Texture2D playerTex;
public int speed;
KeyboardState oldState;
public Rectangle boundingBox;
public Player(int positionX, int positionY)
{
playerPos.X = positionX;
playerPos.Y = positionY;
speed = 14;
}
public void LoadContent(ContentManager Content)
{
playerTex = Content.Load<Texture2D>("player");
boundingBox = new Rectangle((int)playerPos.X, (int)playerPos.Y, playerTex.Width, playerTex.Height);
}
public void Update(GameTime gameTime)
{
KeyboardState newState = Keyboard.GetState();
if(newState.IsKeyDown(Keys.Right))
{
playerPos.X += speed;
}
if (newState.IsKeyDown(Keys.Left))
{
playerPos.X -= speed;
}
if (newState.IsKeyDown(Keys.Up))
{
playerPos.Y -= speed;
}
if (newState.IsKeyDown(Keys.Down))
{
playerPos.Y += speed;
}
oldState = newState;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(playerTex, playerPos, Color.White);
}
} }
This is my Block.cs
using System; using System.Collections.Generic; using System.Linq;
using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;
namespace Collision_Testing {
class Block
{
public Vector2 blockPos;
public Texture2D blockTex;
public Rectangle boundingBox;
public Block(int blockX, int blockY)
{
blockPos.X = blockX;
blockPos.Y = blockY;
}
public void LoadContent(ContentManager Content)
{
blockTex = Content.Load<Texture2D>("wall");
boundingBox = new Rectangle((int)blockPos.X, (int)blockPos.Y, blockTex.Width, blockTex.Height);
}
public void Update(GameTime gameTime)
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(blockTex, blockPos, Color.White);
}
} }
I think I've done quite a good job for a beginner but don't know what to do next.
It looks to me like speed is a scalar. so when you intersect with the box,
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos.X -= player.speed;
player.playerPos.Y -= player.speed;
}
you're merely moving the player 14 units to the left, and 14 units up, regardless of where the player was.
It looks like you're intending to subtract the velocity. In order to do that, you first have to declare a velocity
public Vector2 playerVelocity;
make sure you initialize playerVelocity in your constructor.
and then you should modify the velocity instead of the position when measuring input
if(newState.IsKeyDown(Keys.Right))
{
playerVelocity.X = speed;
}
else if (newState.IsKeyDown(Keys.Left))
{
playerVelocity.X = -speed;
}
else
{
playerVelocity.X = 0;
}
...
playerPos += playerVelocity;
// i believe you can just add Vectors in XNA like this
// but if it makes you feel better you can do playerPos.X += playerVelocity.X
and then you can reverse your player's position when you collide
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos -= player.playerVelocity;
}
If your character doesn't stop moving I think you miss something like this:
if (newState.IsKeyUp(Keys.Up) && newState.IsKeyUp(Keys.Down) &&
newState.IsKeyUp(Keys.Left) && newState.IsKeyUp(Keys.Right))
{
playerVelocity = Vector2.Zero;
}
I can't figure out why this is the case. I'm creating a View class from Game class and then I'm trying to call a method from View in Game and send it the entire game object as a parameter. If I send single variables as a parameter then it work's no problem but I wanted to send the whole Game object so that only one thing would be passed.
Game class
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 Airfield
{
public class Game : Microsoft.Xna.Framework.Game
{
// Device Objects
GraphicsDevice device = null;
GraphicsDeviceManager graphics = null;
MouseState mouse;
// Game Objects
SpriteBatch spriteBatch;
Texture2D b = null;
View view = null;
// Arrays
Buoy [] buoy = new Buoy[3];
Plane [] plane = new Plane[3];
// Variables
bool selected = false;
int index = 0;
public Game()
{
graphics = new GraphicsDeviceManager(this);
}
protected override void Initialize()
{
Content.RootDirectory = "Content";
this.IsMouseVisible = true;
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
base.Initialize();
view = new View();
for (index = 0; index < buoy.Length; index++)
{
buoy[index] = new Buoy();
plane[index] = buoy[index].CreatePlane();
}
}
protected override void LoadContent()
{
device = graphics.GraphicsDevice;
spriteBatch = new SpriteBatch(device);
b = Content.Load<Texture2D>("buoy");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
mouse = Mouse.GetState();
if (selected == true || mouse.X >= buoy[0].position.X - 3 && mouse.X <= buoy[0].position.X + 19 && mouse.Y >= buoy[0].position.Y - 3 && mouse.Y <= buoy[0].position.Y + 19)
{
if (mouse.LeftButton == ButtonState.Pressed)
{
selected = true;
buoy[0].position= new Vector2(mouse.X - 8, mouse.Y - 8);
}
else
{
selected = false;
}
}
}
protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
view.DrawScreen(this);
}
}
}
View Class
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 Airfield
{
class View
{
public View()
{
}
public void DrawScreen(Game game)
{
game.device.Clear(Color.CornflowerBlue);
game.spriteBatch.Begin();
DrawBuoys(game);
game.spriteBatch.End();
}
public void DrawBuoys(Game game)
{
for (int x = 0; x < game.buoy.Length; x++)
{
game.buoy[x].DrawBuoy(game.spriteBatch, game.b);
}
}
}
}
Basically I get the error for every time that I try and use something that has come from Game.
The problem here is that all of the members inside of Game are marked as protected or not marked at all which defaults to private. This means that only Game and any classes which derive from it will have access to those protected members and no-one else to private. The type View is a completely separate type and hence can't access any members that are protected or private.
To expose the private fields they need to be marked as internal or public.
public class Game : Microsoft.Xna.Framework.Game
{
...
public SpriteBatch spriteBatch;
}
Most of these members are also labeled as override hence you are locked into protected. But you can use another non-protected member to call into the protected. It's not clear from the sample if you want to invoke these methods or not.
All of this is implicitly private:
// Device Objects
GraphicsDevice device = null;
GraphicsDeviceManager graphics = null;
MouseState mouse;
// Game Objects
SpriteBatch spriteBatch;
Texture2D b = null;
View view = null;
// Arrays
Buoy [] buoy = new Buoy[3];
Plane [] plane = new Plane[3];
// Variables
bool selected = false;
int index = 0;
You'd need to change them to public, which is a bad idea for member variables. Or you can create properties to access the member variables:
public SpriteBatch SpriteBatch {
get { return this.spriteBatch; }
protected set { this.spriteBatch = value; }
}
By default in C# any fields that do not have accessibility explicitly defined are assumed to be private. So, you will need to do the following in your Game class:
// Device Objects
public GraphicsDevice device = null;
public GraphicsDeviceManager graphics = null;
public MouseState mouse;
// etc... for your other fields
Second, it's worth noting that all of your Game class's methods have protected accessibility, which means that only classes that inherit from Game will be able to call those methods.