creating rectangles for each side of an object? - c#

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.

Related

XNA: ArgumentNullException when referencing value from a public class

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.

Operator '>' cannot be applied to operands of type 'int' and 'method group'

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)

Isometric tile engine optimisation for better FPS

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

Animating an array

currently trying to animate an array of enemy sprites for within a game I'm producing in C# using XNA 4.0
Using this animation code
namespace Rotationgame
{
class Animation
{
Texture2D texture;
Rectangle rectangle;
Vector2 position;
Vector2 origin;
Vector2 velocity;
int currentFrame;
int frameHeight;
int frameWidth;
float timer;
float interval = 150;
public Animation(Texture2D newTexture, Vector2 newPosition, int newFrameHeight, int newFrameWidth)
{
texture = newTexture;
position = newPosition;
frameHeight = newFrameHeight;
frameWidth = newFrameWidth;
}
public void Update(GameTime gameTime)
{
rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
origin = new Vector2(rectangle.Width / 2, rectangle.Height / 2);
position = position + velocity;
if (Keyboard.GetState().IsKeyUp(Keys.F1))
{
AnimateRight(gameTime);
velocity.X = 0;
}
else if (Keyboard.GetState().IsKeyUp(Keys.F2))
{
AnimateLeft(gameTime);
velocity.X = -0;
}
else velocity = Vector2.Zero;
}
public void AnimateRight(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
if (timer > interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 1)
currentFrame = 0;
}
}
public void AnimateLeft(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
if (timer > interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 1)
currentFrame = 0;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, rectangle, Color.White, 0f, origin, 1.0f, SpriteEffects.None, 0);
}
}
}
And this code for the array
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Animation[] invaders;
protected override void Initialize()
{
invaders = new Animation[13];
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// Array of Space Invaders
invaders[0] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(400, 400), 115, 96);
invaders[1] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(427, 310), 115, 96);
invaders[2] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(427, 490), 115, 96);
invaders[3] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(490, 250), 115, 96);
invaders[4] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(490, 550), 115, 96);
invaders[5] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(580, 240), 115, 96);
invaders[7] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(580, 560), 115, 96);
invaders[8] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(670, 550), 115, 96);
invaders[9] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(670, 250), 115, 96);
invaders[10] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(730, 490), 115, 96);
invaders[11] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(730, 310), 115, 96);
invaders[12] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(757, 400), 115, 96);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// Drawing Invaders
foreach (Animation invader in invaders)
invaders.Draw(spriteBatch);
}
spriteBatch.End();
Everything works in the code in visual Studio however I get a error on the Draw method saying: "Error 1 'System.Array' does not contain a definition for 'Draw' and no extension method 'Draw' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)"
Any ideas what's gone wrong?
Edit: Here is full code of game1 file
namespace Rotationgame
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Animation[] invaders;
// Different Windows
enum GameState
{
MainMenu,
Playing,
}
GameState CurrentGameState = GameState.MainMenu;
// Screeb Adjustments
int screenWidth = 1250, screenHeight = 930;
// Main Menu Buttons
button btnPlay;
button btnQuit;
// Pause Menu & buttons
bool paused = false;
button btnResume;
button btnMainMenu;
// Player's Movement
Vector2 spriteVelocity;
const float tangentialVelocity = 0f;
float friction = 1f;
Texture2D spriteTexture;
Rectangle spriteRectangle;
Vector2 spritePosition;
float rotation;
// The centre of the image
Vector2 spriteOrigin;
// Background
Texture2D backgroundTexture;
Rectangle backgroundRectangle;
// Shield
Texture2D shieldTexture;
Rectangle shieldRectangle;
// Bullets
List<Bullets> bullets = new List<Bullets>();
KeyboardState pastKey;
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()
{
invaders = new Animation[12];
// 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);
// Load Player's Shield (Cosmetic at moment as not set up fully
shieldTexture = Content.Load<Texture2D>("Shield");
shieldRectangle = new Rectangle(517, 345, 250, 220);
// Load Player's Ship
spriteTexture = Content.Load<Texture2D>("PlayerShipright");
spritePosition = new Vector2(640, 450);
// Load Game background
backgroundTexture = Content.Load<Texture2D>("Background");
backgroundRectangle = new Rectangle(0, 0, 1250, 930);
// Screen Adjustments
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
graphics.ApplyChanges();
IsMouseVisible = true;
// Main menu Buttons & locations
btnPlay = new button(Content.Load<Texture2D>("Playbutton"), graphics.GraphicsDevice);
btnPlay.setPosition(new Vector2(550, 310));
btnQuit = new button(Content.Load<Texture2D>("Quitbutton"), graphics.GraphicsDevice);
btnQuit.setPosition(new Vector2(550, 580));
// Array of Space Invaders
invaders[0] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(400, 400), 115, 96);
invaders[1] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(427, 310), 115, 96);
invaders[2] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(427, 490), 115, 96);
invaders[3] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(490, 250), 115, 96);
invaders[4] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(490, 550), 115, 96);
invaders[5] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(580, 240), 115, 96);
invaders[6] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(580, 560), 115, 96);
invaders[7] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(670, 550), 115, 96);
invaders[8] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(670, 250), 115, 96);
invaders[9] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(730, 490), 115, 96);
invaders[10] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(730, 310), 115, 96);
invaders[11] = new Animation(Content.Load<Texture2D>("SpaceInvaderbefore"), new Vector2(757, 400), 115, 96);
// Pause menu buttons & locations
btnResume = new button(Content.Load<Texture2D>("Playbutton"), graphics.GraphicsDevice);
btnResume.setPosition(new Vector2(550, 310));
btnMainMenu = new button(Content.Load<Texture2D>("Quitbutton"), graphics.GraphicsDevice);
btnMainMenu.setPosition(new Vector2(550, 580));
// 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)
{
MouseState mouse = Mouse.GetState();
// Allows the game to exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
switch (CurrentGameState)
{
case GameState.MainMenu:
if(btnPlay.isClicked == true) CurrentGameState = GameState.Playing;
btnPlay.Update(mouse);
if (btnQuit.isClicked == true)
this.Exit();
btnQuit.Update(mouse);
break;
case GameState.Playing:
if (!paused)
{
if (Keyboard.GetState().IsKeyDown(Keys.Enter))
{
paused = true;
btnResume.isClicked = false;
}
}
else if (paused)
{
if (Keyboard.GetState().IsKeyDown(Keys.Enter))
if (btnResume.isClicked)
paused = false;
if (btnMainMenu.isClicked) CurrentGameState = GameState.MainMenu;
}
break;
}
// TODO: Add your update logic here
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space))
Shoot();
pastKey = Keyboard.GetState();
spritePosition = spriteVelocity + spritePosition;
spriteRectangle = new Rectangle((int)spritePosition.X, (int)spritePosition.Y,
spriteTexture.Width, spriteTexture.Height);
spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2);
if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if (Vector2.Zero != spriteVelocity)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
base.Update(gameTime);
}
UpdateBullets();
}
public void UpdateBullets()
{
foreach (Bullets bullet in bullets)
{
bullet.position += bullet.velocity;
if (Vector2.Distance(bullet.position, spritePosition) > 760)
bullet.isVisible = false;
}
for (int i = 0; i < bullets.Count; i++)
{
if(!bullets[i].isVisible)
{
bullets.RemoveAt(i);
i--;
}
}
}
public void Shoot()
{
Bullets newBullet = new Bullets(Content.Load<Texture2D>("bullet"));
newBullet.velocity = new Vector2((float)Math.Cos(rotation),(float)Math.Sin(rotation)) * 3f + spriteVelocity;
newBullet.position = spritePosition + newBullet.velocity * 5;
newBullet.isVisible = true;
if(bullets.Count() < 25)
bullets.Add(newBullet);
}
/// <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 (CurrentGameState)
{
case GameState.MainMenu:
spriteBatch.Draw(Content.Load<Texture2D>("MainMenu"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
btnPlay.Draw(spriteBatch);
btnQuit.Draw(spriteBatch);
break;
case GameState.Playing:
// Drawing Background
spriteBatch.Draw(backgroundTexture, backgroundRectangle, Color.White);
// Drawing Shield
spriteBatch.Draw(shieldTexture, shieldRectangle, Color.White);
// Drawing Invaders
foreach (Animation invader in invaders)
invader.Draw(spriteBatch);
// Drawing Bullets
foreach (Bullets bullet in bullets)
bullet.Draw(spriteBatch);
// Drawing Player's Character
spriteBatch.Draw(spriteTexture, spritePosition, null, Color.White, rotation, spriteOrigin, 1f, SpriteEffects.None, 0);
if (paused)
{
spriteBatch.Draw(Content.Load<Texture2D>("PauseMenu"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
btnResume.Draw(spriteBatch);
btnMainMenu.Draw(spriteBatch);
}
break;
}
spriteBatch.End();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}
2nd Edit: Button class
namespace Rotationgame
{
class button
{
Texture2D texture;
Vector2 position;
Rectangle rectangle;
Color colour = new Color(255, 255, 255, 255);
public Vector2 size;
public button(Texture2D newTexture, GraphicsDevice graphics)
{
texture = newTexture;
// ScreenW = 1250 (currently atm 800), ScreenH = 930 (currently atm 600)
//ImgW = 100 , ImgH = 20
size = new Vector2(graphics.Viewport.Width / 8, graphics.Viewport.Height / 30);
}
bool down;
public bool isClicked;
public void Update(MouseState mouse)
{
rectangle = new Rectangle((int)position.X,(int)position.Y,
(int)size.X, (int)size.Y);
Rectangle mouseRectangle = new Rectangle(mouse.X, mouse.Y, 1, 1);
if (mouseRectangle.Intersects(rectangle))
{
if (colour.A == 255) down = false;
if (colour.A == 0) down = true;
if (down) colour.A += 3; else colour.A -= 3;
if (mouse.LeftButton == ButtonState.Pressed) isClicked = true;
}
else if (colour.A < 255)
{
colour.A += 3;
isClicked = false;
}
}
public void setPosition(Vector2 newPosition)
{
position = newPosition;
}
public void Draw(SpriteBatch spritebatch)
{
spritebatch.Draw(texture, rectangle, colour);
}
}
}
C# has wonderful library of collection classes to replace list. I highly discourage to use Array as it is not flexible enough. If you are writing code specifically for low end hardware and knowing in and out of code and managing every bit of it than and only then go for array.
But I like the way you structured classes. It is pretty good. Now, if you have list then you can add any number of class at any moment of time. You don't have to decide above time how to do that.
Now, that class has collection of Rectangles which gives the position of sprite in your sprite collection, then you just need to use the in draw method with your animation logic. Which you already have.
And one more thing, There is no need to add
Content.Load<Texture2D>("SpaceInvaderbefore")
multiple time. Instead store it to variable and use it.
With this here is the line of two wonderful article. 1 and 2. Which provide details about how to do animation with XNA.
And there is must have course of Plural Sight for game development. You can also try that.
I hope my answer helps you. please let me know if any further details required.

Smooth fadeout/transition between 2 textures in XNA WP7

I have 2 textures 800x480 (foreground/backgound) which are .png files in XNA Windows Phone 7 application.
I want to fadeout/transision foreground to reveal background. I have huge problem with performance. My idea is only to maipulate Alpha channel in one Texture2D so i created such a code:
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
private Texture2D _background, _foreground;
private BlendState _blendState;
private uint[] _pixelsForeground;
private uint[] _pixelsBackground;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
TargetElapsedTime = TimeSpan.FromTicks(333333);
graphics.IsFullScreen = true;
graphics.SupportedOrientations = DisplayOrientation.Portrait;
graphics.PreferredBackBufferHeight = 840;
graphics.PreferredBackBufferWidth = 480;
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
_background = this.Content.Load<Texture2D>(#"background");
_foreground = this.Content.Load<Texture2D>(#"foreground");
_pixelsForeground = new uint[_foreground.Width * _foreground.Height];
_pixelsBackground = new uint[_foreground.Width * _foreground.Height];
_background.GetData(_pixelsBackground);
_foreground.GetData(_pixelsForeground);
_blendState = new BlendState
{
AlphaBlendFunction = BlendFunction.Add,
ColorBlendFunction = BlendFunction.Add,
AlphaSourceBlend = Blend.SourceAlpha,
ColorSourceBlend = Blend.SourceAlpha,
AlphaDestinationBlend = Blend.InverseSourceAlpha,
ColorDestinationBlend = Blend.InverseSourceAlpha
};
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
this.GraphicsDevice.Textures[0] = null;
for (int x = 0; x < _foreground.Width; x++)
{
for (int y = 0; y < _foreground.Height; y++)
{
uint pixelCanvas = _pixelsForeground[y * _foreground.Width + x];
uint newPixelCanvas = pixelCanvas - 0x05000000;
_pixelsForeground[y*_foreground.Width + x] = newPixelCanvas;
_pixelsForeground[y * _foreground.Width + x] = (newPixelCanvas & 0xFF000000) > (pixelCanvas & 0xFF000000)
? pixelCanvas & 0x00FFFFFF
: newPixelCanvas;
}
}
Rectangle rect = new Rectangle(0, 0, _foreground.Width, _foreground.Height);
_foreground.SetData<uint>(0, rect, _pixelsForeground, 0, _foreground.Height * _foreground.Width);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.FrontToBack, _blendState);
spriteBatch.Draw(_foreground, Vector2.One, null, Color.White);
spriteBatch.Draw(_background, Vector2.One, null, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Problem is that it generates poor performance because of:
_foreground.SetData<uint>(...)
What technique I can use to manage this better?
I'd rather need that manipulation of Alpha channel for other purposes.
Keep in mind that foreground pixels can have different alpha channel already on start something like transparent spots.
This is definitely the wrong way to approach this. What you want to do is pass a Color to the sprite batch's Draw method that has the appropriate alpha channel.
int alpha = 150;
spriteBatch.Draw(tex, pos, new Color(255,255,255,alpha));
That way, the GPU handles the alpha blending on your behalf, and your performance issues dissapear :-)

Categories