Required to replenish resources/nature in 2d.

Started by
6 comments, last by BaneTrapper 9 years, 11 months ago

Hello.

In my progress to make 2d top down game i got stuck on a topic about resource refreshment / regrowth(The time period is bronze age,iron age)

I have a RTS kind of structure, you have units that can gather resources from map, but the map/resources will run out eventualy, and i want a way for them to replenish so i thought about nature growing back, it will add a nice spice.

My issue is that, i am kinda rusty on technical terms, and have found absolutely nothing while googling.

How i currently achieve resource regrowth is that i just place resource at random time, on map which provides quite unsatisfying results.

I thought about making areas for each specified stuff can spawn, so berry bush cannot just appear anywhere else but it regrows at specified place,(in radius of x). In the end the formula is will be quite fast and will provide with regrowth system but that is not very innovating, i think i could do more.

So i thought about making the nature expand logic for each biome separately. The nature would expand as such:

If there is a patch of dirt in forest area, and i do growth on it i would check whats nearby?(i found: grass, apple tree, flowers, berry bush). I would tier this stuff so i could have multiple stuff on one tile for, but no matching of type.


auto grass = 1;
auto flowers = 2;
auto berryBush = 3;
auto tree = 3;

From the example we can see that "berryBush" and "tree" could not occupy one tile at same time, but a tree, grass and flowers could.

This system could be done but the process consumption would be high.

Thus i am looking for alternatives, so if you have suggestions or if you know what a generic term it is so i could google it would help allot.

Advertisement

There's a multitude of ways to do this, but one novel idea is with leveraging cellular automata.

For instance, for each tile that borders a berry bush, give it a chance or number of turns to grow a new berry bush, optionally faster/higher based on the number of bushes it borders. This is sort of along the lines of what you were already thinking.

Check out something like Conway's Game of Life for an existing application of the concept.

EDIT: as for dealing with conflicts between different types of objects, I'd probably just use a percentage weight. e.g. if there's both a tree and a bush next to a tile, 60% chance the tree will take precedence. Maybe if you want something fancier you could modify that percentage based on the total number of trees vs. bushes, to keep a good proportion.

This system could be done but the process consumption would be high.

really?

unless your map contains like 1 million trees i dont really think it can be that much consuming...

This system could be done but the process consumption would be high.

really?

unless your map contains like 1 million trees i dont really think it can be that much consuming...

For example take in mind a small map of 100x100 tiles, checking each tile would take 4*radius + for(int i = 1; i <= radius; i++){i*4} so for radius of 3 the tiles check would be

4*3 + 4+8+12 = 36 tile checks, also check if out of bounds... so 100x100 = 10,000 * 36 = 360,000. Off course it could be optimized in many ways but i do not like the end result.

For example take in mind a small map of 100x100 tiles, checking each tile would take 4*radius + for(int i = 1; i <= radius; i++){i*4} so for radius of 3 the tiles check would be
4*3 + 4+8+12 = 36 tile checks, also check if out of bounds... so 100x100 = 10,000 * 36 = 360,000. Off course it could be optimized in many ways but i do not like the end result.


360,000 is really not much at all. Further, you aren't making those checks every turn - only when a plant needs to grow. Let's imagine you update the growth of plants once a second (really, once every 10 seconds would give perfectly fine results). Once a second, at 30 frames a second, means you are only updating once every 30 frames. So instead, break your 360,000 checks so they are spread out over the entire 30 frames - that's only 12,000 checks a frame.

But honest, 360,000 is not much. Also, checking if a tile needs to be updated once every 30 seconds would probably be acceptable.

Let's say you have a map that is 2,000 by 2,000 tiles instead of 100x100.

Take your map, of whatever size, and divide it up (mentally, not in code) into blocks that are 20x20 tiles. That's 400 tiles in each of these imaginary blocks.
If the map is 2,000x2,000, that is 10,000 imaginary blocks.

