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.
Related
I am trying to create a simple menu, the string that is selected changes colur as it is instructed to do, I just can't seem to space out each item in the string list on the Y axis, currently they are all positioned in the middle but at the top of the screen overlapping each other. I know this is probably a very simple fix but I am a novice at XNA. Any help would be very appreciated. Thanks in advance.
MenuManagement Class
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game2
{
class MenuManagement
{
KeyboardState keyboard;
KeyboardState prevKey;
MouseState mouse;
Vector2 position;
List<String> buttonList = new List<string>();
SpriteFont spriteFont;
int selected = 0;
public MenuManagement ()
{
buttonList.Add("Play");
buttonList.Add("Options");
buttonList.Add("instructions");
buttonList.Add("Exit");
}
private void MeasureMenu()
{
height = 0;
width = 0;
foreach (string item in buttonList)
{
Vector2 size = spriteFont.MeasureString(item);
height += spriteFont.LineSpacing + 5;
}
}
public void LoadContent (ContentManager Content )
{
spriteFont = Content.Load<SpriteFont>("spriteFont");
}
public void Update (GameTime theGameTime)
{
keyboard = Keyboard.GetState();
if (checkKeyBoard(Keys.Up))
{
if (selected > 0)
{
selected--;
}
}
if (checkKeyBoard(Keys.Down))
{
if (selected < buttonList.Count - 1)
{
selected++;
}
}
prevKey = keyboard;
}
public bool checkKeyBoard (Keys key)
{
return (keyboard.IsKeyDown(key) && prevKey.IsKeyDown(key));
}
public void Draw (SpriteBatch theSpriteBatch)
{
theSpriteBatch.Begin();
Color color;
for (int i = 0; i < buttonList.Count; i++)
{
Vector2 location = position;
if (i == selected)
{
color = Color.Yellow;
}
else
{
color = Color.Blue;
}
location.Y += spriteFont.LineSpacing + 5;
}
theSpriteBatch.DrawString(spriteFont, buttonList[0], new Vector2 (300, 100), color);
theSpriteBatch.DrawString(spriteFont, buttonList[1], new Vector2(300, 150), color);
theSpriteBatch.DrawString(spriteFont, buttonList[2], new Vector2(300, 200), color);
theSpriteBatch.DrawString(spriteFont, buttonList[3], new Vector2(300, 250), color);
theSpriteBatch.End();
}
}
}
Game1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game2
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch theSpriteBatch;
public static Rectangle screen;
public static string GameState = "Menu";
MenuManagement menuManagement;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
menuManagement = new MenuManagement();
screen = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
base.Initialize();
}
protected override void LoadContent()
{
theSpriteBatch = new SpriteBatch(GraphicsDevice);
menuManagement.LoadContent(Content);
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
switch (GameState)
{
case "Menu":
menuManagement.Update(gameTime);
break;
}
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
switch (GameState)
{
case "Menu":
menuManagement.Draw(theSpriteBatch);
break;
}
base.Draw(gameTime);
}
}
}
You can calculate the length of the strings and place the next item where you want. You should look to SpriteFont.MeasureString().
https://msdn.microsoft.com/en-us/library/bb464128(v=xnagamestudio.30).aspx
To be clear, the reason they are overlapping is because you are putting them all in the same position:
Vector2 location = position;
and then:
new Vector2 (300, location.Y)
is where you are drawing the entire batch. You need to change the position of each of the menu items. The simplest fix is to increment the Y value of the location for each item. That will move the next menu item toward the bottom. Increment X to move right.
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 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.
I'm trying to code a very basic top down 2D game with XNA, and I've gotten to the part where I'm trying to add grass textures to the game and then draw those textures to the bottom portion of the screen.
However, I'm getting a "NullReferenceException was Unhandled" error on Line 32 of my Level.cs class. As I'm just new to XNA and fairly new (in comparison) to C#, I can't figure this out for the life of me.
UPDATE 1: Thanks mcmonkey4eva, that error is resolved. However, my code now stops during the Draw() method of my TestLevel class (Level.cs). The error is still a "NullReferenceException was Unhandled" error, and the methods are a bit different from what they were.
Anyone know this what I'm doing wrong here?
Here's my updated Level.cs class:
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;
using First.Tiles;
using First;
namespace First.Level
{
class TestLevel
{
//An array of groundtiles that will be set to grass, lava, etc
public GroundTile[,] groundlevel;
//Width/Height of the Level
int width, height;
Grass grass;
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
this.width = width;
this.height = height;
groundlevel = new GroundTile[width, height];
grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
}
//Drawing the grass near the bottom of the screen
public void generateGround()
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x += 32)
{
if (y == (height - 100))
{
if (groundlevel[x, y] == null)
{
groundlevel[x, y] = grass;
}
}
}
}
}
public void draw(GameTime gameTime, SpriteBatch spriteBatch)
{
foreach(GroundTile ground in groundlevel)
{
ground.Draw(gameTime, spriteBatch); //Here's where the error is
}
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
}
}
Here's my updated Game1.cs 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;
using First.Entity;
using First.Tiles;
using First.Level;
namespace First
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 400;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TestLevel level;
UserControlledSprite Lancer;
Texture2D lancerTexture;
Vector2 position = new Vector2(200, 200);
Point frameSize = new Point(32, 48);
int collisionOffset = 0;
Point currentFrame = new Point(0, 0);
Point sheetSize = new Point(4, 4);
Point spriteToUse = new Point(0, 0);
Vector2 speed = new Vector2(2, 2);
int millisecondsPerFrame = 500;
Rectangle clientBounds;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <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
clientBounds = graphics.GraphicsDevice.Viewport.Bounds;
clientBounds.Width = SCREEN_WIDTH;
clientBounds.Height = SCREEN_HEIGHT;
this.IsMouseVisible = true;
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);
Content.RootDirectory = "Content";
level = new TestLevel(SCREEN_WIDTH, SCREEN_HEIGHT, Content);
level.generateGround();
lancerTexture = Content.Load<Texture2D>(#"Images\Lancer");
Lancer = new UserControlledSprite(lancerTexture, position, frameSize, collisionOffset,
currentFrame, sheetSize, spriteToUse, speed, millisecondsPerFrame);
}
/// <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();
Lancer.Update(gameTime, clientBounds);
base.Update(gameTime);
}
/// <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();
Lancer.Draw(gameTime, spriteBatch);
level.draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Here's my Grass.cs class:
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;
using First.Tiles;
using First;
namespace First.Level
{
class TestLevel
{
//An array of groundtiles that will be set to grass, lava, etc
public GroundTile[,] groundlevel;
//Width/Height of the Level
int width, height;
Grass grass;
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
this.width = width;
this.height = height;
groundlevel = new GroundTile[width, height];
grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
}
//Drawing the grass near the bottom of the screen
public void generateGround()
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x += 32)
{
if (y == (height - 100))
{
if (groundlevel[x, y] == null)
{
groundlevel[x, y] = grass;
}
}
}
}
}
public void draw(GameTime gameTime, SpriteBatch spriteBatch)
{
foreach(GroundTile ground in groundlevel)
{
ground.Draw(gameTime, spriteBatch);
}
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
}
}
Just in case, here's my GroundTile class too:
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;
using First.Entity;
namespace First.Tiles
{
class GroundTile
{
//public GroundTile grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
// frameSize needs to be modular, for the objects above walking-ground level
public Texture2D texture;
protected Point frameSize;
public Point frame;
public Vector2 position;
int collisionOffset;
protected Point sheetSize = new Point(9, 19);
public GroundTile(Texture2D tiles, Point frame, Point frameSize, int collisionOffset)
{
this.frame = frame;
this.frameSize = frameSize;
this.collisionOffset = collisionOffset;
this.texture = tiles;
}
//Collision Detection, incase of water or something
public Rectangle collisionRect
{
get
{
return new Rectangle(
(int)position.X + collisionOffset,
(int)position.Y + collisionOffset,
frameSize.X - (collisionOffset * 2),
frameSize.Y - (collisionOffset * 2));
}
}
//Not really used, but just in case
public bool collidesWith(GroundTile tile, Sprite sprite)
{
if (sprite.collisionRect.Intersects(collisionRect))
{
sprite.position -= sprite.direction;
}
return false;
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
public GraphicsDevice Graphicsdevice
{
get { return graphicsDevice; }
}
GraphicsDevice graphicsDevice;
public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,
position,
new Rectangle(frame.X * frameSize.X,
frame.Y * frameSize.Y,
frameSize.X, frameSize.Y),
Color.White, 0, Vector2.Zero,
1f, SpriteEffects.None, 0);
}
}
}
You're accessing Content before it's set - or, rather, you're never setting it at all.
Change
public TestLevel(int width, int height)
{
//I input my screen dimensions as my level size
to
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
and then add the Content argument when you create your TestLevel object (I assume from Game1.cs) (Note: Be sure to create TestLevel after you create the Content object [in the LoadContent method]!)
EDIT:
For the new problem:
You're not defining the contents of the array, except a single layer of grass...
The line
ground.Draw(gameTime, spriteBatch);
Change to
if (ground != null)
{
ground.Draw(gameTime, spriteBatch);
}
But you should also make sure that ground is actually getting filled with content... specifically, new tile objects for each and every point in the array, not just a single line, and not just the same 'grass' instance for every location.
I don't mean to offend, but you're dealing with pretty basic errors here. It might be beneficial for you to look up and follow some basic C# tutorials.
I don't know about XNA, but clearly you Content. returns null.
Is this a class name or a property of your level class? If it's a property, then make sure it is initialized. Otherwize, I don't understand how you would received a nullreferenceexception if you call a static property of a class
I am trying to make a game and I want "enemies" or meteors to spawn from the right side and going to the left side. I am working on some code and it seems to be working pretty good but the respawning fails. They end up spawning one and one REALLY slow and then after a while they don't spawn at all. All help would be really appreciated.
Here's my code:
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 WindowsGame2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
List<Enemies> enemies = new List<Enemies>();
Random random = new Random();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
}
float spawn = 0;
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;
foreach (Enemies enemy in enemies)
{
enemy.Update(graphics.GraphicsDevice);
}
LoadEnemies();
base.Update(gameTime);
}
public void LoadEnemies()
{
int randY = random.Next(100, 400);
if (spawn > 1)
{
spawn = 0;
if (enemies.Count() < 10)
enemies.Add(new Enemies(Content.Load<Texture2D>("meteor"), new Vector2(1110, randY)));
}
for (int i = 0; i < enemies.Count; i++)
{
if (!enemies[i].isVisible)
{
enemies.RemoveAt(i);
i--;
}
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
foreach (Enemies enemy in enemies)
{
enemy.Draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
and here's my class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace WindowsGame2
{
class Enemies
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public bool isVisible = true;
Random random = new Random();
int randX, randY;
public Enemies(Texture2D newTexture, Vector2 newPosition)
{
texture = newTexture;
position = newPosition;
randX = random.Next(-4, 4);
randY = random.Next(-4, -1);
velocity = new Vector2(randX, randY);
}
public void Update(GraphicsDevice graphics)
{
position += velocity;
if (position.Y <= 0 || position.Y >= graphics.Viewport.Height - texture.Height)
{
velocity.Y = -velocity.Y;
}
if (position.X < 0 - texture.Width)
{
isVisible = false;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
}
Your problem lies here. Some of your meteors are moving right and some are not moving at all.
randX = random.Next(-4, 4);
Try using
randX = random.Next(-4, -1);
Your enemies/meteors sometimes had a velocity on the X that was between 0 and 4, so they moved right.
I can see you changed the Y to this, maybe you got them mixed up?