I am making the character run but the animation is extremely quick as I am doing:
_frameIndex++;
_frameIndex; is the value which points to the image in the SpriteSheet. Does anyone know how I can use gameTime.ElapsedGameTime.TotalMilliseconds to slow the animation down?
I saw that you've asked a couple of questions tonight concerning animation and spritesheets, so here's an example from Aaron Reed's "Learning XNA 4.0," from Chapter 3 under the "Adjusting the Animation Speed" heading.
First, create two class-level variables to track time between animation frames:
int timeSinceLastFrame = 0;
int millisecondsPerFrame = 50;
The first variable tracks time passed since the animation frame was changed, and the second is an arbitrary amount of time that you specify to wait before moving the frame index again. So making millisecondsPerFrame smaller will increase the animation speed, and making it larger will decrease the animation speed.
Now, in your update method, you can take advantage of game.ElapsedGameTime to check time passed since the last frame change, and change the frame when when that value greater than millisecondsPerFrame, you can do work:
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame){
timeSinceLastFrame -= millisecondsPerFrame;
// Increment Current Frame here (See link for implementation)
}
This sort of solution is similar to what you've found works, except that you can take an extra step to specify exactly how often you want the animation to update, or even change that duration later on in your code if you like. For example, if have some condition that would "speed up" the sprite (like a power-up) or likewise slow it down, you could do so by changing millisecondsPerFrame.
I removed the code that actually updates the current frame, since you should already have something that does that since you have a working animation. If you'd like to see the example in-full, you can download it from the textbook's website.
I debugged the code and noticed that the gameTime.ElapsedGameTime.TotalMilliseconds always equated to 33. So I did the following:
milliSeconds += gameTime.ElapsedGameTime.Milliseconds;
if (milliSeconds > 99)
{
_frameIndex++;
milliSeconds = 0;
}
Which basically means that if this is the THIRD frame of the game, then make he _frameIndex go up. Reset the milliseconds to start over.
Related
I want to set the animation frame without playing it currently i am doing this it work perfectly but can i make it possible without playing the animation?
GO.GetComponent<Animation>().Play("Start");
GO.GetComponent<Animation>()["Start"].time = ((1f / 30f) * 0);
GO.GetComponent<Animation>()["Start"].speed = 0;
My advice would be to create a new state that simply contain that one frame.
It is counter-intuitive to think of a state that is stuck on its first frame. It is like saying you are int eating state but only holding the fork without any movement. Something is not quite right in that statement.
So you'd rather have a Immobile state and then run it in loop. When you need to start doing other actions, then just switch as would.
Now if you want to start an animation at a specific position:
animator.Play("AnimName",layer, normPosition);
I am pretty new at C# and I wanted to make a simple 2D RPG (Role-Playing-Game) character which can move around with its walking animation by simply using 'W' 'A' 'S' 'D' keywords. To do that, I used Picture Box to hold character image and 2 Timers Tool, one for managing the 'walking' animation by changing the picture every 100 ms, and the another timer is for moving that Picture Box location every 1 ms.
In the 'Form_KeyDown' event, I set those 2 timers Enabled = True whenever user presses one of the moving keywords and I set those 2 timers Enabled = False in the 'Form_KeyUp' event to indicate that the character is no longer moving.
Here is the first timer code that control the animation by changing the picture on each tick:
private void timerchangepic_Tick(object sender, EventArgs e)
{
//movementPhase will determine the picture to be displayed, added by 1
//every tick means character image change every tick
movementPhase++;
if (movementPhase > 4) movementPhase = 1;
//determining which image is currently displayed
if (charDirection == Direction.Front)
{
if (movementPhase == 1)
pbcharacter.BackgroundImage = Image.FromFile("Icon\\front.png");
else if (movementPhase == 2)
pbcharacter.BackgroundImage = Image.FromFile("Icon\\front2.png");
else if (movementPhase == 3)
pbcharacter.BackgroundImage = Image.FromFile("Icon\\front3.png");
else if (movementPhase == 4)
pbcharacter.BackgroundImage = Image.FromFile("Icon\\front4.png");
}
//and goes the same for another 3 directions (left, right, and back)
}
Here is the second timer code that move the location of the character on each tick:
private void timermovement_Tick(object sender, EventArgs e)
{
if (charDirection == Direction.Front)
{
pbcharacter.Location = new Point(pbcharacter.Location.X, pbcharacter.Location.Y + 5);
}
//and goes the same for another 3 directions (left, right, and back)
}
My problem is: the character can't move well when I hold one of the moving keystroke. In a first second it works fine, but after a few second (2-3 seconds) pressing and holding 'S' stroke made the character stopped, moved a little, stopped again, moved a little and over and over. Besides, the animation only worked for 1 lap, the picture changed from 'front' to 'front2' until 'front4' well, but not from 'front4' back to 'front'. In conclusion, the character's animation only ran for 1 shift, then it became a static image which moved a little, stopped, moved again, and stopped again whenever i hold 'S' button.
What is wrong with my codes? Are there any better approaches to implement a moving 2D character task with its animation?
I suggest you to use somethimg more specific to build your application: XNA, MonoGame or Unity3D. But if you are using winforms I have several suggestion for you:
1) Cache images instead load them from file every time.
2) Cause Timer Events interval is not very accurate calculate ElapsedTime from last event. And make change +5 to something dependent of ElapsedTime.
3) Instead using several timers organize game loop to handle your events.
4) Use Double Buffer on your form.
Building a game using windows forms can be incredible hard, and also extremely inefficient. If you were to use XNA, which isn't that difficult to learn, you could create a much better and much stronger game.
If your using WinForms i will presume your a beginner so I wouldn't bother with unity or mono as they are much more complicated. If you still reject this I would advise you to:
Cache images
more accurately calculate ElapsedTime and use dependencies
use a while loop to repeat for each tick, this point should fix your problem
Hope to have been of help.
I think if you must make your game using windows form then you need to
at least handle your update with a gameloop instead of form timers and
if your moving things around your going to need some kind of clock to
help your game run at the same speed on any cpu
I am trying to run an evolutionary algorithm using xna
i would like only to run the logical side of the game
and after a long caculation time add the animation.
Does anybody know how to accelerate calculation time and disable the
Draw() call.
Thanks
Just don't draw in your Draw method. You can keep a counter or a time stamp as reference, and only draw once out of 100 times or once per second.
However, your problem is not the number of times Draw is called, but the number of times Update is called. By default, XNA will never call Update more than 30/60 times per second. You can change the frame rate XNA tries to achieve as explained in this post. To call Update 100 times per second, just change the target elapsed time in your game to:
this.TargetElapsedTime = TimeSpan.FromSeconds(1.0f / 100.0f);
My update function gets called like 60 times a second, and the player is meant to move in 32 pixel steps on my grid, so the player moves very quickly, i want a way to only recieve certain key inputs every like 10 frames, and still have my game run at 60fps.
You can
require user to do full keyboard clicks with releasing each key
have user's position to be sort-of float instead of int where whole part represents grid steps. While user tries to move in particular direction it will move with some defined speed (like 2 per sec) and when float position becomes next cell player jumps
you can require player to stay in particular cell some given amount of time (like .5 seconds) - thus definind speed how fast it moves.
The easiest way is to keep time on when a key was pressed. There isn't a way to slow down the speed of the input system, so you have to fake it yourself. Here is some pseudocode to get you started.
// See if the key is currently down
if (KeyIsDown(key))
{
if (gameTime.TotalGameTime >= nextTime)
{
// Move the character, and indicate that you want to wait another second for movement.
moveTheCharacter();
nextTime = gameTime.TotalGameTime + 1;
}
}
The main advantage of this approach is that it will always be based on time as opposed to the framerate of your game. So if you drop frames for some reason your character will still move at the same speed.
I'm trying to get a general smooth scrolling mechanism that I can implement in my mobile applications.
I want it to be generic enough so that it can port to any platform, but I am currently working in C# on the .net Compact Framework.
What I'm doing right now is:
Create a Stopwatch object (in the panel's ctor)
on mouse down start the Stopwatch and save the current mouse point _lastMouse
on mouse move, stop the Stopwatch, and store velocity = (_lastMouse - curMouse) / Stopwatch.TotalSeconds then reset the Stopwatch and start it again
In most cases Stopwatch.TotalSeconds is between 0.02 and 0.03
on mouse up, I pass the velocity value into a smooth scrolling function, and that function continues to scroll the panel until either the end is hit or the increasing friction causes the velocity to be == 0
My problem is in the final step. The velocity values are generally int the 2,000-3,000 pixel range. The velocity is in pixels per second, so this is to be expected. I take the Stopwatch (which should be still running), stop it and I find the elapsed time from last mous move and multiply velocity by Stopwatch.TotalSeconds, get that distance and then reset and start the Stopwatch, then loop back and start all over again.
The expected result is that the elapsed time between refreshes multiplied by the velocity should give me the number of pixels (according to the last mouse move) that I should scroll. My actual result is that sometimes the panel goes flying and sometimes it bearly moves! the gradual slowdown is fine, it's just the beginning velocity that is off
Is there a flaw in the logic? Should I be doing something else?
Thanks for any help!
It seems to me that there are three possible sources of inaccuracy here. Firstly, as "A.R." said, you'll have problems if the granularity of your timer isn't good enough. Have you checked IsHighResolution and Frequency to make sure it's OK?
Secondly, even if your timer is perfect, there may be some inaccuracy in your position measurements, and if you're taking two in very quick succession then it may hurt you. My guess is that this isn't a big deal, but e.g. if you're on a capacitive touchscreen then as the finger lifts off you may get variation in position as the contact area goes down.
Thirdly, the physical motion of the finger (or stylus or mouse or whatever you've got doing the actual input; I'm going to guess a finger) may not be all that well behaved. At the end of a gesture, it may change from being mostly horizontal to being mostly vertical.
All these problems would be substantially mitigated by using a longer sampling period and maybe (try it both ways) ignoring the very last sample or two. So, keep a little circular buffer of recent samples, and when you get the mouse-up look back (say) 100ms or thereabouts and use that to decide your velocity. Or, if you don't want to keep that much history, use a simple IIR filter: every time you get a sample, do something like
filtered_dt = filtered_dt + SMALL*(latest_dt-filtered_dt);
filtered_dx = filtered_dx + SMALL*(latest_dx-filtered_dx);
filtered_dy = filtered_dy + SMALL*(latest_dy-filtered_dy);
where SMALL should be, at a guess, somewhere around 0.2 or so; then use filtered_dx/filtered_dt and filtered_dy/filtered_dt as your velocity estimate. (I think this is better than calculating a velocity every time and filtering that, because e.g. the latter will still blow up if you ever get a spuriously small dt. If in doubt, try both ways.)
If you use the IIR approach, you may still want to make it ignore the very last sample if that turns out to be unreliable; if you remember the latest dt,dx and dy you can do that by undoing the last update: use (filtered_dt-SMALL*latest_dt)/(1-SMALL), etc.
Here's an off-the-wall suggestion that may or may not work. You mentioned that you get more erratic results when there's a "flick" at the end of the gesture. Perhaps you can use that to your advantage: look at, say, how rapidly the estimated velocity is changing right at the end of the gesture, and if it's changing very rapidly then increase the velocity you use somewhat.