views:

79

answers:

2

I'm not sure if the term real-time is being misused here, but the idea is that many players on a server have a city producing n resources per second. There might be a thousand such cities. What's the best way to reward all of the player cities?

Is the best way a loop like such placed in an infinite loop running whenever the game is "live"? (please ignore the obvious faults with such simplistic logic)

foreach(City c in AllCities){
  if(c.lastTouched < DateTime.Now.AddSeconds(-10)){
    c.resources += (DateTime.Now-c.lastTouched).Seconds * c.resourcesPerSecond;
    c.lastTouched = DateTime.Now;
    c.saveChanges();
  }
}
+5  A: 

I don't think you want an infinite loop as that would waste a lot of CPU cycles. This is basically a common simulation situation Wikipedia Simulation Software and there are a few approaches I can think of:

  1. A discrete time approach where you increment the clock by a fixed time and recalculate the state of your system. This is similar to your approach above except do the calculation periodically and remove the 10 seconds if clause.
  2. A discrete event approach where you have a central event queue, each with a timestamp, sorted by time. You sleep until the next event is due and then dispatch it. E.g. the event could mean adding a single resource. Wikipedia Discrete Event Simulation
  3. Whenever someone asks for the number of resources calculate it based on the rate, initial time, and current time. This can be very efficient when the number of queries is expected to be small relative to the number of cities and the elapsed time.
Guy
2. is especially nice when you have good event support in your language of choice. 3. can get a bit tricky when there are outer factors which can change the production rate at times, although one could push the factors to a stack and then recompute back in time when requested.
Ivo Wetzel
A: 

while you can store the last ticked time per object, like your example, it's often easier to just have a global timestep

while(1) {
  currentTime = now();
  dt = currentTime - lastUpdateTime;

  foreach(whatever)
     whatever.update(dt);

  lastUpdateTime = currentTime;
}

if you have different systems that don't need as frequent updates:

while(1) {
  currentTime = now();
  dt = currentTime - lastUpdateTime;

  subsystem.timer += dt
  while (subsystem.timer > subsystem.updatePeriod)  {// need to be careful
       subsystem.timer -= subsystem.updatePeriod;    // that the system.update()
       subsystem.update(subsytem.updatePeriod);      // is faster than the 
  }                                                  // system.period

  // ...
}

(which you'll notice is pretty much what you were doing on a per city basis)

Another gotcha is that with different subsystem clock rates, you can get overlaps (ie ticking many subsystems the same frame), leading to inconsistent frame times which can sometimes be an issue.

Jeff Gates