Isometric tile engine optimisation for better FPS - c#

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

Related

How should I return a list that was previously set without setting it again?

I have two classes, Main and Grid. Grid simply makes a grid of square pixels. In my Main class, I want to get the list that was create in the Grid class. I managed to figure it out, but I'm wondering if there's a way to optimize the code.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace teeeest
{
public class Grid
{
Texture2D image;
Color color;
int rows;
int columns;
float outerThickness;
float innerThickness;
Vector2 size;
Vector2 origin;
Vector2 dotSize;
List<Pixel> pixels = new List<Pixel>(0);
public Grid(Texture2D image, int rows, int columns, float outerThickness, float innerThickness, Vector2 size, Vector2 origin, Vector2 dotSize, Color color)
{
this.dotSize = dotSize;
this.origin = origin;
this.color = color;
this.image = image;
this.rows = rows;
this.columns = columns;
this.outerThickness = outerThickness;
this.innerThickness = innerThickness;
this.size = size;
}
public void Update()
{
float sizeX = size.X / (columns - 1);
float sizeY = size.Y / (rows - 1);
for (int i = 0; i < rows; i++)
{
for (int g = 0; g < columns; g++)
{
Pixel p = new Pixel(image, 3, new Vector2((g * sizeX) + origin.X, sizeY * i + origin.Y), new Vector2(image.Width / 2, image.Height / 2), color);
pixels.Add(p);
}
}
}
public virtual void Draw(SpriteBatch hspritebatch, List<Grid> grids)
{
foreach (Pixel p in pixels)
{
hspritebatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: new Vector2(image.Width / 2, image.Height),
scale: new Vector2(dotSize.X * .02f, dotSize.Y * .02f),
SpriteEffects.None,
0);
}
}
public Texture2D getImage()
{
return image;
}
public Vector2 getPosition()
{
return origin;
}
public Vector2 getOrigin()
{
return new Vector2(image.Width / 2, image.Height);
}
public Color getColor()
{
return color;
}
public List<Pixel> getList()
{
Update(); # This seems unnecessary. Is it?
return pixels;
}
}
}
The problem lies in the getList() function. In order to return the correct pixel list that was edited in the Update function, my solution there is to call that function right before returning the list. However, this seems costly for no reason. Is there a way around this without calling the Update function, or is this the only way?
I realize there's been posts similar to this, but I just don't understand them. I'm very much a beginner at coding. Here is my Main class.
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace teeeest
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private SpriteFont font;
private Texture2D ball;
private Texture2D square;
private Color color = Color.White * .1f;
private Vector2 MouseCoords;
private Vector2 winMiddle;
private Vector2 ballOrigin;
private bool leftDown;
private bool eDown;
private int winWidth;
private int winHeight;
List<Line> lines = new List<Line>(0);
List<Grid> grids = new List<Grid>(0);
List<Pixel> pixels = new List<Pixel>(0);
List<Pixel> test = new List<Pixel>(0);
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
ball = Content.Load<Texture2D>("ball");
square = Content.Load<Texture2D>("square");
font = Content.Load<SpriteFont>("File");
ballOrigin = new Vector2(ball.Width / 2, ball.Height / 2);
winWidth = _graphics.PreferredBackBufferWidth;
winHeight = _graphics.PreferredBackBufferHeight;
winMiddle = new Vector2(winWidth / 2, winHeight / 2);
}
protected override void Update(GameTime gameTime)
{
lines.Clear();
grids.Clear();
pixels.Clear();
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Mouse.GetState().LeftButton == ButtonState.Released)
{
leftDown = false;
}
if (Mouse.GetState().LeftButton == ButtonState.Pressed && !leftDown)
{
Pixel g = new Pixel(ball, 5, MouseCoords, new Vector2(ball.Width / 2, ball.Height / 2), Color.Blue);
pixels.Add(g);
}
if (Keyboard.GetState().IsKeyUp(Keys.E))
{
eDown = false;
}
if (Keyboard.GetState().IsKeyDown(Keys.E) && !eDown)
{
color *= 1.1f;
eDown = true;
}
MouseCoords = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
Grid q = new Grid(ball, 10, 10, 7, 3, new Vector2(500, 500), new Vector2(30, 30), new Vector2(.2f, .2f), Color.White);
grids.Add(q);
# Here is where I'm calling the getList() function.
System.Console.WriteLine(q.getList()[7].getPosition());
# Here is where I'm calling the getList() function.
foreach (Line s in lines)
{
s.Update();
}
foreach (Grid gh in grids)
{
gh.Update();
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
foreach (Line l in lines)
{
l.Draw(_spriteBatch, lines);
}
foreach (Grid g in grids)
{
g.Draw(_spriteBatch, grids);
}
foreach (Pixel p in pixels)
{
_spriteBatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: p.getOrigin(),
scale: new Vector2(.02f, .02f),
SpriteEffects.None,
0);
}
_spriteBatch.DrawString(font,
MouseCoords.ToString(),
new Vector2 (winWidth - 100, 10),
Color.White,
rotation: 0,
origin: new Vector2(0, 0),
scale: new Vector2(1, 1),
SpriteEffects.None,
0);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
You could only call Update() when the List is EMPTY?
public List<Pixel> getList()
{
if (pixels.Count == 0)
{
Update(); // now it only gets called when pixels is EMPTY
}
return pixels;
}
This type of check may need to be done in Update() as well if it can be called directly from other places so you don't end up with more Pixel instances in it than you were expecting.

