Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Transport Tycoon is a simulation game where you control a transport company, place railroad tracks and trains, airports, bus depots, boats etc. Now the game is about 15 years old and I remember running it on a 486sx25 with 4Mb of RAM without any problems.

I was recently thinking about modern simulation game requirements and how high they are for relatively little increase in graphics and gameplay, so how did they managed to pull it with so little resources back in the day?

Does each train car have a thread, that moves it every 100ms, sleeps, wakes, recalculates position and does crash detection, and goes back to sleep?

Or is it one thread that moves every 100ms? What happens if there is too much work to do in each 100ms interval?

share|improve this question

closed as off-topic by Josh Petrie Jan 5 at 16:30

  • This question does not appear to be about game development within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

Was multi-threaded even a thing 15 years ago? But even if this game were implemented today I wouldn't expect it to have each train car on a separate thread. – jhocking Jan 12 '12 at 12:58
I'm voting to close this question as off-topic because it is about how a specific game implemented a specific feature. – Josh Petrie Jan 5 at 16:30
@JoshPetrie Asking how a specific game implemented a specific feature is not a game dev topic? You are misinterpreting the help center. Sure, it mentions that questions about "what technology some particular game used" aren't welcome. But is the help center who is wrongly worded: it points to the meta question… where one can clearly see that the discussion was about forbidden questions on how entire games were made. Not questions about specific feature implementations. Which are obviously useful – Louis15 Jan 14 at 3:32
@Louis15 No, these questions are still considered off-topic as discussed here, and it's a long-standing policy. You are welcome to post a new meta topic on the subject if you'd like to re-open the discussion. However, it's a good point that this is not called out in the help center despite being a common issue, so I've added the link to the appropriate meta thread. – Josh Petrie Jan 14 at 3:40
@JoshPetrie In that case, I suggest the link you've just sent to be the one the help center forwards to. – Louis15 Jan 14 at 3:44
up vote 8 down vote accepted

The real question is, how does modern games use so much memory?

I have very sparse knowledge of Transport Tycoon, so the following is only a generalisation of how such games would be made at that time.

The game would be single threaded, split into two primary portions, game logic, and rendering.

In game logic elements are represented as only a few bytes each, the map is probably a 2D array, implemented as a flat space of memory with the implicit mapping that each tile is stored in position Xcoordinate + mapWidth*Ycoordinate, with probably just a single byte for each tile signifying one of up to 256 possible combinations of terrain and structures. Stuff like trains is a bit more complex, they'd have X and Y coordinate, possibly using 16 bit integers for each getting pixel perfect or better positioning, then there is cargo, speed, rotation, route and possibly some other stuff, but all things that you can express using a few integers.

On each update the game will use a simple loop to go through all trains, move them, increase or decrease speed as required, for collision detection either a simple double iteration over the array of trains will be used, or an array will be filled with with train positions thus requiring some memory to be cleared for every update but avoiding a costly double iteration.

The rendering part will go through the part of the map array that is currently in view, for each tile it will copy the image corresponding to the value of that tile to the output buffer in video card memory. Then the trains in view will be blitted onto the output buffer.

Depending on how the game is written it will if there is not enough processing power to do all the required tasks either simply slow everything down, or skip some of the rendering, thus lowering the framerate but keeping the game itself running at constant speed.

There are some thing from this example that can be used in modern programming:

You do not need fancy stuff like multi threading and events, you should try programming without them, not because they are bad tools, but learning the alternatives broadens your toolbox and helps you to better pick the right tool for the job.

One of my favourites, you can actually count memory use. Some modern languages makes it a bit harder by using a lot of memory that doesn't correspond directly to the resources you use, but it doesn't make it impossible. If you make one 32 bit integer, that is 4 bytes, if you make an array of 1024 such integers that is 4 kB, if you load a 640x480 image into memory as a 32 bit ARGB texture, that is 1200 kB. People should in general count memory use way more that they do, it's a great tool for planning.

Game logic typically doesn't need a lot of memory, some games use a lot anyway because they can, but often that simply means the developers then have to deal with representing all this information in a way that makes it easy to understand for the player. The big memory spender is always graphics, if not you are probably doing something wrong.

