zacharycarter / zengine

2D | 3D Game development library
157 stars 13 forks source link

Timer module #21

Closed zacharycarter closed 6 years ago

zacharycarter commented 6 years ago

Continuing discussion from : https://github.com/zacharycarter/zengine/issues/13

define-private-public commented 6 years ago

My opinion is that maybe we should have some sort of global object that anything can read from. e.g:

type
  ZApp* = object
    totalTicks*: int          # Total amount of elapsed ticks for the app
    updateDeltaTicks*: int    # Ticks since the last logical update
    drawDeltaTicks*: int      # Ticks since the last draw

# (somewhere else in the code...)
zengine.app = ZApp()

# (In the main update/draw loops...)
zengine.init(...)
while running:
  zengine.app.nextUpdateFrame()
  # ... game logic here

I'd also like to throw my stopwatch module in the running to facilitate this. AFAIK, it should run on mobile platforms since it tries to use Nim code, but I'm not 100% if it does as I haven't tested it.

zacharycarter commented 6 years ago

I'm trying to refrain from having globals the user has to manage, thus keeping everything very module based and just exposing functions to the user - if that makes sense. How about another module called timer which holds these globals and exposes a function called nextUpdateFrame() or whatever? Is there a reason you'd prefer to have a global object?

It's just a bit different from the current implementation is all I'm trying to get at.

define-private-public commented 6 years ago

eh, I just like objects.

define-private-public commented 6 years ago

I'd like to bump this ticket and give it the highest priority to work on right now. As I'm starting to work on sprite rendering I'll need this for when it comes time to animate, which is going to be pretty soon.

define-private-public commented 6 years ago

I'd also like to say I'd like to deal with deltas as floating point numbers. E.g. at 60 FPS, we'd give them a value of 0.016666666667 each frame. I like this because If someone says, "I want my player to move five units per second." It's easier to do this: player.x += speed * delta instead of player.x += speed * (delta / 1000.0) (assuming we use milliseconds if we go with hard ints).

zacharycarter commented 6 years ago

I'll work on this after work today.

zacharycarter commented 6 years ago

What do you think about something like -

import sdl2

var 
  startTime, currentTime, previousTime, updateTime: float64
  ticks: uint

proc getTicks*(): uint =
  ticks

proc getDeltaTime*(): float64 =
  updateTime

proc getTimeSinceLastTick*(): float64 =
  currentTime - previousTime

proc getTimeElapsed*(): float64 =
  currentTime - startTime

proc getTime*(): float64 =
  currentTime

proc tick*() =
  currentTime = float64(sdl2.getPerformanceCounter()*1000) / float64 sdl2.getPerformanceFrequency()
  updateTime = currentTime - previousTime
  previousTime = currentTime
  inc(ticks)

proc init*() =
  startTime = getTime()
  currentTime = startTime

Anything you'd like to see added? I don't understand this whole logic tick component you referred to in your example. I figured that'd be left up to the user to implement?

define-private-public commented 6 years ago

Yeah, this looks pretty good right now. A few tiny things:

  1. I'd mark each of the procs with a {.inline.} pragma so we get a tiny performance boost, since these will probably be called a lot.
  2. Does sdl2.getPerformanceFrequency() return the same value each time it's called? If so, we should cache it in another variable at the init() step
  3. Isn't getTimeSinceLastTick() a little redundant?
  4. I don't think getTime() is needed. Unless someone wants the time since application start and not tick time start. I'll leave decision up to you.
  5. Maybe some renamings:

We also need some documentation to explain what is the different between a tick and a delta and how to use what functions in the game loop.

define-private-public commented 6 years ago

I saw your commit and left some notes inline. Please take a look at them:

https://github.com/zacharycarter/zengine/commit/20751d70870a372cb234633b7b8a3cdc01076771

define-private-public commented 6 years ago

As a side note, next time can you make a separate branch then make a PR for it instead? I'd rather do review there than do it inline with a commit in master.

define-private-public commented 6 years ago

Hey, I tried out what you have put in the timer module right now and it's kind of incorrect.

E.g. I though we were going to have the deltaTime() function return time in seconds. But instead, each tick it's giving me 16.6667 per tick. It should be 0.01666667. I'll post a PR tomorrow that uses this behavior and better defines the documentation. I'd also like to adjust the names to fit what I have above, but I'll keep what you've got.

You might need to go back and adjust your examples, though it shouldn't be too hard.