Tilemap collision detection C# XNA

I am trying to make a very simple terraria-like game in C# XNA for a school project. I have very limited time otherwise I would probably have spent more time trying to figure this out myself. I created a tilemap but I just can't figure out how to make the tiles "solid" and not passable.
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 TileEngine {
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D character;
Vector2 cPosition;
Rectangle cBounds, t1Bounds;
List<Texture2D> tileTextures = new List<Texture2D>();
int[,] tileMap = new int[,]
{
{ 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
{ 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
{ 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
{ 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
};
int tileWidth = 64;
int tileHeight = 36;
int cameraPositionX = 0;
int cameraPositionY = 0;
int vSpeed = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
IsMouseVisible = true;
graphics.IsFullScreen = false;
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
graphics.ApplyChanges();
cPosition = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2 - 15, graphics.GraphicsDevice.Viewport.Height / 2 - 20);
cBounds = new Rectangle((int)(cPosition.X), (int)(cPosition.Y), character.Width, character.Height);
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D texture;
character = Content.Load<Texture2D>("Tiles/character");
texture = Content.Load<Texture2D>("Tiles/green");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/red");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/blue");
tileTextures.Add(texture);
cBounds = new Rectangle((int)(cPosition.X), (int)(cPosition.Y),
character.Width, character.Height);
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
KeyboardState keyState = Keyboard.GetState();
vSpeed += 1;
cameraPositionY += vSpeed;
if (keyState.IsKeyDown(Keys.Right))
cameraPositionX += 5;
if (keyState.IsKeyDown(Keys.Left))
cameraPositionX -= 5;
if (keyState.IsKeyDown(Keys.Space))
vSpeed = -15;
if (cBounds.Intersects(t1Bounds))
{
cameraPositionY = 0;
vSpeed = 0;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int tileMapWidth = tileMap.GetLength(1);
int tileMapHeight = tileMap.GetLength(0);
spriteBatch.Draw(character, cPosition, Color.White);
for (int x = 0; x < tileMapWidth; x++)
{
for (int y = 0; y < tileMapHeight; y++)
{
int textureIndex = tileMap[y, x];
Texture2D texture = tileTextures[textureIndex];
spriteBatch.Draw(
texture, t1Bounds =
new Rectangle(
320 + x * tileWidth - cameraPositionX,
540 + y * tileHeight - cameraPositionY,
tileWidth,
tileHeight),
Color.White);
}
}
spriteBatch.End();
base.Draw(gameTime);
}
} }
As you can see I tried to make Rectangles around all the sprites and detect when they intersect, but it doesn't seem to work. And even if I get the Rectangle-thing to work I just don't know what to do if they intersect. If I set the velocity to 0 then it will still slowly "fall" through the blocks as there is a default vertical acceleration.
First, you need to create a simple class for your tiles like this:
Class Tile
{
public int type; //Holds the ID to the specific texture.
public bool collision; //If true you should check for collision if the player is close.
public int health; //You probably need this since rock is harder to break then dirt.
}
Then create an array with Tiles. Now you have to check if the player is close to a collidable tile. You need a function that converts world space to tile space and put your player coordinates in it, check each frame for a couple of tiles around the player. If you check the complete map for collision your FPS will drop to .001, likewise for drawing all the tiles. Some pseudo code (already on tile level):
for (int y = player.y-4;y <= player.y+4;y++)
{ //If your player is just the size of a single tile then just -2/+2 will do. 9*9 is already an expensive 81 rectangles to check.
for (int x = player.x-4;x <= player.x+4;x++)
{
if (map[x,y].collision){
if (new Rectangle(x*tilewidth,y*tileheight,tilewidth,tileheight).intersects(player.rectangle)){
//Check farthest valid position and put player there
}}
}
}
The best thing to do is add in a newPosition property and before moving the player to this newPosition you have to check if the position is valid.
Other then that, if you do not have the time then the best advice is to not create a terraria like game. Even the simplest of terraria like game will be time consuming. Since you do not know the basics of collision i suggest making a pong or arkanoid clone that is pretty much how we all started out.

XNA C# Why is my string not drawing?

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.

whats wrong with using depth image for lighting

I want use a depth image to lighting a RawColor image but it not seems good
i want know whats wrong with my code , or its all depth image can do :|
the output image shape like Cone instead of circle and there are many noise on it , what i want to know is my code wrong or its not right way to do this?!
for that i get normal for each pixel and add it to a texture and send it to pixel shader to use for lighting. result image and code are added here
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D depth;
Texture2D image;
Texture2D texNormal;
Vector3 cameraPos = new Vector3(0.5f, 0.5f, -0.0999f);
Effect mEffect;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
graphics.PreferredBackBufferWidth = 1000;
graphics.PreferredBackBufferHeight = 1000;
graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
depth = Content.Load<Texture2D>("depth");
image = Content.Load<Texture2D>("image");
texNormal = getNormalFromDepth(depth);
mEffect = Content.Load<Effect>("depthEffect");
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
cameraPos.Y += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
cameraPos.Y -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
cameraPos.X -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.D))
{
cameraPos.X += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
cameraPos.Z += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
cameraPos.Z -= 0.01f;
}
// TODO: Add your update logic here
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.Textures[1] = texNormal;
mEffect.Parameters["LightPos"].SetValue(cameraPos);
// TODO: Add your drawing code here
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, mEffect);
spriteBatch.Draw(image, new Rectangle(0, 0, 500, 500), Color.White);
spriteBatch.End();
spriteBatch.Begin();
spriteBatch.Draw(texNormal, new Rectangle(500, 0, 500, 500), Color.White);
spriteBatch.Draw(image, new Rectangle(500, 500, 500, 500), Color.White);
spriteBatch.Draw(depth, new Rectangle(0, 500, 500, 500), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Texture2D getNormalFromDepth(Texture2D depth)
{
Texture2D output = new Texture2D(GraphicsDevice, depth.Width, depth.Height);
Color[] outbyte = new Color[depth.Width * depth.Height];
Color[] colors1D = new Color[depth.Width * depth.Height];
depth.GetData(colors1D);
Color[,] colors2D = new Color[depth.Width, depth.Height];
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
colors2D[x, y] = colors1D[x + y * depth.Width];
}
}
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
float left = GetHeight(colors2D, ref depth, x - 1, y);
float right = GetHeight(colors2D, ref depth, x + 1, y);
float top = GetHeight(colors2D, ref depth, x, y - 1);
float bottom = GetHeight(colors2D, ref depth, x, y + 1);
// Compute gradient vectors, then cross them to get the normal.
Vector3 dx = new Vector3(1, 0, (right - left) * 1);
Vector3 dy = new Vector3(0, 1, (bottom - top) * 1);
Vector3 normal = Vector3.Cross(dx, dy);
normal.Normalize();
// Store the result.
float alpha = colors2D[x, y].A;
outbyte[y * depth.Width + x] = new Color(new Vector4(normal, alpha));
}
}
output.SetData(outbyte);
return output;
}
float GetHeight(Color[,] depth, ref Texture2D depthImage, int x, int y)
{
if (x < 0)
{
x = 0;
}
else if (x >= depthImage.Width)
{
x = depthImage.Width - 1;
}
if (y < 0)
{
y = 0;
}
else if (y >= depthImage.Height)
{
y = depthImage.Height - 1;
}
Color mColor = (depth[x, y]);
float output = (mColor.R + mColor.G + mColor.B) / 3;
return output;
}
}
and shader Code is here
sampler normalSampler : register(s1);
sampler imageSampler : register(s0);
float3 LightPos = (1,0,-0.5);
float3 AmbientColor = (0.1,0.1,0.1);
float3 LightColor = (0.9,0.9,0.9);
float4 main(float4 color : COLOR0 ,float2 texCoord : TEXCOORD0):COLOR0
{
float4 output = float4(1,1,1,1);
float4 normal = tex2D(normalSampler,texCoord);
float4 imageColor = tex2D(imageSampler,texCoord);
float3 tex3DCoord = float3(texCoord.x,texCoord.y,0);
float3 lighting = AmbientColor;
float3 lightDir = (LightPos - tex3DCoord);
lighting += ( LightColor* max(dot(normal.xyz, lightDir), 0));
output = float4 (imageColor*lighting,1);
return output;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}
}

