Does anyone know how to get the monitor Screen Refresh Rate (Hz) in a C# UWP app?
...that will be valid to publish to the Microsoft Store (ie, no HWNDs?).
The reason for the question is that when writing a game, it's good to base movement on elapsed time between updates. To get smooth frame timing it's useful to know how often we're drawing to the screen and so time our frame updates to be in sync with that.
For example, if you know the Refresh Rate is 120Hz then it's optimal to set a fixed game time:
TargetElapsedTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond / 120L));
Which results in consistent frame timing and smooth motion.
Unbound the process timing using IsFixedTimeStep = false; in Game1.
The default of graphics.SynchronizeWithVerticalRetrace = true; should cap the FPS to match the refresh rate.
It should work according to the source code comments:
The first argument instructs DXGI to block until VSync, putting the application to sleep until the next VSync. This ensures we don't waste any cycles rendering frames that will never be displayed to the screen.
If you still need the actual refresh rate in Hz, calculate the average of (1000/gameTime.ElapsedTime.TotalMilliseconds) in update.
I made a game and when you die the score moves from top right to the middle of the screen using an animation. When you press Retry I reverse the animation by by setting the a speed parameter which is used as a speed multiplier in AnimationState.
While the parameter switches value (from 1.0 to -1.0 and or the other way around) the animation has a delay. I also noticed the longer you wait pressing retry, the longer it'll take for the animation to start. I do have to mention the animation doesn't have a transition to an idle state, so it probably means the animation time is moving > 1.0. I tried setting normalizedTime, but this didn't work either.
Does anyone know how to fix this?
Okay apparently I had to use ForceStateNormalizedTime() as normalizedTime was going above 1.0f and below 0.0f.
Let's say my app is running dozens of animations simultaneously and I want to pause them all as if this were a game and the user hit the pause button. What's the best way to do that? I'm using a combination of CAKeyFrameAnimations, UIView.Animate(), CABasicAniamtions, etc. Obviously I could manually stop them all when the user hits pause, and resume them from where they stopped when the user un-pauses.. But is there a better way to do this?
Edit: I want to be able to Pause & Resume via user pressing a button.
2nd Edit: I got like 90% of the way there, but I'm still having a problem...
Here's my Xamarin iOS project:
https://www.dropbox.com/s/5zbhhao6cijtb1i/Test_Pause.zip
Useful Apple reference:
https://developer.apple.com/library/ios/qa/qa1673/_index.html
I have an app that starts an position animation. When I pause it the first time, it pauses correctly. When I hit resume, it resumes correctly from right where it was paused. But when you hit pause again a 2nd time (during the same animation) it resumes at a position as if it had never paused to begin with. It pauses way ahead of where it should be. The desired result of course is to have it halt exactly where it is when you hit the pause button.
Sorry if this sounds confusing, the example project i've attached is really simple, to reproduce the problem, download my app from the link above. Run it. Make sure to Pause, Resume, then Pause again all within the same animation. Any idea what I'm doing wrong?
you can use a Boolean at the beginning of the drawing method, if the boolean is true (means no animation ) then it goes directly to the end
You can use a CAAnimationGroup, which is a subclass of CAAnimation, and manipulates its component Animations as a group (I'm not sure if they're strictly synchronized, but I think they're close enough for visual purposes).
I can now successfully pause and resume animations with CAMediaTiming, all without having to Stop the aniamtion and change the duration and start it again. See this useful resource
Class Level Variables:
UIView MyImage;
double timeSincePause = 0;
double pauseTime = 0;
Pause Function:
MyImage.Layer.Speed = 0.0f;
MyImage.Layer.TimeOffset = MyImage.Layer.ConvertTimeFromLayer(CAAnimation.CurrentMediaTime(), MyImage.Layer) - timeSincePause;
Resume Function:
pauseTime = MyImage.Layer.TimeOffset;
MyImage.Layer.Speed = 1.0f;
MyImage.Layer.TimeOffset = 0.0f;
MyImage.Layer.BeginTime = 0.0f;
timeSincePause = (MyImage.Layer.ConvertTimeFromLayer(CAAnimation.CurrentMediaTime(), MyImage.Layer) - pauseTime);
MyImage.Layer.BeginTime = timeSincePause;
I'm trying to get the frame rate of my XNA game on WP7 up to 60 fps. It appears to be locked at around the 30fps mark. I've tried the change of but makes little difference.
PresentationParameters.PresentationInterval = PresentInterval.One
Any thoughts?
You can change the fixed time step that XNA defaults to:
// 166666 ticks is 16.6ms, which is 60hz
game.TargetElapsedTime = new TimeSpan(166666) // 'game' refers to your instance of XNA.Game
Here's documentation on the feature:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.targetelapsedtime.aspx
Or, if you just want to turn off the fixed timestep, try setting fixed time step to false:
game.IsFixedTimeStep = false // 'game' refers to your instance of XNA.Game
Here's documentation on the feature:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.isfixedtimestep.aspx
This is set to true by default in XNA, so you will see a fixed time-step until you set it otherwise.
Of course there is also the chance that performance problems are keeping you around 30 fps. You could be seeing V-sync holding up the frame to sync with the phone's display, either the display may be limited to 30 fps (not likely), or if your game is taking longer than 16.6ms per frame, the V-sync might be holding it to 30 fps to keep it in sync with the display. At 30 fps your game would render every other frame that the display refreshes. But if V-sync was disabled and your game was running at something like 50 fps, your game would only partially be done rendering by the time the display refreshed, and you'd end up with screen tearing.
I'm writing a simple control in C# that works like a picture box, except the image is constantly scrolling upwards (and re-appearing from the bottom). The animation effect is driven by a timer (System.Threading.Timer) which copies from the cached image (in two parts) to a hidden buffer, which is then drawn to the control's surface in its Paint event.
The problem is that this scrolling animation effect is slightly jerky when run at a high frame rate of 20+ frames per second (at lower frame rates the effect is too small to be perceived). I suspect that this jerkiness is because the animation is not synchronized in any way with my monitor's refresh rate, which means that each frame stays on the screen for a variable length of time instead of for exactly 25 milliseconds.
Is there any way I can get this animation to scroll smoothly?
You can download a sample application here (run it and click "start"), and the source code is here. It doesn't look horribly jerky, but if you look at it closely you can see the hiccups.
WARNING: this animation produces a pretty weird optical illusion effect which might make you a little sick. If you watch it for awhile and then turn it off, it will look as if your screen is stretching itself vertically.
UPDATE: as an experiment, I tried creating an AVI file with my scrolling bitmaps. The result was less jerky than my WinForms animation, but still unacceptable (and it still made me sick to my stomach to watch it for too long). I think I'm running into a fundamental problem of not being synced with the refresh rate, so I may have to stick to making people sick with my looks and personality.
You would need to wait for a VSYNC before you draw the buffered image.
There is a CodeProject article that suggests using a multimedia timer and DirectX' method IDirectDraw::GetScanLine().
I'm quite sure you can use that method via Managed DirectX from C#.
EDIT:
After some more research and googling I come to the conclusion that drawing via GDI doesn't happen in realtime and even if you're drawing in the exact right moment it might actually happen too late and you will have tearing.
So, with GDI this seems not to be possible.
(http://www.vcskicks.com/animated-windows-form.html)
This link has an animation and they explain the way they accomplish it. There is also a sample project that you can download to see it in action.
Use double buffering. Here are two articles: 1 2.
Another factor to ponder is that using a timer doesn't guarantee you to be called at exactly the right time. The correct way to do this is to look at the time passed since the last draw and calculate the correct distance to move smoothly.
I had a similar problem a couple of months ago, and solved them by switching to WPF. The animated control ran a lot smoother than with a standard timer-based solution and I didn't have to take care of synchronization any more.
You might want to give it a try.
You need to stop relying on the timer event firing exactly when you ask it to, and work out the time difference instead, and then work out the distance to move. This is what games, and WPF do, which is why they can achieve smooth scrolling.
Let's say you know you need to move 100 pixels in 1 second (to sync with the music), then you calculate the time since your last timer event was fired (let's say it was 20ms) and work out the distance to move as a fraction of the total (20 ms / 1000 ms * 100 pixels = 2 pixels).
Rough sample code (not tested):
Image image = Image.LoadFromFile(...);
DateTime lastEvent = DateTime.Now;
float x = 0, y = 0;
float dy = -100f; // distance to move per second
void Update(TimeSpan elapsed) {
y += (elapsed.TotalMilliseconds * dy / 1000f);
if (y <= -image.Height) y += image.Height;
}
void OnTimer(object sender, EventArgs e) {
TimeSpan elapsed = DateTime.Now.Subtract(lastEvent);
lastEvent = DateTime.Now;
Update(elapsed);
this.Refresh();
}
void OnPaint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(image, x, y);
e.Graphics.DrawImage(image, x, y + image.Height);
}
Some ideas (not all good!):
When using a threading timer, check that your rendering time is considerably less than one frame interval (from the sound of your program, you should be fine). If rendering takes longer than 1 frame, you will get re-entrant calls and will start rendering a new frame before you've finished the last. One solution to this is to register for only a single callback at startup. Then in your callback, set up a new callback (rather than just asking to be called repeatedly every n milliseconds). That way you can guarantee that you only schedule a new frame when you've finished rendering the current one.
Instead of using a thread timer, which will call you back after an indeterminate amount of time (the only guarantee is that it is greater than or equal to the interval you specified), run your animation on a separate thread and simply wait (busy wait loop or spinwait) until it is time for the next frame. You can use Thread.Sleep to sleep for shorter periods to avoid using 100% CPU or Thread.Sleep(0) simply to yield and get another timeslice as soon as possible. This will help you to get much more consistent frame intervals.
As mentioned above, use the time between frames to calculate the distance to scroll, so that the scroll speed is independent of the frame rate. But note that you will get temporal sampling/aliasing effects if you try to scroll by a non-pixel rate (e.g. if you need to scroll by 1.4 pixels in a frame, the best you can do is 1 pixel, which will give a 40% speed error). A workaround for this would be to use a larger offscreen bitmap for scrolling and then scale it down when blitting to screen, so you can effectively scroll by sub-pixel amounts.
Use a higher thread priority. (really nasty, but may help!)
Use something a bit more controllable (DirectX) rather than GDI for rendering. This can be set up to swap the offscreen buffer on a vsync. (I'm not sure if Forms' double buffering bothers with syncing)
I had the same problem before and found it to be a video card issue.
Are you sure your video card can handle it?
I modified your example to use a multimedia timer that has a precision down to 1 ms, and most of the jerkiness went away. However, there is still some little tearing left, depending on where exactly you drag the window vertically. If you want a complete and perfect solution, GDI/GDI+ is probably not your way, because (AFAIK) it gives you no control over vertical sync.
Well, if you wanted to run the timer at a lower speed, you can always change the ammount the image is scrolled in the view. This gives better preformance, but makes the effect look kinda jerky.
Just change the _T += 1; line to add the new step...
Actually, you could even add a property to the control to adjust the step ammount.