Random Land Algorithm in Tank Wars

Have you ever played the Tank Wars game?

enter image description here

I program this game using JavaScript + Canvas (for a personal task), and I need an algorithm to generate this random green earth every time I start the game, but I'm not too good at math, so I can't do it myself.

I don’t want someone to give me the code, I only need an idea for this algorithm.

Thanks!

+6
source share
6 answers

enter image description here
(9 segments)

Demo screenshot

enter image description here
(7 segments)

The main generation function is as follows:

var numOfSegments = 9; // split horizontal space var segment = canvas.width / numOfSegments; // calc width of each segment var points = [], calcedPoints; var variations = 0.22; // adjust this: lower = less variations var i; //produce some random heights across the canvas for(i=0; i < numOfSegments + 1; i++) { points.push(segment * i); points.push(canvas.height / 2.8 + canvas.height * variations * Math.random()); } //render the landscape ctx.beginPath(); ctx.moveTo(canvas.width, canvas.height); ctx.lineTo(0, canvas.height); calcedPoints = ctx.curve(points); // see below ctx.closePath(); ctx.fillStyle = 'green'; ctx.fill(); 

The curve() function is a separate function that generates a cardinal spline. Here you can change it to also store voltage values ​​to make more surges. You can also use the created points as a basis for where and at what angle the tanks will move.

Cardinal Spline Function:

 CanvasRenderingContext2D.prototype.curve = function(pts, tension, numOfSegments) { tension = (tension != 'undefined') ? tension : 0.5; numOfSegments = numOfSegments ? numOfSegments : 16; var _pts = [], res = [], t, i, l, r = 0, x, y, t1x, t2x, t1y, t2y, c1, c2, c3, c4, st, st2, st3, st23, st32; _pts = pts.concat(); _pts.unshift(pts[1]); _pts.unshift(pts[0]); _pts.push(pts[pts.length - 2]); _pts.push(pts[pts.length - 1]); l = (_pts.length - 4); for (i = 2; i < l; i+=2) { //overrides and modifies tension for each segment. tension = 1 * Math.random() - 0.3; for (t = 0; t <= numOfSegments; t++) { t1x = (_pts[i+2] - _pts[i-2]) * tension; t2x = (_pts[i+4] - _pts[i]) * tension; t1y = (_pts[i+3] - _pts[i-1]) * tension; t2y = (_pts[i+5] - _pts[i+1]) * tension; st = t / numOfSegments; st2 = st * st; st3 = st2 * st; st23 = st3 * 2; st32 = st2 * 3; c1 = st23 - st32 + 1; c2 = -(st23) + st32; c3 = st3 - 2 * st2 + st; c4 = st3 - st2; x = c1 * _pts[i] + c2 * _pts[i+2] + c3 * t1x + c4 * t2x; y = c1 * _pts[i+1] + c2 * _pts[i+3] + c3 * t1y + c4 * t2y; res[r++] = x; res[r++] = y; } //for t } //for i l = res.length; for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]); return res; //return calculated points } 
+5
source

Look at perlin noise generation, this combined with a good smoothing algorithm can lead to a pretty good landscape and pretty fast. There is a reference version of the code that kicks somewhere on the net, which should provide you with a pretty hefty hat

+3
source

First you need a point that is random y (between 55.65); got x = 0 So this is the start point for green, let's save it as x1, y1 (x1 is always 0).

Then you need a random integer from 30 to 40. This is x2. And random y, which is in the range y1 + 8 to y1 + 20.

Then x3 and y3 by the same principle (we call it a formula of type 1)

Now you need to get a random value of -1 or 1 first, these will be y4 directions. So y4 can go above y3 or lower ... it will be a formula of type 2.

You need to save max and min y for the new y if it crosses this and then go the other way β†’ it will be a correction type 3 formula.

Xn continues to increase to its> = board width.

Join the lines in eclipses ... and it looks like searching on the Internet is the way to go!

+1
source

I am sure there are many encoded libraries that you could use to make this easy. But if you are trying to code it yourself, here is my idea.

You need to determine the landscape from everything else. Thus, each part of your environment is a cluster, for example. You need to determine how these clusters are separated, for example, by nodes (points).

You can create a polygon from a sequence of points, and this polygon can become what you want, in this case, the terrain.

Look at the image that you transmitted, there are peaks, these are nodes (points). Remember to also identify nodes at the borders of your environment.

+1
source

There is, of course, a novel, written algorithms, either fractal, as pointed out by @DesertIvy, or others, maybe there are libraries, but if you want toi to generate what is on the image, it can be quite simple, because it is simple (slightly curved) lines between points. If you do this in stages, without trying to be right right away, this is easy:

  • Divide the area x of your game screen into sections (with minimum and maximum width), using random ones (in the last section you can be a little distracted, but it does not matter, I think). Remember x-es, where sections meet (including at the border of the game screen).
  • Prepare some data structure to include ys as well as the previously saved xs. Start with leftmost.y = 0 , slope = Math.random()-0.5; .
  • Create each next undefined y starting with 1: right.y = left.y + slope * (right.x-left.x); , as well as the update slope after each y: slope += Math.random()-0.5; . Do not worry at the moment if all this fits into the game screen.
  • If you need arcs, you can generate a "curviness" parameter for each section randomly, representing how much the midline intersects compared to the straight lines.
  • Install ys in the game screen: first find the maximum and minimum generated y ( mingeny , maxgeny ) (you can track this when generating in step 4). Choose where max and min y in the game screen ( minscry , maxscry ) (say, in the top fourth and bottom of the fourth). Then convert the generated ys so that they span between minscry and maxscry : for each point do apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny) .
  • Now use the lines between the [x, y] points as the terrain if you want to use "curviness" than add a curvemodifier to y for any specific x in the section between leftx and rightx. The arc should not be around: I would suggest a parabola or cosine, which are easy to produce: var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left); var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left); and then either var curvemodifier = curviness * (1-excess*excess); , or var curvemodifier = curviness * Math.cos(Math.PI/2*excess) .
+1
source

Wow ... At some point, I was completely dependent on tank wars .

Since you are participating in a learning adventure ...

You can also learn about context.globalCompositeOperation.

This canvas operation will allow you to capture an image of the actual grass and combine it into your game.

You can randomize the appearance of the grass by changing x / y of your drawImage ();

Yes, the actual grass is likely to be too distracting to include in your finished game, but learning compositing would be valuable knowledge.

... and +1 for the question: "Good for you, challenging yourself."

+1
source

Source: https://habr.com/ru/post/947140/


All Articles