Smooth fadeout/transition between 2 textures in XNA WP7 - c#

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 :-)

Related

Models appear black in XNA

Ive been trying to draw a simple cube in xna but its showing up completely black. Ive tried multiple diffirent FBX models. Played around with the settings for the models in the pipeline. Ive also to apply basic lightning in every way possible. Its still appearing black.
My code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
namespace Game1
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
BasicEffect effect;
Texture2D floor;
Model model;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
effect = new BasicEffect(graphics.GraphicsDevice);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
floor = Content.Load<Texture2D>("floor");
model = Content.Load<Model>("cube");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
var cameraPosition = new Vector3((float)Math.Cos((double)gameTime.TotalGameTime.TotalMilliseconds/1000)*20, 40, (float)Math.Cos((double)gameTime.TotalGameTime.TotalMilliseconds / 1000) * 20);
var cameraLookAtVector = Vector3.Zero;
var cameraUpVector = Vector3.UnitZ;
effect.View = Matrix.CreateLookAt(
cameraPosition, cameraLookAtVector, cameraUpVector);
float aspectRatio =
graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
float nearClipPlane = 1;
float farClipPlane = 200;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
fieldOfView, aspectRatio, nearClipPlane, farClipPlane);
effect.TextureEnabled = true;
effect.Texture = floor;
drawModel(model, effect.World, effect.View, effect.Projection);
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
drawQuad(new Vector3[] {
new Vector3(20,-20,0),
new Vector3(-20,-20,0),
new Vector3(-20,20,0),
new Vector3(20,20,0),
},2f);
}
base.Draw(gameTime);
}
public void drawQuad(Vector3[] p, float tiling)
{
VertexPositionNormalTexture[] verts = new VertexPositionNormalTexture[6];
verts[0].Position = p[0];
verts[1].Position = p[1];
verts[2].Position = p[3];
verts[3].Position = p[1];
verts[4].Position = p[2];
verts[5].Position = p[3];
verts[0].Normal = p[0];
verts[1].Normal = p[1];
verts[2].Normal = p[3];
verts[3].Normal = p[1];
verts[4].Normal = p[2];
verts[5].Normal = p[3];
verts[0].TextureCoordinate = new Vector2(0, 0);
verts[1].TextureCoordinate = new Vector2(0, tiling);
verts[2].TextureCoordinate = new Vector2(tiling, 0);
verts[3].TextureCoordinate = verts[1].TextureCoordinate;
verts[4].TextureCoordinate = new Vector2(tiling, tiling);
verts[5].TextureCoordinate = verts[2].TextureCoordinate;
graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, 2);
}
public void drawModel(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (var mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.DiffuseColor = Color.White.ToVector3();
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
}
}
FBX doesn't embed textures in the model file itself, it just stores a path to the texture file. This path is usually relative to the export location (but it depends on the tool).
Try placing the texture file in the same relative path as it was with the export location, but in the output directory of the executable. Otherwise, FBX files are human readable IIRC, so you should be able to determine where it is looking for the texture, and put it there.

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.

creating rectangles for each side of an object?

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.

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

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