I am still a novice at programming, and I'm currently trying to make a menu for a test game. However, I am having an issue where, when I reference a value from class, Language.cs in my Main.cs using spriteBatch.DrawString, it returns an ArgumentNullException. Any help would be greatly appreciated.
The debugger highlights the following segment under DrawMainMenu() in my Main.cs:
spriteBatch.DrawString(UIFont, Language.mainMenu[0], new Vector2(mainWidth / 2, mainHeight / 2 - 192), Color.White);
I'm not sure if it's an issue of what order I'm using my methods in, but here's what the whole page of Main.cs looks like. Please pardon some of the mess, as I have been experimenting with a variety of things in this program.
public class Main : Game
{
GraphicsDeviceManager graphics;
public static SpriteBatch spriteBatch;
public static SpriteFont UIFont;
public static Texture2D logo;
public static Texture2D titleBack;
public static Texture2D titleSelect;
public static int menuType;
public static Texture2D cursor1;
public static MouseState mouseState;
public static MouseState mouseStatePrevious;
public static MouseState oldState;
public static MouseState newState;
public static int mouseX = mouseState.X;
public static int mouseY = mouseState.Y;
public static Vector2 cursorPos;
public static int strength = 0;
public static int mainWidth = 1920;
public static int mainHeight = 1080;
public static bool showSplash = true;
public int splashCounter;
public static int fadeCounter;
public static bool gameTimeActive = false;
private static int maxMenuItems = 12;
public static int selectedMenu = -1;
public static int selectedMenuType = -1;
public static bool mainMenu = false;
public static Vector2 screenPosition;
Player player = new Player();
public Main()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = mainWidth; // set this value to the desired width of your window
graphics.PreferredBackBufferHeight = mainHeight; // set this value to the desired height of your window
//graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width;
//graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height;
graphics.ApplyChanges();
}
// 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.
protected override void Initialize()
{
// TODO: Add your initialization logic here
player.Initialize();
base.Initialize();
}
// LoadContent will be called once per game and is the place to load
// all of your content.
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
// Load initial content...
spriteBatch = new SpriteBatch(GraphicsDevice);
logo = Content.Load<Texture2D>(#"Textures\StudioLogoW");
UIFont = Content.Load<SpriteFont>(#"Textures\Fonts\Font_FrontEnd");
cursor1 = Content.Load<Texture2D>(#"Textures\CursorWhite");
titleBack = Content.Load<Texture2D>(#"Textures\UI\TitleBackground");
titleSelect = Content.Load<Texture2D>(#"Textures\UI\TitleSelect");
player.LoadContent(Content);
// TODO: use this.Content to load the rest of the game content...
}
// UnloadContent will be called once per game and is the place to unload
// all content.
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
// Allows the game to run logic such as updating the world,
// checking for collisions, gathering input, and playing audio.
// <param n
protected override void Update(GameTime gameTime)
{
// Enable mouse funtion in game.
//this.IsMouseVisible = true;
cursorPos = new Vector2(mouseState.X, mouseState.Y);
mouseState = Mouse.GetState();
base.Update(gameTime);
// Get Mouse State, in this case, we're checking to see if a button was clicked, and which one.
// Depending on which button was pressed, it will either add or subract strength.
if (gameTimeActive)
{
player.Update(gameTime);
if (mouseState.LeftButton == ButtonState.Pressed && mouseStatePrevious.LeftButton == ButtonState.Released)
strength++;
if (mouseState.RightButton == ButtonState.Pressed && mouseStatePrevious.RightButton == ButtonState.Released)
strength--;
if (strength > 255)
strength = 255;
if (strength < 0)
strength = 0;
mouseStatePrevious = mouseState;
}
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Add your update logic here
}
protected void DrawSplash(GameTime gameTime) //Section for drawing our splash logo, and fading it in and out.
{
base.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.Black);
base.Draw(gameTime);
Main.spriteBatch.Begin();
this.splashCounter++;
Microsoft.Xna.Framework.Color white = Microsoft.Xna.Framework.Color.White;
byte splashByte = 0;
if (this.splashCounter <= 75)
{
float splashNum = (float)this.splashCounter / 75f * 255f;
splashByte = (byte)splashNum;
}
else if (this.splashCounter <= 225)
{
splashByte = 255;
}
else if (this.splashCounter <= 300)
{
int splashNum2 = 225 - this.splashCounter;
float splashNum3 = (float)splashNum2 / 75f * 255f;
splashByte = (byte)splashNum3;
}
else
{
Main.showSplash = false;
Main.mainMenu = true;
Main.selectedMenu = 0;
Main.fadeCounter = 75;
}
white = new Color((int)splashByte, (int)splashByte, (int)splashByte, (int)splashByte);
Main.spriteBatch.Draw(Main.logo, new Rectangle(0, 0, Main.mainWidth, Main.mainHeight), white);
Main.spriteBatch.End();
}
protected void DrawMainMenu() //Section for drawing our Main Menu and fading it in after the splash logo.
{
Language.lang = 1;
graphics.GraphicsDevice.Clear(Color.Black);
// Display some stuff. In this case, we're displaying the logo and some text.
spriteBatch.Begin();
splashCounter++;
Microsoft.Xna.Framework.Color white = Microsoft.Xna.Framework.Color.White;
spriteBatch.Draw(titleBack, new Rectangle(0, 0, mainWidth, mainHeight), Color.White);
//spriteBatch.DrawString(UIFont, "Strength: " + strength, new Vector2(mainWidth / 2, 50), Color.White);
//player.Draw(spriteBatch);
if (selectedMenu == 0)
{
spriteBatch.DrawString(UIFont, Language.mainMenu[0], new Vector2(mainWidth / 2, mainHeight / 2 - 192), Color.White);
}
spriteBatch.Draw(cursor1, cursorPos, Color.White);
spriteBatch.End();
//base.Draw(gameTime);
}
// This is called when the game should draw itself.
// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
if (Main.showSplash)
{
DrawSplash(gameTime);
return;
}
if (Main.mainMenu)
{
gameTimeActive = false;
DrawMainMenu();
return;
}
}
}
And here is my Language.cs:
public class Language
{
public static int lang = 0;
public static string[] mainMenu = new string[99];
public static string[] debugMenu = new string[99];
public static void MenuStrings()
{
if (lang == 1)
{
//For unavailable functions
mainMenu[99] = "Currently unavailable";
//Main Menu
mainMenu[0] = "Single Player";
mainMenu[1] = "Multiplayer";
mainMenu[2] = "Options";
mainMenu[3] = "Credits";
mainMenu[4] = "Exit";
//Single Player - Character
mainMenu[5] = "New Character";
mainMenu[6] = "Load Character";
//Single Player - World
mainMenu[7] = "New World";
mainMenu[8] = "Load World";
//Multiplayer - Front
mainMenu[9] = "Host";
mainMenu[10] = "Join";
//Multiplayer - Host
mainMenu[11] = "Game Mode";
}
}
}
You never called your Language.MenuStrings() method, so Language.mainMenu just contains 99 nulls.
From the code you've shown, you never actually call Language.MenuStrings. Which means Language.mainMenu[0] is still a null reference when you access it.
Related
Heres my whole code, maybe my variables are in correct, i'm not to sure:
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 System.IO;
using System.Text;
namespace PickUpTheCrewGame
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class PickUpTheCrewGame : Microsoft.Xna.Framework.Game
{
public enum State
{
Menu,
Playing,
Gameover,
}
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont messageFont;
SpriteFont playerScoreFont;
Texture2D backgroundTexture;
Rectangle backgroundRectangle;
Texture2D menuImageTexture;
Rectangle menuImageRectange;
Texture2D gameoverImageTexture;
Rectangle gameoverImageRectangle;
Sprite BlueBall;
Sprite GreenBall;
Sprite OrangeBall;
Sprite PinkBall;
Sprite RedBall;
Sprite c;
Sprite YellowBall;
public Texture2D menuImage;
public Texture2D gameoverImage;
//---player scoresyer
int playerScore = 0;
int highScore = 0;
//Lists
List<sharks> sharks = new List<sharks>();
List<Sprite> crew = new List<Sprite>();
List<int> highscoreList = new List<int>();
//highScoreList.Add(score);
//Set First State
State gameState = State.Menu;
HUD hud = new HUD();
public PickUpTheCrewGame()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
//sreen size
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
menuImage = null;
gameoverImage = null;
}
/// <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
//enable the mousepointer
//IsMouseVisible = true;
base.Initialize();
}
public static bool _highScore (int playerScore)
{
if(playerScore >_highScore)
{
return true;
}
else
{
return false;
}
}
public void Save(string filename)
{
System.IO.TextWriter textOut = null;
try
{
textOut = new System.IO.StreamWriter(filename);
Save(textOut);
}
catch (Exception e)
{
throw e;
}
finally
{
if (textOut != null) textOut.Close();
}
}
private void Save(TextWriter textOut)
{
try
{
foreach (Sprite crew1 in crew)
{
textOut.WriteLine(crew1.location.X);
textOut.WriteLine(crew1.location.Y);
}
foreach (sharks enemySprite in sharks)
{
textOut.WriteLine("Shark");
textOut.WriteLine(enemySprite.location.X);
textOut.WriteLine(enemySprite.location.Y);
}
}
catch
{
}
}
public void Load(string filename)
{
System.IO.TextReader textIn = null;
//try
//{
textIn = new System.IO.StreamReader(filename);
Load(textIn);
//}
//catch (Exception e)
//{
// throw e;
//}
//finally
//{
if (textIn != null) textIn.Close();
//}
}
private void Load(TextReader textIn)
{
foreach (Sprite crew1 in crew)
{
crew1.location.X = int.Parse(textIn.ReadLine());
crew1.location.Y = int.Parse(textIn.ReadLine());
}
foreach (sharks enemySprite in sharks)
{
enemySprite.location.X = int.Parse(textIn.ReadLine());
enemySprite.location.Y = int.Parse(textIn.ReadLine());
}
throw new NotImplementedException();
}
/// <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);
hud.LoadContent(Content);
//-----LOAD THE MENU BACKGROUND-----
menuImageTexture = Content.Load<Texture2D>("menuImage");
menuImageRectange = new Rectangle(0, 0,
Window.ClientBounds.Width,
Window.ClientBounds.Height);
//------LOAD INGAME BACKGROUND-----
backgroundTexture = Content.Load<Texture2D>("Background");
backgroundRectangle = new Rectangle(
0, 0, // top left hand corner
Window.ClientBounds.Width,
Window.ClientBounds.Height); // size of screen display
//GAMEOVER IMAGE BACKGROUND
gameoverImageTexture = Content.Load<Texture2D>("gameoverImage");
gameoverImageRectangle = new Rectangle(
0, 0,
Window.ClientBounds.Width,
Window.ClientBounds.Height);
//-------Captains crew-------
c = new Sprite(new Vector2(0, 0), new Vector2(0, 0),
Content.Load<Texture2D>("WhiteBall"), Color.White);
BlueBall = new Sprite(new Vector2(640, 450),
Content.Load<Texture2D>("BlueBall"));
crew.Add(BlueBall);
GreenBall = new Sprite(new Vector2(250, 600),
Content.Load<Texture2D>("GreenBall"));
crew.Add(GreenBall);
OrangeBall = new Sprite(new Vector2(115, 400),
Content.Load<Texture2D>("OrangeBall"));
crew.Add(OrangeBall);
RedBall = new Sprite(new Vector2(500, 600),
Content.Load<Texture2D>("RedBall"));
crew.Add(RedBall);
YellowBall = new Sprite(new Vector2(800, 400),
Content.Load<Texture2D>("YellowBall"));
crew.Add(YellowBall);
PinkBall = new Sprite(new Vector2(25, 175),
Content.Load<Texture2D>("PinkBall"));
crew.Add(PinkBall);
//--------Sharks------
sharks s = new sharks(new Vector2(1000, 200),
Content.Load<Texture2D>("BlackBall"));
sharks.Add(s);
s = new sharks(new Vector2(900, 200),
Content.Load<Texture2D>("BlackBall"));
sharks.Add(s);
s = new sharks(new Vector2(800, 200),
Content.Load<Texture2D>("BlackBall"));
sharks.Add(s);
messageFont = Content.Load<SpriteFont>("messageFont");
// TODO: use this.Content to load your game content here
}
/// <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)
{
//----------This gets the time value---------
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
//--------------keyboard input---------------
//Exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
//Save
if (Keyboard.GetState().IsKeyDown(Keys.S))
Save("test.txt");
//Load
if (Keyboard.GetState().IsKeyDown(Keys.L))
Load("test.txt");
//Directional Movement
if (Keyboard.GetState().IsKeyDown(Keys.Left))
c.velocity.X = -350;
if (Keyboard.GetState().IsKeyDown(Keys.Right))
c.velocity.X = 350;
if (Keyboard.GetState().IsKeyDown(Keys.Down))
c.velocity.Y = 350;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
c.velocity.Y = -350;
//UPDATING PLAYING STATE
switch (gameState)
{
case State.Playing:
c.Update(elapsed);
foreach (Sprite cr in crew)
{
cr.Update(elapsed);
}
c.col = Color.White;
//----sharks intersects with whiteball----
foreach (sharks s in sharks)
{
if (c.bounds.Intersects(s.bounds))
{
gameState = State.Gameover;
break;
}
}
foreach (sharks s in sharks)
{
s.Update(elapsed, c.location);
}
//hud.Update(gameTime);
//----sprites intersect with whiteball----
foreach (Sprite crew1 in crew)
{
if (c.bounds.Intersects(crew1.bounds))
{
//gameState = State.Gameover;
playerScore += 1;
crew1.bounds.X = 10000;
crew1.bounds.Y = 10000;
crew1.location.Y = 10000;
crew1.location.X = 10000;
break;
}
} break;
//UPDATING MENU STATE
case State.Menu:
{
//Get keyboard state
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = State.Playing;
}
break;
}
//UPDATING GAMEOVER STATE
case State.Gameover:
{
//Get keyboard state
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Back))
{
if (playerScore > highScore)
{
highScore = playerScore;
SavehighScore();
}
playerScore = 0;
sharks.Clear();
crew.Clear();
gameState = State.Menu;
}
break;
}
}
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();
switch (gameState)
{
//DRAWING PLAYING STATE
case State.Playing:
{
spriteBatch.Draw(backgroundTexture, backgroundRectangle,
Color.White);
c.Draw(spriteBatch);
//FOR EACH CREW DRAW
foreach (Sprite cr in crew)
{
cr.Draw(spriteBatch);
}
//FOREACH SHARK DRAW
foreach (sharks s in sharks)
{
s.Draw(spriteBatch);
}
hud.Draw(spriteBatch);
spriteBatch.DrawString(messageFont, playerScore.ToString(),
new Vector2(200, 0),
Color.White);
spriteBatch.DrawString(messageFont, " Player Scores - ",
new Vector2(0, 0), Color.White);
break;
}
//DRAWING MENU STATE
case State.Menu:
{
spriteBatch.Draw(menuImageTexture, menuImageRectange, Color.White);
break;
}
//DRAWING GAMEOVER STATE
case State.Gameover:
{
spriteBatch.Draw(gameoverImageTexture, gameoverImageRectangle, Color.White);
spriteBatch.DrawString(messageFont, "Your Final Score was - " + playerScore.ToString(),new Vector2 (0,0), Color.White);
break;
}
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Here the fist error:
Error 1 Operator '>' cannot be applied to operands of type 'int' and 'method group'
I'm doing highscores in XNA and have gotten an error message:
public static bool _highScore (int playerScore)
{
if(playerScore >_highScore)
{
return true;
}
else
{
return false;
}
}
I also get an error messeage at the end saying:
'The name 'SavehighScore' does not exist in current context'
Code:
case State.Gameover:
{
//Get keyboard state
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Back))
{
if (playerScore > highScore)
{
highScore = playerScore;
SavehighScore();
}
playerScore = 0;
sharks.Clear();
crew.Clear();
gameState = State.Menu;
}
break;
}
That is my whole gameover state of which when the player dies, its meant to show there highscores.
IF you could advise a way of whats best way to save a highscore in a method, that would be really helpful as well please:
I am rather new to XNA, still learning. If anyone could be any help would really appreciate it. Thank You
public static bool _highScore (int playerScore)
{
if(playerScore >_highScore)
{
return true;
}
else
{
return false;
}
}
"Here the fist error: Error 1 Operator '>' cannot be applied to operands of type 'int' and 'method group'"
The reason why you get this error is because you are comparing playerScore (an int) to the _highScore method (which is also called incorrectly).
What are you trying to accomplish here? If you just want a convenience method to check the high score:
Refactor to:
public bool IsHighScore()
{
return playerScore > highScore;
}
Then, in your gamestate:
case State.Gameover:
{
//Get keyboard state
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Back))
{
if (IsHighScore())
{
highScore = playerScore;
SavehighScore();
}
playerScore = 0;
And as others have said, you have to write your SavehighScore method.
just use if(playerScore > this.highScore)
I'm building a breakout type game and I'm having a little issue with collision detection. How should I create the rectangle(s), do I do one rectangle per block but then how do I detect which side has been hit, or do I do 4 rectangles for each side of the block and base an if statement around them.
I tried to create 4 rectangles per block, one for top, bottom etc etc but I couldn't get it correct.
heres my code to see if you can work out the best way to handle it.
Brick class:
class Bricks
{
Texture2D redbrickimg;
Texture2D blueBrickimg;
Texture2D greenBrickimg;
Texture2D pinkBrickimg;
Texture2D aquaBrickimg;
/*Rectangle aquaBrickrectangle;
Rectangle redBrickrectangle;
Rectangle blueBrickrectangle;
Rectangle greenBrickrectangle;
Rectangle pinkBrickrectangle;
*/
Rectangle[,] topHit = new Rectangle[12,12];
Rectangle[,] bottomHit = new Rectangle[12,12];
Rectangle[,] rightHit = new Rectangle[12,12];
Rectangle[,] leftHit = new Rectangle[12,12];
int[,] redBrickXPos = new int [12,12];
int[,] redBrickYPos = new int [12,12];
int[,] colourBrick = new int[12, 12];
public Bricks(
Texture2D Redbricks,
Texture2D blueBricks,
Texture2D greenBricks,
Texture2D pinkBricks,
Texture2D aquaBricks
)
{
redbrickimg = Redbricks;
blueBrickimg = blueBricks;
greenBrickimg = greenBricks;
pinkBrickimg = pinkBricks;
aquaBrickimg = aquaBricks;
}
public void Initialize()
{
for (int j = 0; j < 12; j++)
{
for (int i = 0; i < 12; i++)
{
redBrickXPos[j,i] = 1 + i * redbrickimg.Width;
redBrickYPos[j,i] = 1 + j * redbrickimg.Height;
colourBrick[j,i] = j/2;
}
}
}
public void Update()
{
}
public void Draw(SpriteBatch spritebatch)
{
for (int j = 0; j < 12; j++)
{
for (int i = 0; i < 12; i++)
{
if (colourBrick[j, i] == 0)
{
spritebatch.Draw(redbrickimg, new Vector2(redBrickXPos[j, i], redBrickYPos[j, i]),Color.White);
}
else if (colourBrick[j, i] == 1)
{
spritebatch.Draw(blueBrickimg, new Vector2(redBrickXPos[j, i], redBrickYPos[j, i]),Color.White);
}
else if (colourBrick[j, i] == 2)
{
spritebatch.Draw(greenBrickimg, new Vector2(redBrickXPos[j, i], redBrickYPos[j, i]), Color.White);
}
else if (colourBrick[j, i] == 3)
{
spritebatch.Draw(pinkBrickimg, new Vector2(redBrickXPos[j, i], redBrickYPos[j, i]),Color.White);
}
else if (colourBrick[j, i] == 4)
{
spritebatch.Draw(aquaBrickimg, new Vector2(redBrickXPos[j, i], redBrickYPos[j, i]), Color.White);
}
}
}
}
}
My main class:
public class Breakout : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D BackgroundImg;
Bricks bricks;
Paddle paddle;
GameBall gameball;
bool iskeyLeft = false;
bool iskeyRight = false;
bool Flag;
int moveBy;
float ballX;
float ballY;
public Breakout()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 960;
graphics.PreferredBackBufferHeight = 768;
graphics.ApplyChanges();
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
bricks.Initialize();
paddle.Initialize();
gameball.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);
BackgroundImg = Content.Load<Texture2D>("starfield");
bricks = new Bricks(
Content.Load<Texture2D>("red brick"),
Content.Load<Texture2D>("brickblue"),
Content.Load<Texture2D>("greenbrick"),
Content.Load<Texture2D>("pinkbrick"),
Content.Load<Texture2D>("aquaBrick")
);
paddle = new Paddle(Content.Load<Texture2D>("Paddle"),
new Rectangle(0, 0, 110, 30),iskeyLeft,iskeyRight);
gameball = new GameBall(Content.Load <Texture2D>("ball"),
new Rectangle(0, 0, 60, 60));
IsMouseVisible = true;
// TODO: use this.Content to load your game content here
}
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();
// call update on paddle
moveBy = paddle.Update();
Flag = gameball.Update();
if (Flag == false)
{
gameball.moveBall(moveBy);
}
// TODO: Add your update logic here
// mainmenu = new mainmenu(mainmenuISon, Content.Load<Texture2D>("option_menu"),
Content.Load<Texture2D>("start_button"), Content.Load<Texture2D>("exit_button"));
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
spriteBatch.Begin();
spriteBatch.Draw(BackgroundImg, Vector2.Zero, Color.White);
bricks.Draw(spriteBatch);
paddle.Draw(spriteBatch);
gameball.Draw(spriteBatch);
spriteBatch.End();
}
}
You left out the most interesting part of your code where you're actually attempting the collision test.
I would go with one rect for your brick (and thereby only one collision test per brick) and only if that passes you need to figure out what side was hit. You can easily rule out two sides by the direction of the GameBall (you cannot hit the "backside"). For the remaining two sides you check if the "front" corner is on the left or right of your current line of movement.
I have an isometric tile engine written in XNA (Monogame). It can only draw tile map surface. But when I have bigger map (for example 50x50 tiles) then is very slow (about 15 FPS). When I have small map (for example 10x10 tiles) than framrate is perfect (60 FPS).
I'm trying to find way how to optimise my code but I have no idea how to do it.
This is my code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using System;
namespace IsoEngine
{
public class Game1 : Game
{
GraphicsDeviceManager _graphics;
SpriteBatch _spriteBatch;
Texture2D Tile1;
Texture2D Tile2;
MouseState mouseState;
bool isMousePressed = false;
int[,] map = { {1, 1, 1, 1},
{1, 0, 0, 1},
{1, 0, 0, 1},
{1, 1, 1, 1} };
int tileWidth = 64;
int tileHeight = 32;
Vector2 scrollSpan = new Vector2(0, 0);
Vector2 mouseDragPos = new Vector2(0, 0);
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.IsMouseVisible = true;
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
Tile1 = Content.Load<Texture2D>("1");
Tile2 = Content.Load<Texture2D>("2");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
mouseState = Mouse.GetState();
if (mouseState.LeftButton == ButtonState.Pressed && !isMousePressed)
{
isMousePressed = true;
mouseDragPos.X = mouseState.X;
mouseDragPos.Y = mouseState.Y;
}
if (mouseState.LeftButton == ButtonState.Pressed && isMousePressed)
{
if (mouseDragPos.X < mouseState.X)
{
scrollSpan.X += mouseState.X - mouseDragPos.X;
mouseDragPos.X = mouseState.X;
}
if (mouseDragPos.X > mouseState.X)
{
scrollSpan.X -= mouseDragPos.X - mouseState.X;
mouseDragPos.X = mouseState.X;
}
if (mouseDragPos.Y < mouseState.Y)
{
scrollSpan.Y += (mouseState.Y - mouseDragPos.Y) * 2;
mouseDragPos.Y = mouseState.Y;
}
if (mouseDragPos.Y > mouseState.Y)
{
scrollSpan.Y -= (mouseDragPos.Y - mouseState.Y) * 2;
mouseDragPos.Y = mouseState.Y;
}
}
if (mouseState.LeftButton == ButtonState.Released && isMousePressed)
isMousePressed = false;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin();
DrawMap();
_spriteBatch.End();
base.Draw(gameTime);
}
private void DrawMap()
{
for (int osaY = 0; osaY < map.GetLength(0); osaY++)
{
for (int osaX = 0; osaX < map.GetLength(1); osaX++)
{
int x = osaX * 32;
int y = osaY * 32;
Texture2D thisTile = Tile1;
if (map[osaY, osaX] == 0)
thisTile = Tile1;
if (map[osaY, osaX] == 1)
thisTile = Tile2;
PlaceTile(thisTile, CartToIso(new Vector2(x, y)), new Vector2(osaX, osaY));
}
}
}
public void PlaceTile(Texture2D tileImage, Vector2 tilePos, Vector2 tileCoords)
{
_spriteBatch.Draw(tileImage, new Vector2(tilePos.X - (tileWidth / 2), tilePos.Y - tileHeight), Color.White);
}
public Vector2 CartToIso(Vector2 cartCoords)
{
Vector2 isoCoords = new Vector2(0, 0);
isoCoords.X = (cartCoords.X + scrollSpan.X) - cartCoords.Y;
isoCoords.Y = (cartCoords.X + scrollSpan.Y + cartCoords.Y) / 2;
return isoCoords;
}
public Vector2 IsoToCart(Vector2 isoCoords)
{
Vector2 cartCoords = new Vector2(0, 0);
cartCoords.X = (2 * isoCoords.Y + isoCoords.X - scrollSpan.X - scrollSpan.Y) / 2;
cartCoords.Y = (2 * isoCoords.Y - isoCoords.X + scrollSpan.X - scrollSpan.Y) / 2;
return cartCoords;
}
}
}
I'd suggest you to take a look at an answer I wrote a while ago, it does draw only the only the visible part of a level, no matter how big the level is :
I'm not copying and pasting the answer here as I wrote it already, so go and have a look at it here :
https://gamedev.stackexchange.com/a/29930/16262
Generally, to increase performace avoid creating unessesary objects and dont do anything you dont have to. For example you create one useless local texture in DrawMap(), also for single call of method PlaceTile you create 3 new vectors, while you need one.etc. also note, these are only minor improvements.
Another ways of speeding up might be using buffers(not sure what is default for XNA)
But most importantly, parallelize wherever you can.
Before doing anything else, profile your code and see where the most time is being spent. Only then can you begin to optimize
When you click on the top most button it is suppose to draw a string to the screen, but it's no showing up. I moved mainMenu.UpdateButtons(); to the Draw method in Main.cs but the string is drawn then the background image is drawn again. Making it appear as the string appears for a split second and disappear. Why is it doing this?
Main.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;
using TestGame.Controls;
using TestGame.GameStates;
namespace TestGame
{
public class Main : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
InputHandler inputHandler;
public SpriteBatch spriteBatch;
public SpriteFont spriteFont;
MainMenu mainMenu;
Vector2 position;
public Main()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
inputHandler = new InputHandler();
mainMenu = new MainMenu(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
}
protected override void Initialize()
{
this.IsMouseVisible = true;
base.Initialize();
mainMenu.MenuInitialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spriteFont = Content.Load<SpriteFont>(#"Fonts\MainFont");
mainMenu.MenuLoadContent();
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
inputHandler.Update();
if (inputHandler.currentKeyState.IsKeyDown(Keys.Escape))
this.Exit();
mainMenu.frameTime = gameTime.ElapsedGameTime.Milliseconds / 1000;
MouseState mouseState = Mouse.GetState();
mainMenu.mouseX = mouseState.X;
mainMenu.mouseY = mouseState.Y;
mainMenu.previouslyPressed = mainMenu.mousePressed;
mainMenu.mousePressed = mouseState.LeftButton == ButtonState.Pressed;
mainMenu.UpdateButtons();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
mainMenu.MenuDraw();
spriteBatch.End();
base.Draw(gameTime);
}
}
}
MainMenu.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace TestGame.GameStates
{
public class MainMenu
{
enum buttonState { hover, up, released, down }
const int numberOfButtons = 4, newGameButtonIndex = 0, loadGameButtonIndex = 1, optionsButtonIndex = 2, quitButtonIndex = 3, buttonHeight = 48, buttonWidth = 80;
Color[] buttonColor = new Color[numberOfButtons];
Rectangle[] buttonRect = new Rectangle[numberOfButtons];
buttonState[] buttonSt = new buttonState[numberOfButtons];
Texture2D[] buttonTexture = new Texture2D[numberOfButtons];
double[] buttonTimer = new double[numberOfButtons];
public bool mousePressed, previouslyPressed = false;
public int mouseX, mouseY;
public double frameTime;
int buttonPadding;
Main main;
Texture2D backgroundImage;
Texture2D backgroundImageFade;
public MainMenu(Game game)
{
main = (Main)game;
}
public void MenuInitialize()
{
for (int i = 0; i < numberOfButtons; i++)
{
buttonSt[i] = buttonState.up;
buttonColor[i] = Color.White;
buttonTimer[i] = 0.0;
buttonRect[i] = new Rectangle(0, buttonPadding, buttonWidth, buttonHeight);
buttonPadding += buttonHeight;
}
}
public void MenuLoadContent()
{
backgroundImage = main.Content.Load<Texture2D>(#"Backgrounds\titlescreen");
backgroundImageFade = main.Content.Load<Texture2D>(#"Backgrounds\titlescreenfade");
buttonTexture[newGameButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[loadGameButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[optionsButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[quitButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
}
public void MenuDraw()
{
main.spriteBatch.Draw(backgroundImage, new Vector2(0, 0), Color.White);
for (int i = 0; i < numberOfButtons; i++)
{
main.spriteBatch.Draw(buttonTexture[i], buttonRect[i], buttonColor[i]);
}
}
Boolean targetImageAlpha(Rectangle rect, Texture2D texture, int x, int y)
{
return targetImageAlpha(0, 0, texture, texture.Width * (x - rect.X) / rect.Width, texture.Height * (y - rect.Y) / rect.Height);
}
Boolean targetImageAlpha(float tx, float ty, Texture2D texture, int x, int y)
{
if (targetImage(tx, ty, texture, x, y))
{
uint[] data = new uint[texture.Width * texture.Height];
texture.GetData<uint>(data);
if ((x - (int)tx) + (y - (int)ty) * texture.Width < texture.Width * texture.Height)
{
return ((data[(x - (int)tx) + (y - (int)ty) * texture.Width] & 0xFF000000) >> 24) > 20;
}
}
return false;
}
Boolean targetImage(float tx, float ty, Texture2D texture, int x, int y)
{
return (x >= tx && x <= tx + texture.Width && y >= ty && y <= ty + texture.Height);
}
public void UpdateButtons()
{
for (int i = 0; i < numberOfButtons; i++)
{
if (targetImageAlpha(buttonRect[i], buttonTexture[i], mouseX, mouseY))
{
buttonTimer[i] = 0.0;
if (mousePressed)
{
buttonSt[i] = buttonState.down;
buttonColor[i] = Color.Blue;
}
else if (!mousePressed && previouslyPressed)
{
if (buttonSt[i] == buttonState.down)
{
buttonSt[i] = buttonState.released;
}
}
else
{
buttonSt[i] = buttonState.hover;
buttonColor[i] = Color.LightBlue;
}
}
else
{
buttonSt[i] = buttonState.up;
if (buttonTimer[i] > 0)
{
buttonTimer[i] = buttonTimer[i] - frameTime;
}
else
{
buttonColor[i] = Color.White;
}
}
if (buttonSt[i] == buttonState.released)
{
onButtonClick(i);
}
}
}
void onButtonClick(int i)
{
switch (i)
{
case newGameButtonIndex:
main.spriteBatch.Begin();
//main.spriteBatch.DrawString(main.spriteFont, "Creating new game", new Vector2(100, 200), Color.White);
main.spriteBatch.Draw(backgroundImageFade, new Vector2(0, 0), Color.White);
main.spriteBatch.End();
break;
default:
break;
}
}
}
}
It is being drawn, but then you proceed to erase it in your Draw method. That's the issue you'll get when you start to mix your drawing code in with your updating code.
So here's an example of what's happening in your game right now.
Update Main Game
Update Buttons
Draw Main Game
Draw Buttons
Then a click occurs and here's what happens.
Update Main Game
Update Buttons
onButtonClick -> this is where you draw your text
Draw Main Game -> the screen now clears and your draw your buttons
Draw Buttons
So it's all "working" just not how you really intended it. You're going to want to separate your drawing code so that you're drawing from Draw method calls. Basically check to see if the buttonState has become "released" in your Draw method and THEN draw the text you want.
I want to create a low resolution game on a larger window. (96x54 res on 960x540 size window for example).
How would I go about this? Is there a way to resize a window independently of the preferred back buffer width and height? Or should I just keep a low resolution render target I draw on, and just draw it as a full screen quad on my window when I'm done adjusting for nearest texture sampling?
Thanks in advance,
xoorath
I tend to opt for the "render to texture" solution so that I can allow for things like full screen without distortions.
The class I use to achieve this usually looks something like:
class VirtualScreen
{
public readonly int VirtualWidth;
public readonly int VirtualHeight;
public readonly float VirtualAspectRatio;
private GraphicsDevice graphicsDevice;
private RenderTarget2D screen;
public VirtualScreen(int virtualWidth, int virtualHeight, GraphicsDevice graphicsDevice)
{
VirtualWidth = virtualWidth;
VirtualHeight = virtualHeight;
VirtualAspectRatio = (float)(virtualWidth) / (float)(virtualHeight);
this.graphicsDevice = graphicsDevice;
screen = new RenderTarget2D(graphicsDevice, virtualWidth, virtualHeight, false, graphicsDevice.PresentationParameters.BackBufferFormat, graphicsDevice.PresentationParameters.DepthStencilFormat, graphicsDevice.PresentationParameters.MultiSampleCount, RenderTargetUsage.DiscardContents);
}
private bool areaIsDirty = true;
public void PhysicalResolutionChanged()
{
areaIsDirty = true;
}
private Rectangle area;
public void Update()
{
if (!areaIsDirty)
{
return;
}
areaIsDirty = false;
var physicalWidth = graphicsDevice.Viewport.Width;
var physicalHeight = graphicsDevice.Viewport.Height;
var physicalAspectRatio = graphicsDevice.Viewport.AspectRatio;
if ((int)(physicalAspectRatio * 10) == (int)(VirtualAspectRatio * 10))
{
area = new Rectangle(0, 0, physicalWidth, physicalHeight);
return;
}
if (VirtualAspectRatio > physicalAspectRatio)
{
var scaling = (float)physicalWidth / (float)VirtualWidth;
var width = (float)(VirtualWidth) * scaling;
var height = (float)(VirtualHeight) * scaling;
var borderSize = (int)((physicalHeight - height) / 2);
area = new Rectangle(0, borderSize, (int)width, (int)height);
}
else
{
var scaling = (float)physicalHeight / (float)VirtualHeight;
var width = (float)(VirtualWidth) * scaling;
var height = (float)(VirtualHeight) * scaling;
var borderSize = (int)((physicalWidth - width) / 2);
area = new Rectangle(borderSize, 0, (int)width, (int)height);
}
}
public void BeginCapture()
{
graphicsDevice.SetRenderTarget(screen);
}
public void EndCapture()
{
graphicsDevice.SetRenderTarget(null);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(screen, area, Color.White);
}
}
And then in my game, the initialisation tends look something like:
VirtualScreen virtualScreen;
protected override void Initialize()
{
virtualScreen = new VirtualScreen(96, 54, GraphicsDevice);
Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
Window.AllowUserResizing = true;
base.Initialize();
}
void Window_ClientSizeChanged(object sender, EventArgs e)
{
virtualScreen.PhysicalResolutionChanged();
}
With the all important call to Update:
protected override void Update(GameTime gameTime)
{
virtualScreen.Update();
base.Update(gameTime);
}
And then the act of drawing itself:
protected override void Draw(GameTime gameTime)
{
virtualScreen.BeginCapture();
GraphicsDevice.Clear(Color.CornflowerBlue);
// game rendering happens here...
virtualScreen.EndCapture();
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
virtualScreen.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
With this in place, I can basically stop caring about resolution at all and just focus on the game.
Using the RenderToTexture method you're talking about might be a good idea (plus it will be easier for you if you want to do post-process shaders).
Alternatively, you can set the Window's size, but your code will only work on a desktop.
You must add those 2 references in your project:
using System.Drawing;
using System.Windows.Forms;
And then in your Game class (i.e. in the Initialize method)
GraphicsDeviceManager.PreferredBackBufferWidth = 96;
GraphicsDeviceManager.PreferredBackBufferHeight = 54;
IntPtr ptr = this.Window.Handle;
Form form = (Form) Control.FromHandle(ptr);
form.Size = new Size(960, 540);