Hime-Works / Requests

Bug reports and requests that may require longer discussions and is not suitable to leave on the blog
http://himeworks.com/
GNU General Public License v2.0
7 stars 9 forks source link

Time System in RM #72

Open HimeWorks opened 10 years ago

HimeWorks commented 10 years ago

There are several time-related systems available already. From the master script list

The purpose of this topic is to discuss what a time system should have, and how to easily integrate that into RM (in particular, with events). Existing implementation of time (outside of RM) may be useful as well.

The various time systems can then be examined to see what things have been done well, and what could be improved, or should be improved.

What Time is it?

There are two general approaches to the notion of time in your game world.

  1. Use an in-game time. Time depends on the game's state. It could be the frame count, or some other variable that is updated parallel to the game.
  2. Use an external clock. Time in such a system is independent of the game's state.

Many games use their own in-game time system. For example, maybe you can only enter a dungeon during the first 15 minutes of each hour of game play. This would really only work for single player games, but you're not forced to have to get up at 3 AM just to do a particular quest.

An in-game time would not have to be based on any sort of existing time system either; you could invent something that would be suitable for your world. You could still use our hour/minute/second system, but maybe make it so that an hour in the game is equivalent to a minute in real-life.

Because I am focused on the development of single player games, I will mainly focus on how to implement an in-game time system, but this could be generalized to external time systems since as you would change the point of reference from, for example

Graphics.frame_count

in the case of in-game time, to

Time.now

If you want to use earth time.

What do we need to know about time?

For the most part, all you need to know is how to answer "What time is it?", which requires us to be able to describe time in a standard way.

Because the use of "years", "months", "days", "hours", "minutes", and "seconds" is likely the most familiar with the general audience, it may be suitable to just adopt that.

How to tell time

The general rules that we use for our own time system can followed, assuming a second is the smallest unit of time. In reality, that's not the case, as we can divide a second into an infinitely small fraction of a unit simply because time is continuous, but if we're working with frame counts, that may be a bit difficult. Introducing a separate variable for the purpose of time-tracking would solve the problem, but then you might still need to figure out how to work out the flow of time given your frame rates.

Using the familiar time conventions on earth, we have the following relationships, assuming a frame rate of 60.

1 second = 60 frames
1 minute = 60 seconds
1 hour = 60 minutes
1 day = 24 hours

Months are annoying due to all sorts of astrological reasons that we could realistically ignore since our game world does not necessarily have elliptical or tilted orbits that would account for the various "exceptions", but those details should be taken into consideration if you were trying to model your game time based on earth time, where you have 29 days in February every so often.

_Generalizing time units _

When it comes to in-game times, frame count is one unit of time, but it isn't necessarily the one you might want to use.

The frame count is updated as long as the game is running. It doesn't matter whether you're in a battle, a cut-scene, going through your menu, sleeping in an inn, etc. Maybe certain things shouldn't change the game time.

Sometimes, you want the flow of time to be altered. Maybe sleeping will fast-forward time by 8 hours. Maybe training will fast-forward time by a week.

A separate "time" variable could be used as the unit of the time, and everything would be based on this variable. Similarly, a minute in your game world might not be 60 seconds. It should be possible to easily define how many seconds there are in a minute using simple constants so you can quickly change how time works in your world.

You may want to add new units, change names, and so on.

Using time in events

This is the most crucial element of this discussion, and really all that matters for the most part: how can we use time during our development.

At this point, it is not very clear what would be the easiest to use.

Given that there are a number of scripts that allow you to extend the event system such as custom page conditions, we have a number of feasible options available to choose from. We can of course provide every option so that different people with different preferences can pick what they are most comfortable with.

Roguedeus commented 10 years ago

When I was involved with design planning on an online strategy game way back in early 2000, I had designed a calendar that was analogous to real time, but compressed by a significant factor. I had even organized the was constellation would rise and fall, giving 'expected' magical adjustments to the world depending on which deities constellation was at apex, etc... It was a whole lot of work for what amounted to nothing. :p But it was fun.

My advice in this regard would be to use an external reference for time, with a compression value that could be changed via script call (or something). Such that normally the compression may be 20:1 (ie: 1 in game hour in 3 real minutes) when the value is 20.0 but can be assigned any float for a set number of real seconds, to simulate accelerated or decelerated time.

Example: A world event may prolong night time, and reduce day time.

Of course, the challenge then, is how to display this passing of time to the player, if desired. As compressing/decompressing time speeds/slows the displayed time. And adding/subtracting time from day/night/seasons can be extremely subjective and difficult to plan for.