A Null Reference Exception

"Object reference not set to an instance of an object."
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace XNAdev
{
class Sprite
{
//The size of the Sprite
public Rectangle Size;
//Used to size the Sprite up or down from the original image
public float Scale = 1.0f;
//The current position of the Sprite
public Vector2 Position = new Vector2(115, 0);
//The texture object used when drawing the sprite
private Texture2D mSpriteTexture;
//Load the texture for the sprite using the Content Pipeline
public void LoadContent(ContentManager theContentManager, string theAssetName)
{
mSpriteTexture = theContentManager.Load<Texture2D>(theAssetName);
Size = new Rectangle(0, 0, (int)(mSpriteTexture.Width * Scale), (int)(mSpriteTexture.Height * Scale));
}
//Draw the sprite to the screen
public void Draw(SpriteBatch theSpriteBatch)
{
theSpriteBatch.Draw(mSpriteTexture, Position,
new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height), Color.White,
0.0f, Vector2.Zero, Scale, SpriteEffects.None, 0);
}
}
}
I am very new at this C# so any help would be great.
I have no idea what my error is.
namespace XNAdev
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Sprite mSprite;
Sprite mSpriteTwo;
Sprite mBackgroundOne;
Sprite mBackgroundTwo;
Sprite mBackgroundThree;
Sprite mBackgroundFour;
Sprite mBackgroundFive;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
mSprite = new Sprite();
mSpriteTwo = new Sprite();
mBackgroundOne = new Sprite();
mBackgroundOne.Scale = 2.0f;
mBackgroundTwo = new Sprite();
mBackgroundTwo.Scale = 2.0f;
mBackgroundThree = new Sprite();
mBackgroundThree.Scale = 2.0f;
mBackgroundFour = new Sprite();
mBackgroundFour.Scale = 2.0f;
mBackgroundFive = new Sprite();
mBackgroundFive.Scale = 2.0f;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
mSprite.Position = new Vector2(125, 245);
mSpriteTwo.LoadContent(this.Content, "SquareGuy");
mSpriteTwo.Position.X = 300;
mSpriteTwo.Position.Y = 300;
mBackgroundOne.LoadContent(this.Content, "Background01");
mBackgroundOne.Position = new Vector2(0, 0);
mBackgroundTwo.LoadContent(this.Content, "Background02");
mBackgroundTwo.Position = new Vector2(mBackgroundOne.Position.X + mBackgroundOne.Size.Width, 0);
mBackgroundThree.LoadContent(this.Content, "Background03");
mBackgroundThree.Position = new Vector2(mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width, 0);
mBackgroundFour.LoadContent(this.Content, "Background04");
mBackgroundFour.Position = new Vector2(mBackgroundThree.Position.X + mBackgroundThree.Size.Width, 0);
mBackgroundFive.LoadContent(this.Content, "Background05");
mBackgroundFive.Position = new Vector2(mBackgroundFour.Position.X + mBackgroundFour.Size.Width, 0);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (mBackgroundOne.Position.X < -mBackgroundOne.Size.Width)
{
mBackgroundOne.Position.X = mBackgroundFive.Position.X + mBackgroundFive.Size.Width;
}
if (mBackgroundTwo.Position.X < -mBackgroundTwo.Size.Width)
{
mBackgroundTwo.Position.X = mBackgroundOne.Position.X + mBackgroundOne.Size.Width;
}
if (mBackgroundThree.Position.X < -mBackgroundThree.Size.Width)
{
mBackgroundThree.Position.X = mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width;
}
if (mBackgroundFour.Position.X < -mBackgroundFour.Size.Width)
{
mBackgroundFour.Position.X = mBackgroundThree.Position.X + mBackgroundThree.Size.Width;
}
if (mBackgroundFive.Position.X < -mBackgroundFive.Size.Width)
{
mBackgroundFive.Position.X = mBackgroundFour.Position.X + mBackgroundFour.Size.Width;
}
Vector2 aDirection = new Vector2(-1, 0);
Vector2 aSpeed = new Vector2(160, 0);
mBackgroundOne.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
mBackgroundTwo.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
mBackgroundThree.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
mBackgroundFour.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
mBackgroundFive.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
mBackgroundOne.Draw(this.spriteBatch);
mBackgroundTwo.Draw(this.spriteBatch);
mBackgroundThree.Draw(this.spriteBatch);
mBackgroundFour.Draw(this.spriteBatch);
mBackgroundFive.Draw(this.spriteBatch);
mSprite.Draw(this.spriteBatch);
mSpriteTwo.Draw(this.spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Thats the rest of the code
Lookup how to set Visual Studio to break on exceptions.
Learn how to use the debugger so you can step through your code to see where the error occurs.
I've had a look through it and managed to get it to work using validation, if the sprite you are drawing has a null reference (No texture) it will ignore it and carry on drawing everything else.
Change your Draw() method in the Sprite.cs to this:
//Draw the sprite to the screen
public void Draw(SpriteBatch theSpriteBatch)
{
if (mSpriteTexture != null)
{
theSpriteBatch.Draw(mSpriteTexture, Position,
new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height), Color.White,
0.0f, Vector2.Zero, Scale, SpriteEffects.None, 0);
}
}
The problem occurs because you never give "Sprite mSprite;" a texture, only a position.
Quick snippet:
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
mSprite.Position = new Vector2(125, 245);
mSpriteTwo.LoadContent(this.Content, "SquareGuy");
mSpriteTwo.Position.X = 300;
mSpriteTwo.Position.Y = 300;
As you can see you only give mSprite a position of 125,245, simply assign it a texture like you have with the rest of the sprites and it will work fine.
You don't need to remove the if(mSpriteTexture != null) from the Draw() method after you assign the texture though, if you don't it simply means you won't notice if something isn't being assigned correctly, could be a pain if you're debugging something else later.
Probably you should check
mSpriteTexture = theContentManager.Load<Texture2D>(theAssetName);
if (mSpriteTexture != null)
Size = new Rectangle(0, 0, (int)(mSpriteTexture.Width * Scale), (int)(mSpriteTexture.Height * Scale));
And in the Draw function too.
This error means that one of the fields or methods of an object has been tried to be accessed without the object being instantiated.
For you code seems that this is happening with the object mSpriteTexture.
You should add
mSpriteTexture = new Texture2D();
somewhere, but I can not tell where only with this piece of code.

Categories