XNA C# Why is my string not drawing? - c#

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.

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.

I need to fix this Tile bug in XNA

I am currently creating a space shooter game. To this game I want a background with stars that keeps looping for eternity.
In order to create this, I made a tile based system that simply creates a rectangle for each texture. I have been able to make said textures kinda loop, but when they do I get a really weird bug.
As you can see, my tiles are sometimes generating a small gap between each other, and I am not sure as of why.
The problem probably lies within my Background.cs file, but I am unsure of where.
Also, I would like a better name for "Background.cs". Do you think that something like "Tile.cs" is better?
Background.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace SpaceShooter
{
class Background
{
public Texture2D texture;
public List<Rectangle> tiles = new List<Rectangle>();
public Color color;
public int tileSize;
public int speed;
GraphicsDevice graphicsDevice;
public Background(Texture2D texture, GraphicsDevice graphicsDevice, int tileSize)
{
this.texture = texture;
this.graphicsDevice = graphicsDevice;
this.tileSize = tileSize;
speed = 3;
this.color = Color.White;
CalculateTiles();
}
public void Update()
{
for (int i = 0; i < tiles.Count(); i++)
{
tiles[i] = new Rectangle(tiles[i].X, tiles[i].Y + speed, tiles[i].Width, tiles[i].Height);
if (tiles[i].Y >= graphicsDevice.Viewport.Height)
{
tiles[i] = new Rectangle(tiles[i].X, 0 - tiles[i].Height, tiles[i].Width, tiles[i].Height);
}
}
}
public void CalculateTiles()
{
if (tiles.Count() > 0)
{
for (int i = 0; i < tiles.Count(); i++)
{
tiles.Remove(tiles[i]);
}
}
int XT = (int)(graphicsDevice.Viewport.Width / (tileSize / 1.5f));
int YT = (int)(graphicsDevice.Viewport.Height / (tileSize / 1.5f));
for (int i = 0; i < XT; i++)
{
tiles.Add(new Rectangle(tileSize * i, 0, tileSize, tileSize));
for (int j = 0; j < YT; j++)
{
tiles.Add(new Rectangle(tileSize * i, tileSize * j, tileSize, tileSize));
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
for (int i = 0; i < tiles.Count(); i++)
{
spriteBatch.Draw(texture, tiles[i], color);
}
}
}
}
Game.cs
public class Game1 : Microsoft.Xna.Framework.Game
{
Background background;
protected override void LoadContent()
{
// Assign Background
background = new Background(Content.Load<Texture2D>("Stars"),GraphicsDevice, 128);
}
protected override void Update(GameTime gameTime)
{
if(Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
this.Exit();
background.Update();
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(bgc);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
// Call all drawing functions here
background.Draw(spriteBatch);
player1.Draw(spriteBatch);
player2.Draw(spriteBatch);
//
spriteBatch.End();
base.Draw(gameTime);
}
I think your problem can be easily solved with LinearWrap
if you do the following in your Game1.draw.
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap);
background.Draw(spriteBatch);
spriteBatch.End();
to get the scale simply do this calculation:
float scale = 128 / 512; // Where 128 is your desired size. and 512 your actual texture size.
and in your Background.cs draw method.
spriteBatch.Draw(texture, new Vector2(0,0), new Rectangle(pos.X, pos.Y, graphicsDevice.Viewport.Width / scale, graphicsDevice.Viewport.Height / scale), Color.White, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
this should repeat your texture over the entire screen.
EDIT:
To make the image dynamic you could use a Camera. But using the system you have you would simply on Update do this :
pos += new Vector2(movementX, movementY);
Note that the spriteBatch.Draw has a parameter "Source Rectangle". If you change the position of this rectangle your texture will shift.
The problem has been solved.
I am now putting the tile up relative to the screen height instead of raw programming it to 0.
if (tiles[i].Y >= graphicsDevice.Viewport.Height)
{
tiles[i] = new Rectangle(tiles[i].X, tiles[i].Y - graphicsDevice.Viewport.Height - tiles[i].Height, tiles[i].Width, tiles[i].Height);
}

Detect collision with Sprite-Sheet animation

How detect collision with sprite animation?
SpriteManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.IO;
namespace Mini
{
public class SpriteManager
{
protected Texture2D Texture;
public Vector2 Position = Vector2.Zero;
protected Dictionary<string, AnimationClass> Animations =
new Dictionary<string, AnimationClass>();
protected int FrameIndex = 0;
protected Vector2 Origin;
private int height;
private int width;
private string animation;
public string Animation
{
get { return animation; }
set
{
animation = value;
FrameIndex = 0;
}
}
public int Height
{
get { return height; }
}
public int Width
{
get { return width; }
}
public Rectangle Rectangle
{
get { return Animations[Animation].Rectangles[FrameIndex]; }
}
public Texture2D Texture2D
{
get { return Texture; }
}
public SpriteManager(Texture2D Texture, int Frames, int animations)
{
this.Texture = Texture;
width = Texture.Width / Frames;
height = Texture.Height / animations;
Origin = new Vector2(width / 2, height / 2);
}
public void AddAnimation(string name, int row,
int frames, AnimationClass animation)
{
Rectangle[] recs = new Rectangle[frames];
Color[][] frameImageData = new Color[frames][];
Texture2D[][] frameImage = new Texture2D[frames][];
for (int i = 0; i < frames; i++)
{
recs[i] = new Rectangle(i * width,
(row - 1) * height, width, height);
frameImageData[i] = new Color[width * height];
}
animation.Frames = frames;
animation.Rectangles = recs;
Animations.Add(name, animation);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position,
Animations[Animation].Rectangles[FrameIndex],
Animations[Animation].Color,
Animations[Animation].Rotation, Origin,
Animations[Animation].Scale,
Animations[Animation].SpriteEffect, 0f);
}
public bool IntersectPixels(SpriteManager b)
{
Rectangle rectangleA = this.Rectangle;
Rectangle rectangleB = b.Rectangle;
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
Color[] dataA = new Color[rectangleA.Width * rectangleA.Height];
this.Texture.GetData(0, rectangleA, dataA, 0, rectangleA.Width * rectangleA.Height);
Color[] dataB = new Color[rectangleB.Width * rectangleB.Height];
b.Texture.GetData(0, rectangleB, dataB, 0, b.Width * b.Height);
Stream s = File.Create("t.png");
b.Texture2D.SaveAsPng(s, rectangleB.Width, rectangleB.Height);
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
if (colorA.A != 0 && colorB.A != 0)
{
return true;
}
}
}
return false;
}
}
}
With this code, the collision is detected every few frames of animation anywhere
IntersectPixels is to detect collisions.

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

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();
}
}

Categories