3DS Homebrew App Framerate control

Discussion in '3DS - Homebrew Development and Emulators' started by Peanut42, Jun 27, 2015.

  1. Peanut42
    OP

    Peanut42 Member

    Newcomer
    30
    34
    Jun 27, 2015
    Mexico
    Hi to everybody!

    I managed to get an a copy of Cubic Ninja, installed the exploit and install everything. I started to program a game. The game already exists, is written in SDL, I understand that is not the same, but, I managed to copy images and do everything "like" SDL.

    Now I have a strange problem, I can't control the velolicty of the game. I'm searching for examples in Internet and most games don't do frame control. If someone knows how to "delay" each frame to something near 24 fps, it will be great.

    I found some funcs: svcSleepThread, svcGetSystemTick, APT_SetAppCpuTimeLimit and osGetTime, but I don't know how exactly they can helpme. I've tried svcSleepThread and SetAppCpuTime, but no luck. I know that osGetTime can meassure the time, but how do I do "microsleeps" (something like SDL_Delay).

    Thanks for reading.

    By the way, the game source code is at Github (https://github.com/gatuno/PaddlePuffle3DS/blob/master/source/main.c)
     
  2. elhobbs

    elhobbs GBAtemp Advanced Fan

    Member
    767
    284
    Jul 28, 2008
    United States
    Use svcSleepThread to sleep. Keep in mind it uses nanoseconds. You can measure ticks using svcGetSystemTick and take the difference from the last frame. If this value is smaller than your target frame time than sleep for the difference. 268123480/24 would be your target ticks per frame.
     
  3. Peanut42
    OP

    Peanut42 Member

    Newcomer
    30
    34
    Jun 27, 2015
    Mexico
    Thanks a lot!

    I solved to something like (again) SDL:

    Code:
    /* Used 12 because with 24 still runs too fast! */
    #define FPS (268123480/12)
    
    void game_loop (void) {
        u64 last_time, now_time;
        while (aptMainLoop ()) {
            //Wait for VBlank
            gspWaitForVBlank();
           
            last_time = svcGetSystemTick ();
            /* Do your game loop here and swap buffers */
            now_time = svcGetSystemTick ();
            if (now_time < last_time + FPS) svcSleepThread (last_time + FPS - now_time);
        }
    }
     
  4. elhobbs

    elhobbs GBAtemp Advanced Fan

    Member
    767
    284
    Jul 28, 2008
    United States
    I would do something like this
    Code:
    #define TICKS_PER_FRAME (268123480/24)
    
    void game_loop(void) {
       u64 last_time, now_time, u64 frame_time;
       
       last_time = svcGetSystemTick();
       
       while (aptMainLoop()) {
    
         /* Do your game loop here */
         
         //Wait for VBlank
         gspWaitForVBlank();
         gfxFlushBuffers();
         gfxSwapBuffers();
    
         now_time = svcGetSystemTick();
         frame_time = now_time - last_time;
         last_time = now_time;
         if (frame_time < TICKS_PER_FRAME) svcSleepThread(TICKS_PER_FRAME - frame_time);
       }
    }
    
     
  5. nop90

    nop90 GBAtemp Maniac

    Member
    1,363
    2,042
    Jan 11, 2014
    Italy
    Rome
    But is svcSleepThread parameter in ticks? Isn't it in nanosecond?
     
  6. TheCruel

    TheCruel Developer

    Banned
    1,351
    2,882
    Dec 6, 2013
    United States
    The reason you probably can't find frame control examples is because it's a backwards approach. Instead of trying to get a framerate that achieves the right velocity, you should be using the framerate in your velocity calculations. Example :

    Code:
        while (aptMainLoop())
        {
            while (eventmanager.pollEvent(event)) {
                processEvent(event); // Process input to change just like player velocity
            }
            deltaTime = clock.restart(); // Get time elapse since last frame render
    
            update(deltaTime.asSeconds()); // Update positioning of everything
            render(); // Draw everything now that it's repositioned
        }
    Then in your game code you just have an update() method like this one:
    https://github.com/cpp3ds/cpp3ds-template/blob/master/src/main.cpp#L22

    Then all you have to do is something like: player.setPosition(delta * player.velocity.x, delta * player.velocity.y);

    Then will ensure consistent movement regardless of players experiencing 5 fps or 60. You just set your velocity to how many pixel per second you want something to move.

    Now I'm not saying you should rewrite everything to follow this. Just letting you know for the future, because when you try to lock the framerate, then you introduce more problems (e.g. if there's a cpu intensive or laggy part in a game, it causes a slowdown instead of just dropping some frames of animation).
     
    Last edited by TheCruel, Aug 29, 2015
    WhoAmI? likes this.