[answered] I need help tweaking the following code

Started by
3 comments, last by flashinpan 12 years, 4 months ago
The following code displays a simple cell animation from a spritesheet. I have some questions on how to modify my code to do the following:

-I want to slow down the frame rate...it is really fast.
-I set the background color to "CornflowerBlue" so that the background of the cell would blend in with the background, but it ended-up adding a slight blue tint to the image as well. How can I prevent that?

Here is my current code:

First, the sprite sheet:

powersourceanimated1a.png

main source


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 XNARobotz
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
AnimatedSprite animatedSprite;

private Texture2D powersource1;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}

/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();
}

/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);

powersource1 = Content.Load<Texture2D>("powersource1");

Texture2D texture = Content.Load<Texture2D>("powersourceanimated1a");
animatedSprite = new AnimatedSprite(texture, 1, 8);

// TODO: use this.Content to load your game content here
}

/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}

/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// TODO: Add your update logic here

animatedSprite.Update();

base.Update(gameTime);
}

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

// TODO: Add your drawing code here

spriteBatch.Begin();

spriteBatch.Draw(powersource1, new Rectangle(0, 0, 32, 32), Color.White);

spriteBatch.End();

animatedSprite.Draw(spriteBatch, new Vector2(100, 100));


base.Draw(gameTime);
}
}
}




class to support the cell animation


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace XNARobotz
{
public class AnimatedSprite
{
public Texture2D Texture { get; set; }
public int Rows { get; set; }
public int Columns { get; set; }
private int currentFrame;
private int totalFrames;

public AnimatedSprite(Texture2D texture, int rows, int columns)
{
Texture = texture;
Rows = rows;
Columns = columns;
currentFrame = 0;
totalFrames = Rows * Columns;
}

public void Update()
{
currentFrame++;
if (currentFrame == totalFrames)
currentFrame = 0;
}

public void Draw(SpriteBatch spriteBatch, Vector2 location)
{
//int width = Texture.Width / Rows;
//int height = Texture.Height / Columns;

int width = 31;
int height = 31;

int row = (int)((float)currentFrame / (float)Columns);
int column = currentFrame % Columns;

Rectangle sourceRectangle = new Rectangle(width * column, height * row, width, height);
Rectangle destinationRectangle = new Rectangle((int)location.X, (int)location.Y, width, height);

spriteBatch.Begin();
spriteBatch.Draw(Texture, destinationRectangle, sourceRectangle, Color.CornflowerBlue);
spriteBatch.End();
}
}
}




Also, here is a short movie showing the above code running in the XNA IDE:

robotz anim demo
Advertisement
Hi!


I want to slow down the frame rate...it is really fast.

At the moment you update you animation every frame. Usually you want animations to be played in a certain rate measured per milliseconds (to make them independent from the performance of your game, since this depends among other things on the hardware). You can get the total elapsed time since start of your application from the GameTime object that is a parameter of the Game’s update method. You can pass it to the update method of your AnimatedSprite and do something like this:
Store in some member of your Animator:

int lastFrame = -1;

And in your update:

int updateRateInMsecs = 500; // update each 500 ms
int frame = ((int)gameTime.TotalGameTime.TotalMilliseconds) / updateRateInMsecs; // compute the frame we are in.
if (frame != lastFrame) // are we in a new frame now?
{
currentFrame = frame % totalFrames; // compute the number of the frame to show.
}
lastFrame = frame; // memorize for the next pass.



I set the background color to "CornflowerBlue" so that the background of the cell would blend in with the background, but it ended-up adding a slight blue tint to the image as well. How can I prevent that?

The last argument of the draw call is the tint color (usually set to white). This color is multiplied with your texture when it is rendered. By this you can implement by very simple means different colors for teams or add some diversity to objects. It is not meant to define a transparent color.
If you want to remove the white borders you have to add an alpha channel to your textures (many image editing tools can do that). Then you have to enable alpha blending, by specifying the following arguments when drawing:
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
Actually it would be better to use an Alpha Test for that, since it rejects pixels based on their alpha value if they are below or above some specified threshold. The test is much faster than blending, but in XNA 4.0 it was removed, because it is deprecated in modern DirectX. You’d have to do the test manually in a shader or use the built-in AlphaTestEffect. For starters, I’d recommend sticking with blending until you hit performance problems or feel ready to take the leap to shader development.

Hope this helps!

Hi!

[quote name='flashinpan' timestamp='1324660211' post='4896853']
I want to slow down the frame rate...it is really fast.

At the moment you update you animation every frame. Usually you want animations to be played in a certain rate measured per milliseconds (to make them independent from the performance of your game, since this depends among other things on the hardware). You can get the total elapsed time since start of your application from the GameTime object that is a parameter of the Game’s update method. You can pass it to the update method of your AnimatedSprite and do something like this:
Store in some member of your Animator:

int lastFrame = -1;

And in your update:

