Search Unity

Taking control of framerate to ensure precise timing

Discussion in 'Scripting' started by Redz0ne, Oct 7, 2015.

  1. Redz0ne

    Redz0ne

    Joined:
    Oct 19, 2010
    Posts:
    332
    Hello!

    I've been researching fighting games and one of the most common things I've learned is that framerate control is crucial.

    I've been looking at the scripting API to see what systems I'd use and I suspect time.CaptureFramerate is the command... But the example is a bit mystifying to me (I'm a relative noob to coding though I am learning.)

    Thing is... While the animation I am going to be making is going to be done in 60fps, I need a way to control the timing and framerate so that I can appropriately synchronize the animations, inputs and control interface (and anything I may be missing) so that I can get precision.

    And if you know someone in the FGC, chances are they'll tell you that precision is important.

    I know there are asset-store kits for fighting games... But I'd rather figure this out without investing in an asset-store package (no offence, I hear it's good... But I would like to learn how to do this. That and I'm not exactly able to buy it anyway since I'm on a very tight budget.)

    So, TLDR: Fighting game... Frame-rate control... Synchronization... What direction do I need to look in order to make something like this?

    EDIT: Oh, and one last thing... Will this method play nicely with the fixedUpdate (so as to keep the things that fixedUpdate handles isolated from the restricted/locked framerate from this method?)
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Application.targetFrameRate is probably what you are interested in.

    Unity in general doesn't play well with trying to run at a precise frame rate. There are a bunch of work arounds, but its not fun.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    First, read the docs on Application.targetFrameRate completely, to get an idea of the technicalities.

    http://docs.unity3d.com/ScriptReference/Application-targetFrameRate.html

    Second, it might not give the expected results, as the docs say, there is no guarantee (and really there is no way to get a fully guaranteed framerate). Primarily because a computer can just slow down.

    In the case of Unity, to target a framerate, what it'll do is if the game is running faster than the targeted framerate is. It will calculate how much time was taken at the end of the frame computation, and determine from that how long it aught to wait until the next frame, and it'll block for that duration (in simple terms).

    If the game is running slow... well, there really isn't anything it can do about that.

    And don't forget, the documentation says this value is ignored all together if one uses vsync (this is going to come up later).

    And well, this isn't good for you if you need as close to guaranteed as possible. You're relying on the idea that all the physics, graphics, and logic will be efficient enough on all target platforms that it's ALWAYS faster than the targeted framerate (60fps most likely).

    And I get it, in a fighter, this level of precision is highly expected by advanced players. When a move requires a very specific sequence of button presses that occur at frame specific points, they want this.

    So what can one do?



    Well, this is all just brain storming, as I don't make fighters. But lets try to solve your problem.

    There's 2 sides to this. There's the "user input", when the player presses buttons. And there is "animation rendering", which is the visual cues to the player when to press a specific button.

    User Input

    Well, first and foremost, I'd avoid unity's input system all together for in game controls. You could use it for general purpose menu navigation and what not. But in game controls should probably use something more precise. I would probably suggest "XInput" as it has very good support, and there is a .Net wrapper for it:
    https://github.com/speps/XInputDotNet

    It appears some people have written wrappers around XInput for .net, and created easier to use asset packages for it:
    http://www.gallantgames.com/pages/incontrol-xinput

    There's probably others.

    Now, because this doesn't actually occur on the Update loop, it needs to be brought back to the main thread (especially for FixedUpdate). That "incontrol-xinput" actually supports this directly and has all the leg work set up for you via 'Bindings', so I'd use that (note, unity actually doesn't support input on the FixedUpdate loop either, so you'd end up having to do something like this no matter what).

    Now because it's not tied to the main update loop, and instead most likely its own thread (i'd make it its own thread), it no longer suffers the slow down of the update thread. The users input will be registered at precise timing, and the only delay will be any minor mid frame update that might occur if there happens to be slow down. This is expected, and shouldn't really result in any major user experience that is noticeable.

    That is if we make sure that the framerate is set right, and the input update is at the same frequency.

    Frame rate

    Next is that we got to have a decent frame rate for the player.

    This is where vsync comes into play. Vsync is used to lock the framerate of the game to the framerate of the monitor (as long as it's supported). Most any gamer who expects PERFECT framerate is going to use vsync. How vsync will work is that if a frame is called to render too early, the GPU/monitor will wait until the correct time to actually update the monitor. And if framerate drops to low, it'll display the same frame again on the next frame, and wait again. And because it does it in hardware, and is locked to the monitor, it results in a more accurate framerate lock with out the expensive software cost as its done in hardware.

    Downside is it looks weird if the framerate drops too low, as the games stutter will become a bit more rhythmic. But vsync users tend to be used to this anyways. And anyways... even though the stutter will look weird... it's STILL precise. And that's our end goal... precision even when the frame rate drops.

    Of course, what about those without vsync will need something. And that's where Application.targetFrameRate comes into play. Use that when vsync isn't available.



    And FINALLY, your input polling (may it be by XInput or something else) needs to occur at the same frequency as the display. So if vsync is selected, set your input to poll at that frequency. If vsync is off, set it to poll at the 'targetFrameRate'.


    And never forget. Make sure you include some expected 'minimum' requirements for your users. Once you have your game together, you'll run performance tests and see what specs are needed to maintain the targeted framerates (may it be vsync or not)... because at the end of the day, it still looks poop if the framerate drops.

    If your users don't have the min requirements... well, that's on them.

    If they can't control those specs (playstation, xbox, iphone, none PC/Mac/Linux platforms), well, make sure you optimize your game to run on those platforms.



    Again, this is all just theory and brain storming. But if I had to solve the problem you have... this is the first route I'd go about doing it.
     
    Last edited: Oct 7, 2015