In those cases I'd suggest allowing for a sort of timer that counts down the real seconds and then executes a script of some sort...

Example: Day/Night Timers = 43,200 each

12 in game hours, 36 real minutes (2,160 real seconds * 20:1 compression) which simulates 12 real hours (43,200 seconds / 20.0 compression = 2,160) Thus for every real second that passes, 20 is subtracted from the timer.

So, if day and night are all the developer wants to track, when the game starts for the first time, the master reference clock starts counting the compression seconds' and subtracting them (at current compression) from the Day Timer. Once the Day Timer reaches 0, it triggers the start of the Night Timer which then begins ticking.

If they wanted to start the game in the early middle of the day, then the Initial Day Timer would be set to about 26,000. Which would correlate to about 11am. (starting the days at 6am)

This way in game events can simply be added to the list of timers that compression is deleted from, every real second.

I hope I explained that adequately.

Roguedeus commented 10 years ago

Note: I think providing an in-game clock (with am/pm timing) is asking for headaches. Instead, provide for a 'time regions' that the player can setup for a current timer.

Example: Starting at 6am : DAY [Early][Morning][Noon][Afternoon] / NIGHT [Evening][Night][Mid-Night][Twilight] Thus a 43,200 value Day Timer, would be split into 4 : 10,800 segments for being inside a specific 'time region' though the exact number of segments and their size can be defined, as long as all regions sum up to the total timer.

Roguedeus commented 10 years ago

In use?

If the compression changes, all that would happen, is that the total time for each time region would get longer or shorter.

Event triggers?

If the Day Timer was not active, it would default false.

HimeWorks commented 10 years ago

The compression idea makes sense. It would make calculations easy to do. It is also a reasonable way to implement scaling in general.

For the passing of time, given the compression, would it be strange to see the minutes and hours ticking by at faster or slower rates?

I like the idea of using constants to reference different times of the day, since that abstracts away the actual hours, allowing you to easily adjust when they begin and end. However, if someone literally wanted to micro-manage their events and say "from 6:30 AM to 6:45 AM', using these named regions probably wouldn't help very much.

Roguedeus commented 10 years ago

They can simply split the timer into as many regions as they like... I know I said 4, but it could easily be 12 (1 for each hour) or 48 (1 for each 15 minutes). Of course, it would require a very small compression to allow for enough time to do it in such a small window.

edit: Also they could chain several smaller timers, all about 1 in game hour each, and then segment those 4 times into 15 minute windows.

Roguedeus commented 10 years ago

The game I cut my script/code teeth on way back when was an RPG (Never Winter Nights) that used a tick timer for all in game time. It was rather simple. There where 20 ticks every minute, and all game time was abstracted from there.

// v1.09
//
// inc_timing
// Rogue Timing
// By: Rogue
// 24-Jun-08
/////////////////////////////////////////////////////////////////////////////////////
/*  Notes:

    To prevent the use of the modules OnHeartbeat event as much as possible.
    To count vertual heartbeats upon time advances. (Not requiring actual beats)

    Seconds Conversions (default NWN2 timing is 2 minutes per hour)
    Hour =  120    seconds
    Day =   2880   seconds
    Month = 80640  seconds
    Year =  967680 seconds
    Example: 1 year, 2 months, 9 days = 1,154,880 seconds

*/
/////////////////////////////////////////////////////////////////////////////////////
HimeWorks commented 10 years ago

Hmm I wonder where I heard of that game. I think it was mentioned in MarkeeDragon videos that I watch on youtube from to time.

I think the main concern I had was how to reference each region. Using names like "noon" and things were ok, but then once you started getting into really small fractions to account for things like 15 minutes of an hour, people would probably have to get creative. Naturally, such a time system would allow you to define these regions and the names you want to give them.

I'd have to re-read the ticking down idea several times over before understanding how it works, and how it addresses the different challenges that are raised.

Would the Day/Night timers be considered two regions?

Or is the design meant to allow you to divide a region into sub-regions, which can further be divided? eg:

timers[:day].regions[:noon].regions[:first_quarter]      # first 15 mins of the "noon" region
timers[:day].regions[:noon].regions[:second_quarter] # second 15 mins of the "noon" region
Roguedeus commented 10 years ago

That's a good point about naming. I would think that if you wanted to, you could create 24 timers all chained, that where called 12am, 1am, 2am, ... 12pm, 1pm, 2pm... etc... Then create 15 minute regions in each timer First Quarter, ... etc. So it would be timers[:3pm].regions[:First Quarter]

Conceivably, you could also have a graphic that changed to indicate the current hour, each time the next am/pm timer started. Of course, second and minutes will be a problem with compression changes.

