Timer drawing on top of itself, Not clearing - c#

Interesting problem! Basically I have a timer for my UI that counts down from 99. Everything works fine save for the fact its drawing the new time on top of the old time. (The previous time is not clearing) There is a clear happening within the GameplayScreens draw call though... its just weird.
Here are my related functions:
GameplayScreen.cs (or our usual Game1)
public override void Update(GameTime gameTime)
{
m_GameUI.Update(gameTime);
m_GameCam.lookAt(m_Hero.Position);//feeds the camera's lookAt function the players vector2 position
m_GameUI.lookAt(m_GameCam.Position); //Look at the camera's position :D
}
public override void Draw(GameTime gameTime)
{
ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
Color.CornflowerBlue, 0, 0);
SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
m_BackgroundManager.Draw(spriteBatch, m_GameCam);
//Begin the Spritebatch Drawing
spriteBatch.Begin(SpriteSortMode.Immediate, null,
null,
null,
null,
null, m_GameCam.ViewMatrix);
//Call EntityManager.DrawAllEntities()
EntityManager.Instance.DrawAllEntities(gameTime, spriteBatch);
//End the spritebatch drawing
spriteBatch.End();
spriteBatch.Begin();
m_GameUI.Draw(gameTime, spriteBatch);
m_PlayerUI.Draw(gameTime, spriteBatch);
spriteBatch.End();
}
GameUI.cs
SpriteFont m_Font;
double m_Timer;
public virtual void Update(GameTime gameTime)
{
m_Timer -= gameTime.ElapsedGameTime.TotalSeconds;
}
public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(UITexture, Position, Color.White);
spriteBatch.DrawString(m_Font, "" + (int)m_Timer + "", new Vector2(380, 45), Color.White);
}

Ended up being a really silly mistake, I had a class deriving from the UI that was calling base.draw() so both the updated clock and the original value were being displayed on the screen at once. Basically poor code design, everyone is a newbie when they start out right?
Thanks for looking into it :)

Related

Why do games sometimes skip frames in monogame/xna?