int updateRateInMsecs = 500; // update each 500 ms
int frame = ((int)gameTime.TotalGameTime.TotalMilliseconds) / updateRateInMsecs; // compute the frame we are in.
if (frame != lastFrame) // are we in a new frame now?
{
currentFrame = frame % totalFrames; // compute the number of the frame to show.
}
lastFrame = frame; // memorize for the next pass.



I set the background color to "CornflowerBlue" so that the background of the cell would blend in with the background, but it ended-up adding a slight blue tint to the image as well. How can I prevent that?

The last argument of the draw call is the tint color (usually set to white). This color is multiplied with your texture when it is rendered. By this you can implement by very simple means different colors for teams or add some diversity to objects. It is not meant to define a transparent color.
If you want to remove the white borders you have to add an alpha channel to your textures (many image editing tools can do that). Then you have to enable alpha blending, by specifying the following arguments when drawing:
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
Actually it would be better to use an Alpha Test for that, since it rejects pixels based on their alpha value if they are below or above some specified threshold. The test is much faster than blending, but in XNA 4.0 it was removed, because it is deprecated in modern DirectX. You’d have to do the test manually in a shader or use the built-in AlphaTestEffect. For starters, I’d recommend sticking with blending until you hit performance problems or feel ready to take the leap to shader development.

Hope this helps!
[/quote]



Okay....I think I have the delay down now. Thank you.


I am still struggling with the blue tint thing.

I tried adding those params as you suggested to the Begin method of the spriteBatch, but it did not seem to work right.


The .png is actually saved with a transparent background, not a white background. Does that make a difference in your advice?


Are you saying that if I had saved the png with a White background instead of a Transparent background this suggestion of yours would have worked??? :)


I'll keep experimenting, but I am hoping for a reply from you.


Regardless...thanks for the help with the timing.


[[EDIT]] - [color="#FF0000"]UPDATE: Actually....the .png was NOT saved with a transparent background, it WAS saved with a White background. Once I saved it with a transparent background it began working and looking as it was intended....so that is sorted out now...thank you!!


This still remains a question though:

Oh....one more thing on the timing.....I was wondering if there was a way to add more of a delay once the frame hits frame 4. The reason I ask is that on frame 4 the power "light" has hit the max intensity before it fades again and I want it to stay "fully lit" for longer than the other cells in the sequence. I just think it makes the power source "pulsing" look cooler. :) How can I do that?

I was wondering if there was a way to add more of a delay once the frame hits frame 4. The reason I ask is that on frame 4 the power "light" has hit the max intensity before it fades again and I want it to stay "fully lit" for longer than the other cells in the sequence. I just think it makes the power source "pulsing" look cooler. :) How can I do that?

The trick would be to manipulate the progress of the time. :)
You can keep a variable that stores “your” totally passed time and with every update you add the elapsed time since the last update, but (here it comes) if your currentFrame == 4 then you add only a fraction of it. This way it takes you longer to leave the time window of frame 4.
So store in some member of the AnimatedSprite that total time:
double virtualTotalTimeInMsecs = 0;

And in the update method you can add:
if (currentFrame == 4)
virtualTotalTimeInMsecs += gameTime.ElapsedGameTime.TotalMilliseconds * 0.25;
else virtualTotalTimeInMsecs += gameTime.ElapsedGameTime.TotalMilliseconds;


And change the previous code to this:
int frame = ((int) virtualTotalTimeInMsecs ) / updateRateInMsecs;

This is rather a hack, though. However, if you want to change the animation speed you have to manipulate the time somehow.
Hope this helps! :)

[quote name='flashinpan' timestamp='1324694350' post='4896982']
I was wondering if there was a way to add more of a delay once the frame hits frame 4. The reason I ask is that on frame 4 the power "light" has hit the max intensity before it fades again and I want it to stay "fully lit" for longer than the other cells in the sequence. I just think it makes the power source "pulsing" look cooler. :) How can I do that?

The trick would be to manipulate the progress of the time. :)
You can keep a variable that stores “your” totally passed time and with every update you add the elapsed time since the last update, but (here it comes) if your currentFrame == 4 then you add only a fraction of it. This way it takes you longer to leave the time window of frame 4.
So store in some member of the AnimatedSprite that total time:
double virtualTotalTimeInMsecs = 0;

And in the update method you can add:
if (currentFrame == 4)
virtualTotalTimeInMsecs += gameTime.ElapsedGameTime.TotalMilliseconds * 0.25;
else virtualTotalTimeInMsecs += gameTime.ElapsedGameTime.TotalMilliseconds;


And change the previous code to this:
int frame = ((int) virtualTotalTimeInMsecs ) / updateRateInMsecs;

This is rather a hack, though. However, if you want to change the animation speed you have to manipulate the time somehow.
Hope this helps! :)
[/quote]



Worked like a charm!!!


Thank you very much for your help.

Tom

This topic is closed to new replies.

Advertisement