Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Timer module #21

Closed
zacharycarter opened this issue Aug 18, 2017 · 11 comments · Fixed by #35
Closed

Timer module #21

zacharycarter opened this issue Aug 18, 2017 · 11 comments · Fixed by #35

Comments

@zacharycarter
Copy link
Owner

Continuing discussion from : #13

@define-private-public
Copy link
Collaborator

define-private-public commented Aug 18, 2017

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
Copy link
Owner Author

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
Copy link
Collaborator

eh, I just like objects.

@define-private-public
Copy link
Collaborator

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
Copy link
Collaborator

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
Copy link
Owner Author

I'll work on this after work today.

@zacharycarter
Copy link
Owner Author

zacharycarter commented Sep 7, 2017

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
Copy link
Collaborator

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:
  • getTicks() -> totalTicks(): Drop the get and better define what the proc does by the name.
  • getDeltaTime() -> deltaTime(): Drop the get.
  • init() -> start()/startTicking().: start() is a really ambiguous name.

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
Copy link
Collaborator

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

20751d7

@define-private-public
Copy link
Collaborator

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
Copy link
Collaborator

define-private-public commented Sep 9, 2017

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.

define-private-public added a commit to define-private-public/zengine that referenced this issue Sep 9, 2017
As mentioned in a few commit comments and issue zacharycarter#21, the first round of
the timer module looked a little wrong (e.g. it was giving us
milliseconds for `deltaTime()` when it should have been giving us
seconds instead).  This commit fixes that and removes a little cruft.

Under the hood all of the times are measured in hard integers, but the
programmer is given a floating point interface to using the time.

On top of that, the timer module now has a `Timer` object.  The
rationale for this is two fold:

1. This makes the `Timer` less tied into the engine internals (i.e.
independant).
2. Users may need timers for other things (e.g. spell cooldowns, time
trials in racing scenarios, making a day n' night cycle; the list goes
on).  Before we only had one global timer.  Now we've got many that the
user can use (and resuse).

I've also added some documentation better explaining things.  (I should
maybe add some drawings too).

closes zacharycarter#21
@zacharycarter zacharycarter moved this from Backlog to In Development in Sprite Implementation Sep 10, 2017
@zacharycarter zacharycarter moved this from In Development to Acceptance Testing in Sprite Implementation Sep 10, 2017
@zacharycarter zacharycarter moved this from Acceptance Testing to Done in Sprite Implementation Sep 10, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

2 participants