This is a simple project created from MonoGame Cross-Platform Desktop template. I created a ball Texture2D and tried to make it move.So I added some code to the Update function.
position.X += 3;
And then in the Draw function
_spriteBatch.Begin();
_spriteBatch.Draw(ballTexture, position, Color.White);
_spriteBatch.End();
I can see the ball flashing sometimes.
Why is that and what can I do to make it not skip frames?
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace SimpleTest
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private Texture2D dirtTexture;
private Vector2 position;
private int direction = 1;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
dirtTexture = Content.Load<Texture2D>("dirt");
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// TODO: Add your update logic here
base.Update(gameTime);
if (position.X > 600)
direction = -1;
else if (position.X < 100)
direction = 1;
position.X = position.X + direction * 3;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
_spriteBatch.Begin();
_spriteBatch.Draw(dirtTexture, position, Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
I think base.Update(gameTime); should only be placed at the very end of the Update() Method, Just like base.Draw(gameTime);. That way it won't skip any lines.
I guess your PC might be running slowly which is the problem, and not your code. To test it, you can replace your Draw method as follows:
protected override void Draw(GameTime gameTime)
{
Color color=gameTime.IsRunningSlowly?Color.Red:Color.CornflowerBlue;
GraphicsDevice.Clear(color);
// TODO: Add your drawing code here
_spriteBatch.Begin();
_spriteBatch.Draw(dirtTexture, position, Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
Everything is the same, except now we are colouring the screen as Red instead of the usual blue only if the game is in fact running slow (Which is due to your PC). We can know this by the gameTime variable as shown in the first two lines of the method. Test it out and see if you can see the game background going red when the "frame-skipping" happens.
I did test your exact code in my PC and it was working fine. Needless to say, I did use some other png I had instead of the "dirt" Texture2D you used but I don't think that it should be necessary.
Perhaps it's due to GC. You could use my -almost- garbage free build to verify.
You can install the updated SDK from here or the nuget package.

Moving Draw() code to a Class

I'm creating a game in monogame, and I've loaded tiles in my game inside the Draw() function like so:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(danChar, charPosition, Color.White);
// loop below loads the 'grass' tiles only
// assuming gameworld size of 770x450
for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
{
position = new Vector2(i, 392); // places incrementation into vector position
spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
if (i == 744)
{
i = i + 26; // fills last space between 744 and 770
position = new Vector2(i, 392);
}
spriteBatch.Draw(gameTile, position, Color.White);
}
// loop below loads the brick tiles only (ones without grass)
spriteBatch.End(); // ends the spriteBatch call
base.Draw(gameTime);
}
However I would prefer that this was a separate class rather than being placed directly into the draw function, however I'm not too sure how to do this and would appreciate any help given.
Thanks in advance!
If you just want to move the code as is to another class, create your class (e.g. something like GameWorld seems to appropriate for your code)
public class GameWorld
{
// You may wish to move your gameTile definition into this class if it is the only
// class that uses it, and handle the content loading for it in here.
// e.g. if you're currently loading the texture in the LoadContent method in your game
// class, create a LoadContent method here and pass in ContentManger as a parameter.
// I've passed in the texture as a parameter to the Draw method in this example to
// simplify as I'm not sure how you're managing your textures.
public void Draw(SpriteBatch spriteBatch, GameTime gameTime, Texture2D gameTile)
{
// loop below loads the 'grass' tiles only
// assuming gameworld size of 770x450
for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
{
Vector2 position = new Vector2(i, 392); // places incrementation into vector position
spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
if (i == 744)
{
i = i + 26; // fills last space between 744 and 770
position = new Vector2(i, 392);
}
spriteBatch.Draw(gameTile, position, Color.White);
}
// loop below loads the brick tiles only (ones without grass)
}
}
Then the Draw method in your Game class would look like
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(danChar, charPosition, Color.White);
// Assuming you've created/loaded an instance of the GameWorld class
// called gameWorld in Initialize/LoadContent
gameWorld.Draw(spriteBatch, gameTime, gameTile);
spriteBatch.End(); // ends the spriteBatch call
base.Draw(gameTime);
}
Just make sure you're calling the Draw methods in the correct order. e.g. you want your player to appear above any background tiles.
I believe the default SpriteSortMode is Deferred which draws in the order the calls are made (i.e. from the back to the front).
You can specify a different SpriteSortMode in your call to spriteBatch.Begin() if you need to but for a simple game just move the Draw calls around.
More info on SpriteSortMode at MSDN if needed.
Similarly you can chain your Update, LoadContent methods into these classes if you wish, making sure to pass in anything you need as arguments.
Update:
To define gameWorld as an instance of the GameWorld class, you define it near the top of your game class, then typically initialize it in the Initialize method.
So your game class will look something like
public class MyGameName : Microsoft.Xna.Framework.Game
{
private SpriteBatch spriteBatch;
// other variable declarations
// Add a declaration for gameWorld
private GameWorld gameWorld;
protected override Initialize()
{
// Add the following line to initialize your gameWorld instance
gameWorld = new GameWorld();
}
// other existing code - your LoadContent, Update, Draw methods etc.
}

Redraw only one texture, not all of them

I'm a little noob with XNA and I've encountered a problem. I have one texture called "dot", that I use to draw a line across the screen. Then I have a texture that I call "tool", that I want to move around when I touch it with my finger. The problem I have is that for the tool to be cleared and redrawn I call the graphicsDevice.Clear-method in XNA. But when I do that, my lines also disappears. So my question is how can i move around the tool, without causing my lines to disappear? Is there a way to only redraw the tool, without redrawing the lines? Heres a snippet of my code, first update-method:
protected override void Update (GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
TouchCollection touchCollection = TouchPanel.GetState ();
foreach (TouchLocation tl in touchCollection) {
if ((tl.State == TouchLocationState.Pressed) || (tl.State == TouchLocationState.Moved)) {
toolPos = touchCollection [0].Position;
}
}
base.Update (gameTime);
}
And the draw-method:
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.Black);
newVector = nextVector (oldVector);
spriteBatch.Begin ();
DrawEvenlySpacedSprites (dot, oldVector, newVector, 0.9f);
spriteBatch.Draw (tool, toolPos, Color.White);
spriteBatch.End ();
oldVector = new Vector2 (newVector.X, newVector.Y);
base.Draw (gameTime);
}
Try using a RenderTarget2D with RenderTargetUsage.PreserveContents. If you didn't use render targets yet, here's a tutorial: http://rbwhitaker.wikidot.com/render-to-texture
All you have to do is to specify RenderTargetUsage.PreserveContents in target's constructor, draw dots to it, and draw the target and tool to the screen. It should look like this:
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.Black);
newVector = nextVector (oldVector);
GraphicsDevice.SetRenderTarget(renderTarget);
spriteBatch.Begin ();
DrawEvenlySpacedSprites (dot, oldVector, newVector, 0.9f);
spriteBatch.End ();
GraphicsDevice.SetRenderTarget(null);
spriteBatch.Begin();
spriteBatch.Draw(renderTarget, new Vector2(), Color.White);
spriteBatch.Draw (tool, toolPos, Color.White);
spriteBatch.End()
oldVector = new Vector2 (newVector.X, newVector.Y);
base.Draw (gameTime);
}

