As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/

Math is Hard (Programming)

Sir CarcassSir Carcass I have been shown the end of my worldRound Rock, TXRegistered User regular
edited January 2012 in Help / Advice Forum
So I've gotten back into messing around with this game I've been creating in C++. I'm stuck on coming up with a formula to calculate a value I need. There are some pretty matherrific people here, so I thought maybe they would enjoy helping me figure this out. Like a brain teaser, yeah. This is a personal project, so not homework or anything.

This is a game that uses ASCII characters, like a rogue-like. I'm currently working on animating cells. These is the current elements:

Cells have the following properties:

a character array that stores each character it would use in animation, graphic[]
an integer of the total number of characters, animationFrames
an integer of the speed it should animate, animationSpeed

There's also a global constant for the total number of frames per second, FPS (currently set at 100)
And there's a counter integer that goes from 1 to 100 every second, animationCounter


The animationSpeed currently is related to the FPS, so if a cell has an animationSpeed of 100, it would go through all of its frames each second. If it were set to 50, it would go through them all twice per second. Set to 200, it would take 2 seconds to go through all of its frames.

To recap:
animationCounter - goes from 1 to 100 every second
FPS - total frames per second, currently 100
graphic[] - character array with each animation frame inside
animationFrames - total number of frames, used as a helper for graphic[] (maybe some sort of null terminator would be better?)
animationSpeed - value related to FPS on how fast cell should animate, open for suggestions on how to redo this

Here are some sample data sets:

animationSpeed = 100, animationFrames = 2
animationCounter 1 <-> 50, function should return a 0
animationCounter 51 <-> 100, function should return a 1

animationSpeed = 100, animationFrames = 1
animationCounter 1 <-> 100, function should return a 0

animationSpeed = 50, animationFrames = 2
animationCounter 1 <-> 25, function should return a 0
animationCounter 26 <-> 50, function should return a 1
animationCounter 51 <-> 75, function should return a 0
animationCounter 76 <-> 100, function should return a 1

animationSpeed = 50, animationFrames = 1
animationCounter 1 <-> 100, function should return a 0

animationSpeed = 200, animationFrames = 1
animationCounter 1 <-> 100, function should return a 0

animationSpeed = 200, animationFrames = 2
animationCounter 1 <-> 100, function should return a 0
second iteration of animationCounter 1 <-> 100, function should return a 1 (this may not be possible without some other variable or redoing the counter)

Notes:
Most of the variables can be made to either start on 0 or 1, depending on what makes the math easier. So animationCounter can go from 0-99 or 1-100, for example.

Anyone know of a way to make this work? Also accepting alternate ways of doing this to make it work. If nothing else I can just have everything animate at the same speed (already have this working), but I would like to add some flexibility to it.

Thanks in advance.

Edit: I should also point out that the point of returning these values is to use as the index of the character array to know what ASCII character to print in any given frame.

Sir Carcass on