And finally to justify my own question, let's count memory use for my description of a game like Transport Tycoon. Let's say for a period typical example, the game use 8 bit colour, the tiles are 16x16 pixels, the biggest map supported is a whooping 256x256, there are 16 different locomotives and 32 different carts, the trains can go 8 different directions, thus 8 images for each locomotive is needed, and 4 for each cart is needed as they look the same rotated 180 degrees, that is 256 images, plus 256 blit masks. All these images are 16x16 pixels. This gives a total of 768 16x16 pixel 8 bit images, thus a total of 192 kB memory for storing all graphics assets.

The map use 64 kB.

Supporting up to 255 stations and 255 trains, with up to 32 stations on each trains route, all will need 16 bytes for a name. The stations will need 2 bytes for coordinates and 32 bytes for stocks of goods, thus 50 bytes total for a station. The trains have up to 6 carts each need 1 byte for type of cart, 1 for amount of content, 4 bytes for position and 1 for rotation. The train need 1 byte for type of locomotive, 32 bytes for route, 1 byte for next stop on route, 1 byte for speed, 4 bytes for position and 1 byte for rotation. 98 bytes total for a whole train. All this sum up to less than 37 kB for trains and stations.

the output buffer is 320x200 pixel at 8 bit per pixel, thus 62.5 kB of video memory, 125 kB to implement switching buffers.

Assume 90 kB of code and we are right around the ½ MB mark total. I have surely forgotten something in this count, but probably nothing major, and it is very typical for a period game to stay below the 640 kB mark, thus avoiding having to deal with expanded or extended memory and the possible problems this would cause for users.

If you do the numbers for a modern game you'd probably end up wondering why PC games need so much memory, indeed the modern consoles seem to do pretty well with only 512 MB of memory, there can be A LOT of textures in that space when you start to think about it.

share|improve this answer
Wow. Thanks for explanation, it makes sense. You say on each update? How/when is an update determined, is it just a continous loop with no sleep and we leave the co-operative multi-tasking to the OS so depending on speed a 486sx might update game logic 6 times a second and a modern computer 600 times a second (the logic takes current epoch timestamp to determine dist to move etc..)? – asdsadasd22 Jan 12 '12 at 17:23
You should look into gameloops and the use of deltaTime. – Tili Jan 12 '12 at 17:54
In the example game it is almost certain that the updates occur at a fixed interval, it uses a loop, but enter into small cycles of nop commands whenever the game would otherwise go ahead of schedule. With an old OS that would simply cause the CPU the use less power, with a new OS another task can take over. As for using variable time step and compensating by varying how much each step changes the world, don't do it, at least not until you are confident enough in you own judgement that you would dare to disregard my advice. – aaaaaaaaaaaa Jan 12 '12 at 19:30
eBusiness, thanks a lot. Tili, found some good articles will read. On a modern OS or rather in a high-level programming lang such as C# or JavaScript nop is a sleep? – asdsadasd22 Jan 13 '12 at 4:39
I'm not actually sure whether you'd normally compile high level code to contain nop commands, or delegate the actual noping to the OS through a system call. To a normal programmer it doesn't really matter how it's done, there is a sleep or similar command in most languages and it works. – aaaaaaaaaaaa Jan 13 '12 at 14:29

Multi core machines became a thing in consumer machines one generation after Pentium 4, that's 4 generations after 486 machines.

When there was only one CPU, using multiple threads to operate on the same data set and having to worry about synchronizing data was just plain stupid, because there was absolutely no benefit at all. Keep in mind that the threading libraries and support for thread safe data structures were awful at that time.

If the work finishes before your 100ms interval ends, you sleep (or busy-wait) until the start of the next interval. If you run out of time, you finish work normally and just start the next frame immediately, slowing the game down. You might consider time that passed since the last frame, so if you're behind you calculate what happens in the next 150ms instead, but I doubt they did that.

Regarding memory, many of today's non-managed programs require less than 4 MB, if you disregard the GUI layer. A pretty high resolution GUI requires a lot of memory, and even more because we can easily waste a couple megabytes to make programming easier. Also keep in mind, in those times we usually worked with 16 bit, not 32 bit.

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.