Drawing a loading screen with percentage, when loading means Drawing a lot of things

In my XNA game I need, at the beginning, to load some image and then Draw a lot of images to be used later in the game. I wanted to draw a loader that shows the progress, but I faced the problem that I can't draw while another spritebatch is already drawing.
It is something like:
I trait this as a thread:
public void DrawCache
{
progress = 0; // I can get this variable from outside
foreach (SpriteToBeCached in AllSprites)
{
graphicsDevice.SetRenderTarget(SpriteToBeCached.MyCachedTexture);
spriteBatch.Begin();
spriteBatch.Draw( ... );
spriteBatch.End();
graphicsDevice.SetRenderTarget(null);
++progress;
}
}
The Update menu state:
...
if (!loading)
{
var loading_thread = new Thread(DrawCache);
loading = false;
}
...
The Draw menu state:
...
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.DrawString(font, progress, position, Color.White);
spriteBatch.End();
...
How can I solve this?

Xna draw order not working right

I have an 2d array of Texture2D, it holds the different parts of the map in this array. I have a problem though, when I run the game, the map is drawn correctly but for some reason the array[0, 0] texture overlaps all my textures including my player texture and mouse texture. Every other texture works as my mouse and player texture correctly overlaps the map.
I'm really confused right now as the map textures are being drawn together using a nested for loop.
Here is my draw method for my map which I call in the Game's Draw method:
public void Draw()
{
// Draws the Map from a 2D Array
for (int row = 0; row < mapTexture.GetLength(0); row++)
{
for (int col = 0; col < mapTexture.GetLength(1); col++)
{
spriteBatch.Draw(mapTexture[row, col], mapPosition[row, col], Color.White);
}//end for
}//end for
}//end Draw()
My actual draw method:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(mouseIcon, mouseIconPosition, Color.White);
player.Draw();
map.Draw();
spriteBatch.End();
base.Draw(gameTime);
}//end Draw()
Try inverting the order that they're drawn, AND use SpriteSortMode.Deferred
You can try use overloaded SpriteBatch.Draw method with depth. As example:
SpriteBatch.Draw (Texture2D, Vector2, Nullable, Color, Single, Vector2, Single, SpriteEffects, Single) Adds a sprite to the batch of sprites to be rendered, specifying the texture, screen position, optional source rectangle, color tint, rotation, origin, scale, effects, and sort depth.
or can try change order for drawing:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
map.Draw(); // first
player.Draw(); // second
spriteBatch.Draw(mouseIcon, mouseIconPosition, Color.White); // third
spriteBatch.End();
base.Draw(gameTime);
}//end Draw()
(its for SpriteSortMode.Deferred)
P.S. Sorry for google-translating
oops... I have not updated comments before responding

Categories

Resources