For each imaginary block in the map, update one tile per block each frame. Over twenty seconds, at twenty updates a frame, you'll have updated the entire map and would've spread your workload over 400 frames, instead of all at once. You could spread it out farther if you needed to (over 30 seconds, or over 45 seconds), and if performance permits, you could update more than 20 times a second.

To visualize it, you mentally take your map made of tiles:
Map_empty.png

Break it into mental blocks:
Map_split.png

One the first frame, update all the blue tiles (one tile from each block). On the next frame, update the orange tiles (one tile from each block), and so on. If the block contains 400 tiles (20x20), then after 400 frames you would've updated every tile on the map.


Despite my possibly butchered explanation, the code is ridiculously simple:


//"Constants"
BlockWidthInTiles = 20;
BlockHeightInTiles = 20;
 
MapWidthInTiles = 2000;
MapHeightInTiles = 2000;
 
MapWidthInBlocks = (MapWidthInTiles / BlockWidthInTiles);
MapHeightInBlocks = (MapHeightInTiles / BlockHeightInTiles);
 
//On each update:
int tileInBlockX = currentFrame % BlockWidth;
int tileInBlockY = currentFrame / BlockWidth;
 
for(int blockY = 0; blockY < MapHeightInBlocks; ++blockY)
{
	for(int blockX = 0; blockX < MapWidthInBlocks; ++blockX)
	{
		int tileX = (blockX * BlockWidthInTiles) + tileInBlockX;
		int tileY = (blockY * BlockHeightInTiles) + tileInBlockY;
		
		UpdateTileAt(tileX, tileY);
	}
}
 
++currentFrame;
currentFrame %= (BlockWidth * BlockHeight);

This physically spreads out the updating as well, so players don't notice one half of the map updating before the other half.
However, if that's not a concern, you could simplify things further by just using a 'scanline' type approach. For every frame, update one row of tiles in your map. If your map is 2000 tiles high, then over 2000 frames you'll spread out the updating. 2000 frames, at 30 frames a second, is less than 70 seconds for the entire map to have done one wave of growth.

Will a more complicated regrowth system make the game more fun?


Another way you could potentially cut down on the number of tiles to check might be to iterate over active resources instead of empty tiles; each resource might have a chance to spawn a copy into a randomly selected empty neighbouring tile. This would be less intensive on a sparsely covered map but potentially more intensive on a crowded one, and would ensure resources grow in clumps.

- Jason Astle-Adams

There's a bajillion possible optimization schemes for this. You can subdivide across frames like SOTL mentioned, then cache all the tiles that can have things grow on them, and maybe rerun that subdivision every 500 frames or something. Or, you can subdivide even more. All that's important is that your process works within the expected visible update timeframe.

Decide on your behavior and the rules that govern it, then come up with a way to make it work. You may have to make performance sacrifices like amortizing it over several frames, but what's important in the end is the end-user experience of the mechanic. Who cares if something takes ten frames, as long as the user doesn't realize it?

For example take in mind a small map of 100x100 tiles, checking each tile would take 4*radius + for(int i = 1; i <= radius; i++){i*4} so for radius of 3 the tiles check would be
4*3 + 4+8+12 = 36 tile checks, also check if out of bounds... so 100x100 = 10,000 * 36 = 360,000. Off course it could be optimized in many ways but i do not like the end result.


360,000 is really not much at all. Further, you aren't making those checks every turn - only when a plant needs to grow. Let's imagine you update the growth of plants once a second (really, once every 10 seconds would give perfectly fine results). Once a second, at 30 frames a second, means you are only updating once every 30 frames. So instead, break your 360,000 checks so they are spread out over the entire 30 frames - that's only 12,000 checks a frame.

...

Oh i got schooled cool.png. Yes it could be done easily because i already got Regions that are big chunks of tiles and Areas that consist of few regions.

Will a more complicated regrowth system make the game more fun?

There is a deep answer, but the quick answer is that it depends on a person playing it.

I got sufficient answers thank!

This topic is closed to new replies.

Advertisement