Posts

  • NichNich Registered User regular
    I can solve this, except for the last bit (the "animationSpeed = 200, animationFrames = 2"). But the last example shows the problem with your way of specifying the time. If you're measuring seconds, you'll be stuck if you want animations longer then that.

    Why not specify the animation speed directly in fps? That seems like it would be more scalable, and make the math a lot easier.

    3DS friend code: 3523-3358-5049
    Proud owner of the Veggie, Constellation and Cephalothorax badges
  • JHunzJHunz Registered User regular
    I think you're going to have to re-think this system some. Here are some reasons:
    1) A global constant for FPS is worthless. You can use a global constant to cap FPS if you like, but you can't guarantee that it won't dip below that if you're doing some heavy processing, or if the target computer is slow, or even just if VSync is turned on.
    2) How are you guaranteeing that animationCounter goes from 1-100 every second? I hope it's not by incrementing it by 1 each frame, for the reasons given above. You're probably better off ditching this variable entirely and doing something like keeping track each second of how far through the second you are.
    3) You obviously need to keep track, per animation that takes more than a second, of how far in you are already (I see you thought of that already). You probably also want animationSpeed to just be the number of seconds you want it to take (maybe make it a float/double if you want fractional amounts) rather than being related to FPS.

    bunny.gif Gamertag: JHunz. R.I.P. Mygamercard.net bunny.gif
  • DraygoDraygo Registered User regular
    edited January 2012
    I would redo this.

    Essentially you want to be able to tell what animation frame to use in any particular screen refresh. Am I correct?

    The problem arises when you are dealing with numbers above 100, that you need to store data related to the character in order to render the frame. But this can be done with a frame counter.

    Pass the current frame counter to the animation function, with the animation speed, and total frames.
    So if you are on frame 165 for an animation speed of 100 and frame count of 2, the function returns a 1.

    psudo code to follow
    framecounter( frame, anSpeed, fcount)
    {
    remainder = frame % anSpeed
    //now you need to divide anspeed into fcount parts
    parts = anSpeed / fcount
    i = 0;
    while (remainder = remainder - parts > 0) i++;

    return i;

    }

    This way you can keep counting frame up and later you can seperate frame from fps and tie it into real time.

    Draygo on
  • Sir CarcassSir Carcass I have been shown the end of my world Round Rock, TXRegistered User regular
    The reason I'm using the constant FPS = 100 is because with the library I'm using (libtcod), if you don't cap the FPS it tends to eat up all of the cpu. 100 was just an arbitrary value that I thought would make some of the other math easier. This is designed to run in a set resolution window (at least for the present), so I don't think v-sync is a concern.

    Yes, I'm incrementing the counter each frame. I probably should separate it based on actual time passed, but if the frame rate is chugging, wouldn't it just slow down the animation? I'm fine with that as it's just (currently) environmental stuff like water and fire. Not sure if it would mess up other areas as I haven't thought it through. These are the time functions available through the library if something there would work better.

    Modulus. Dammit, I knew I was forgetting something to throw at this.

  • DraygoDraygo Registered User regular
    edited January 2012
    Then the psudo function should do what you wanted, with the bonus of handleing anything > 100. It is an O(fcount) function though Probably could make it better by dividing the remainder by the parts and flooring it. You will probably want to make sure inputted values to the function are > 0

    return floor(remainder / parts); instead of the while loop.

    so for 165th frame 100 speed and 2 frames should return 1.
    and 145 should return 0
    165th frame 200 speed and 2 frames should return 1

    Draygo on
  • JHunzJHunz Registered User regular
    The reason I'm using the constant FPS = 100 is because with the library I'm using (libtcod), if you don't cap the FPS it tends to eat up all of the cpu. 100 was just an arbitrary value that I thought would make some of the other math easier. This is designed to run in a set resolution window (at least for the present), so I don't think v-sync is a concern.
    V-sync isn't a concern because you're actually expecting frame tearing, it's a concern because it constrains the FPS of your program to a specific set of values, which may or may not correspond to the constant you're using (probably not if you're using 100).
    Yes, I'm incrementing the counter each frame. I probably should separate it based on actual time passed, but if the frame rate is chugging, wouldn't it just slow down the animation?
    With the plan you outlined, consider what would happen if you had animation speed 100, 4 frames of animation, and an actual FPS of 60 FPS. Every second you'd see frame 1 for .42 seconds, frame 2 for .42 seconds, and frame 3 for .17 seconds. Frame 4 would go missing entirely.

    bunny.gif Gamertag: JHunz. R.I.P. Mygamercard.net bunny.gif
  • DraygoDraygo Registered User regular
    This is why you see developers base things off a unit of time. Typically they call them ticks. That way you can say there is 100 ticks a second. the psudo function i outlined works with ticks if you switch frames->ticks seamlessly.

    For example on my computer i have vsync forced on, that means my frames per second is locked into my monitors refresh rate. 75 hrz = 75 frames a second maximum (60 hrz = 60 fps, and so on). What happens when your program wants to output at 100 fps when i limited it to 75 is that it will discard every 4th frame, the information you wrote to the buffer will simply be tossed.

    For ticks, a single tick can be any length of time you desire, from an entire second to 1/100th of a second to even a millisecond (tribes 2 used this). But switching to that would probably require a rewrite of you code so I didnt suggest it initially. If your in your early stages, doing this change now will save you a lot of work if you decide to change it in the future.

  • Sir CarcassSir Carcass I have been shown the end of my world Round Rock, TXRegistered User regular
    Hmm, yeah, that makes sense.

    It is still in the fairly early stages. Currently I have a while loop at the end of my game loop that waits for a keypress while drawing the screen 100 times a second (based on the FPS constant). The actual game is turn-based, but it draws the screen in real-time for the animations.

  • JasconiusJasconius sword criminal mad onlineRegistered User regular
    I would advise against making what appears to be a tweening and sprite animation system with a global FPS constant.

    You should be computing values based on a delta time between firing of the animation loop (which may just be the main thread)

Sign In or Register to comment.