...

The Day/Night timers would be separate timers that ran serially. one after the other. Game Start = Trigger:Day Timer:Start > Day Timer:End = Trigger Night Timer:Start > repeat.

...

This may read a bit rambling, but I'll try to give an example of a new game start. The numbers involved are only for ease of explanation and not correlated to any real ratios.

Master Timer decrements all active timers by the compression value.

Timers are essentially an integer value indicating the 'simulated' time in total compression. If a timer was to represents a simulated real world hour, it would be given a value of 3,600 seconds. But for our purposes this fake hour could be 100 seconds.

Compression is the amount of simulated seconds that is removed from each active timer, every REAL second. Thus if compression was set to 10.0 the above 100 second timer would reach 0 in 10 REAL seconds.

Regions are value windows that return true, if their Timers current value is within them. Thus the above 100 second timer, with a region of [50,25] would only return true if the 'Master Timer' had removed enough seconds from the 'Timer' to bring its value to 50 or below, but not 25 or less. (the third quarter of the timer) These regions could be auto calculated to be an equal division of X regions, or manually setup.

In the Day/Night example, there would be two Timers, with only one active at a time. When the Day Timer reached 0, it would be erased while pushing the Night Timer into the Master Timer to begin decrementing like normal.

Roguedeus commented 10 years ago

I might note that this process is meant to be very rough, due to the nature of the game. The developer may want to pause time all together, or skip time, so worrying about any errors between fractions of seconds from the end of one timer to another is moot. Functionally the player wont see even feel it.

Also, I should probably note that the names for things are arbitrary. Timer, Compression, Region, whatever. This is just something I threw together in my head many years ago, but never got around to trying out.

HimeWorks commented 10 years ago

I think as a user, I would be struggling to understand how the whole time system works. Without any experience with time systems, I would probably go into it thinking "well, I want this page to be active from 6:15 PM to 6:30 PM", and then look for a way to accomplish it.

Using time regions, I would first have to create my timers, and then create my regions. While it would allow me to create complex time systems that is more manageable than hardcoding specific times, for simple cases, it may be too much work.

However, lack of prior experience here is important, because it means I don't know how manage-able a "simple" time system would be for large games. For example, supposing flow of time never changes, that seasons don't matter, and most astronomical phenomena were not required to be accounted for, would the use of regions to account for these challenges (which we conveniently remove for the sake of simplicity) still be a feasible solution?

Perhaps implementing these time regions and countdown tickers would be useful if someone wanted to get into a really complicated system, but a more "simplified" way of getting the current time would also be available for those that don't need the extra stuff.

It may be useful to look at how the existing time systems have been implemented, and how they have addressed the various challenges (if they chose to address them at all).

Roguedeus commented 10 years ago

Sure. The actual back end can be invisible.

You can aska few questions, such as:

And thats about it.

You can provide a name solution for each hour, and a way to access each hours pieces (regions).

Roguedeus commented 10 years ago

Come to think of it, you can do something similar to your managers... The Timing Manager, and use Plugins to create default setups for users and wacky custom ones.

Roguedeus commented 10 years ago

Or not. I enjoyed thinking about it. Its been a while since I had a reason to.

HimeWorks commented 10 years ago

Looking at this script: http://pastebin.com/bXXaZhpQ

It does basically that. First, it asks how many frames there are in a second (eg: 60). It then asks you to store this "time lapse" in a variable, which you can control easily. This would allow you to manipulate the rate of time.

It then defines the other units of time using things like "seconds per minute" and "minutes per hour". The months themselves are hardcoded, as well as the number of days per month.

Separate variables are used to store the time, one for seconds, minutes, etc., effectively separating them from the frame count, allowing you to pause time whenever you want (eg: battle, menu, etc).

For the most part, using the time in conditions requires you to explicitly check different units (eg: hour > 8 and hour < 12 ?).

It addresses the rate at which time passes. As long as you change how many frames occur per second, you can change how fast time proceeds in the game compared to real world.

Since there are no support for regions, it would require a lot of effort to implement things like timezones, daylight-savings, or any sort of reason why evening would be 5 PM at one point in time, but 6 PM at another. Because time regions allow you to avoid hardcoding numbers, you can easily adjust the values during the query to account for any time-changing factors based on the current game state.

Roguedeus commented 10 years ago

Yeah. When I imagine a time system I wouldn't couple it to real time any more than to measure each new second. There are way to many headaches.

HimeWorks commented 10 years ago

At the very least, time regions should definitely be included in any time system. It is a very easy way to provide a layer of abstraction and makes for more manage-able code/events.