Millisecs since year xxxx/1900
Monkey Forums/Monkey Beginners/Millisecs since year xxxx/1900
| ||
I can't find a function for this, wasn't this a standard function in Unix? Do other languages also have a function for this or would you need to write one? Just thinking about time management type games where something might take 5 hours to "grow" - using the Millisecs() function is obviously not going to work in this situation since the user might quit from the app and come back later. It's not an overly difficult function to create, but if it is in there somewhere that I can't find, why recreate the wheel :) If it's not currently available,, I'll write a function to do it and post it here - feel free to post your own solution though - I'm sure it can be coder a lot better than I'll do it. On a somewhat related subject, working out if a year is a leap year was one of the very first programming exercises I was given when I first started studying programming in tertiary education nearly 25 years ago - yeah it's simple, but they started everyone from a level of knowing nothing about programming so this sort of thing was a good starting point. I think we also had to convert the year into Roman numerals - which is not as easy as you might think. |
| ||
I haven't used it, but AFAIK App.GetDate() should meet your needs. |
| ||
It's not necessarily what you're looking for, but my 'regal.eternity' module may be interesting to you. I haven't messed with it in a while, but it should still work. The problem with 'eternity' is that long durations are approximated. The only way to fix this is to slow it down significantly, which may be what I'll do later down the road. It may have dependencies. If so, the rest of 'regal' is needed to use it. It's not bad as a reference, though. |
| ||
Monkey only guarantees 32 bit integer and float cross platform so an API should ideally use a type that keeps seconds and nanos (10-9) in two distinct fields. Calculating elapsed times with separate fields means you need to do a special 10^9 carry check on the nano portion but otherwise it's pretty simple and it seems that nanos are the new millis in most modern OS time stamps so hooking it up to native API will in most cases be quite painless. |
| ||
@Gerry Quinn - yep GetDate is the function to use, but working out the millisecs elapsed will be left up to you as the programmer. @skid - yeah I did notice that obviously an INT will not be adequate. Depending on the type of time management game, millsecs may not even be necessary. Farmville for example, where something takes 8 hours to grow - it would be neither here nor there tracking 8 hours down to the exact millisecond. Other games (like Cooking Fever that I'm currently hooked) on - where stuff takes 6-10 seconds to cook, then tracking stuff to the millisec is important. The only tricky, well it's not that tricky, really is handling the time when a player puts the game into suspend or hits a pause button. It's then not a simple matter of current time - start time = total time. I know how to get around this. Again, I'll probably go no where with this, but it is interesting to me anything to play some games and think programatically as to how they are doing what they are doing. I'll still write the millsecs elapsed since 19xx function when I can be bother, I'm sure someone will find it useful. EDIT: Thinking about the Int issue - if you aren't going to used the unsigned portion, then it really only leaves room for 68 years give or take for the number of seconds elapsed. For what I've described above - in the Farmville example it doesn't matter about storing time when the game is paused but in these games, things continue to happen when the game is unattended. For the Cooking Fever example, it's only necessary to track time while the game is active - possibly making what I was asking in the first place a complete moot question :) A more useful library would be date functions where you can pass in the standard date array that Monkey uses, choose to add or subtract a period from this and then return the results in a new array as well as obviously getting time differences between two dates & times. |
| ||
@Gerry Quinn - yep GetDate is the function to use, but working out the millisecs elapsed will be left up to you as the programmer. @skid - yeah I did notice that obviously an INT will not be adequate. Depending on the type of time management game, millsecs may not even be necessary. Farmville for example, where something takes 8 hours to grow - it would be neither here nor there tracking 8 hours down to the exact millisecond. Other games (like Cooking Fever that I'm currently hooked) on - where stuff takes 6-10 seconds to cook, then tracking stuff to the millisec is important. The only tricky, well it's not that tricky, really is handling the time when a player puts the game into suspend or hits a pause button. It's then not a simple matter of current time - start time = total time. I know how to get around this. Again, I'll probably go no where with this, but it is interesting to me anything to play some games and think programatically as to how they are doing what they are doing. I'll still write the millsecs elapsed since 19xx function when I can be bother, I'm sure someone will find it useful. EDIT: Thinking about the Int issue - if you aren't going to used the unsigned portion, then it really only leaves room for 68 years give or take for the number of seconds elapsed. For what I've described above - in the Farmville example it doesn't matter about storing time when the game is paused but in these games, things continue to happen when the game is unattended. For the Cooking Fever example, it's only necessary to track time while the game is active - possibly making what I was asking in the first place a complete moot question :) A more useful library would be date functions where you can pass in the standard date array that Monkey uses, choose to add or subtract a period from this and then return the results in a new array as well as obviously getting time differences between two dates & times. |
| ||
Just back to the Cooking Fever example, here is a quick little program I ripped up. I'm sure there are better ways to do certain things, so please elaborate if you know of a better way of doing things - particularly the handling of whether a key is pressed or not. Currently I check if it's hit, and then wait for it to be not down before checking if it's down again if that makes sense. Otherwise holding down the key A (places a new burger on the grill) or P (Pause) will just put all the burgers down really quickly or toggle pause on/off/on/off really quickly. Anyway... Press A to place a new burger on the grill - it cooks in 10 seconds and burns after 15 seconds. Press P to pause the "game" during which time nothing is cooked until the game is unpaused. CookClass.Monkey Import mojo Class Burger Field cookingTime:Int Field x:Int Field y:Int Field burnsAt:Int Field doneAt:Int Method New(burgerNo:Int) Self.cookingTime = 0 Self.burnsAt = 15000 Self.doneAt = 10000 Self.x = 50 Self.y = 100 + burgerNo * 50 End Method Method Draw() SetColor(0, 255, 0) If Self.cookingTime < doneAt Then SetColor(255, 255, 0) If Self.cookingTime > doneAt And Self.cookingTime < burnsAt Then SetColor(0, 255, 0) If Self.cookingTime > burnsAt Then SetColor(255, 0, 0) DrawRect(Self.x - 16, Self.y - 16, 32, 32) SetColor(255, 255, 255) End Method End Class CookingGame.Monkey Strict Import CookClass Function Main:Int() New Game() Return 0 End Class Game Extends App Field burgers:List<Burger> = New List<Burger>() Field burgerOn:Bool = False Field gamePaused:Bool = False Field keyIsDown:Bool = False Field lastMillisec:Int Field currMillisec:Int Method OnCreate:Int() SetUpdateRate(60) Return 0 End Method OnUpdate:Int() lastMillisec = currMillisec currMillisec = Millisecs() If KeyDown(KEY_P) And Not keyIsDown Then keyIsDown = True If gamePaused Then gamePaused = False Else gamePaused = True EndIf If gamePaused Then Print "Paused - Burgers are no longer cooking" Else Print "Resumed - Burgers are cooking again" EndIf If Not KeyDown(KEY_P) Then keyIsDown = False EndIf If KeyDown(KEY_A) And Not burgerOn burgerOn = True If burgers.Count() = 3 Then Print "Don't be greedy, only 3 burgers at once please" Else burgers.AddLast(New Burger(burgers.Count())) EndIf EndIf If Not KeyDown(KEY_A) Then burgerOn = False EndIf If Not gamePaused Then For Local x:Burger = EachIn burgers x.cookingTime = x.cookingTime + currMillisec - lastMillisec Next EndIf Return 0 End Method OnRender:Int() Cls() DrawText(1000 / (currMillisec - lastMillisec) + " FPS", 10, 10) Local y:Int = 100 For Local b:Burger = EachIn burgers DrawText("Burger cooking for " + b.cookingTime, 100, y) b.Draw() If b.cookingTime < b.burnsAt Then DrawText("Burger is " + b.cookingTime + " millisecs old", 300, y) Else DrawText("This burger is toast! You left it on too long", 300, y) EndIf y = y + 50 Next Return 0 End Method OnLoading:Int() Return 0 End Method OnResize:Int() Return 0 End Method OnSuspend:Int() Return 0 End Method OnResume:Int() Return 0 End Method OnClose:Int() Return Super.OnClose() End Method OnBack:Int() Return Super.OnBack() End End The whole point of the code is just to see work out how to handle games where things "happen" in real time but you also want the game to suspend when the user pauses the game for whatever reason. |
| ||
"The whole point of the code is just to see work out how to handle games where things "happen" in real time but you also want the game to suspend when the user pauses the game for whatever reason." Another option is to have a 'non-paused' timer at app or window level - similar to your cookingTime but global or used my many objects within a given reference frame. Objects will refer to this instead of the real timer or Millisecs, so when you pause the game, all the animations automatically stop, and when you unpause they will continue where they left off. A similar idea is wrapping the PlaySound function in your own function that checks the sound on/off setting, so you don't have to worry about it elsewhere. Again, your game is running in an environment sheltered from user interface details it doesn't want to know about. |
| ||
@Gerry - I think I get what you are saying. Both what I've done and what you've suggested should work equally well though (I think?). I can't see either method having a drastic effect on the speed of the app which is the most important thing - e.g. it runs at close to 60fps if you are trying to run at this speed. |
| ||
Oh absolutely, it won't significantly affect speed - it's purely a matter of convenience. And if you don't have multiple types of objects that need individual pause checks, there's not even much in the way of convenience involved either! It's just that if you do have many types, it's easier to make time stop for your game as a whole, by not giving its objects access to the actual time. |
| ||
Yes, that does make a lot more sense doing it that way. For the type of game I'm playing, you're looking at probably 12-20 objects, so it probably does make sense to do it the way you describe. |