“坦克大战”游戏中随机土地的算法

时间:2013-06-12 17:13:38

标签: javascript canvas html5-canvas

你有没有玩过“坦克大战”游戏?

enter image description here

我正在用JavaScript + Canvas编程这个游戏(用于个人挑战),我需要的是每次开始游戏时生成随机绿地的算法,但我不太擅长数学,所以我不能自己做。

我不希望有人给我代码,我只想要算法的想法。

谢谢!

6 个答案:

答案 0 :(得分:5)

enter image description here
(9段)

<强> Fiddle demo

enter image description here
(7段)

主要生成函数如下所示:

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();

curve()函数是一个单独的函数,它生成一个基数样条曲线。在这里,您可以修改它以存储张力值以产生更多峰值。您还可以使用生成的点作为坦克移动的位置和角度的基础。

基数样条函数:

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
}

答案 1 :(得分:3)

研究perlin噪声的产生,结合良好的平滑算法可以产生一些非常好的地形,并且相当快。有一个参考版本的代码在网络上踢,这应该为你提供一个相当沉重的headstart

答案 2 :(得分:1)

首先你需要一个随机y点(在555之间);得到x = 0 所以这是绿色的原点,让它保持为x1,y1(x1始终为0)。

然后你需要一个介于30到40之间的随机整数。这是x2。并且随机y在y1 + 8到y1 + 20的范围内。

然后x3和y3的原理相同(我们称之为公式类型1)

现在你需要首先得到一个随机的-1或1,这将是y4的方向。所以y4可以高于y3或更低......这将是公式类型2。

你需要为一个新的y保持最大和最小y,如果它越过那个,那么走另一条路 - &gt;这将是一个修正类型公式3。

Xn一直在增加,直到它的&gt; =板的宽度。

加入日食中的线条......看起来像网络搜索是要走的路!

答案 3 :(得分:1)

我确信您可以使用许多编码库来简化这一过程。但如果你想自己编写代码,这就是我的想法。

您需要从其他所有内容定义地形。因此,您的环境的每个部分都是一个集群。您需要定义如何按节点(点)分隔这些集群。

你可以从一系列点创建一个多边形,这个多边形可以成为你想要的任何东西,在这种情况下是地形。

在您传递的图像上看到,有峰值,那些是节点(点)。请记住在环境的边界上定义节点。

答案 4 :(得分:1)

肯定有一种新颖的书面算法,无论是@DesertIvy指出的分形还是其他,也许还有库,但是如果你想生成图像中的内容,它可以非常简单,因为它是点之间只有(稍微弯曲)的线条。如果你分阶段进行,不要一次尝试正确,这很容易:

  1. 使用随机分割游戏画面的x区域(具有一些最小和最大宽度)(在最后一部分你可能略微偏离,但我认为这并不重要)。请记住部分相遇的x-es(包括游戏屏幕边框处的那些)
  2. 在以前记住的x-s上准备一些数据结构以包含y-s。从leftmost.y = 0slope = Math.random()-0.5;开始。
  3. 从1:right.y = left.y + slope * (right.x-left.x);开始生成每个下一个未定义的y,并在每个y后更新斜率:slope += Math.random()-0.5;。如果一切都适合游戏画面,请不要打扰。
  4. 如果你想要弧线,你可以随机为每个部分生成“弯曲度”参数,这些参数表示线条中间与直线相比的多少。
  5. 使ys适应游戏画面:首先找到最大和最小生成的y(mingenymaxgeny)(您可以在第4点生成时跟踪它)。选择游戏界面中最大和最小y的位置(minscrymaxscry)(比如在前四分之一和最下四分之一)。然后转换生成的ys,使其跨越minscrymaxscry:对于每个点,执行apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny)
  6. 现在使用[x,y]点之间的线作为地形,如果你想使用“曲线”,而不是将curvemodifier添加到y中,用于leftx和rightx之间的任何特定x。弧不必是一个圆圈:我建议使用易于生成的抛物线或余弦:var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left);然后var curvemodifier = curviness * (1-excess*excess);var curvemodifier = curviness * Math.cos(Math.PI/2*excess)

答案 5 :(得分:1)

哇......有一次我完全沉迷于坦克大战

因为你正在学习冒险......

您可能还会了解context.globalCompositeOperation。

此画布操作可让您抓取实际草的图像并将其合成到游戏中。

您可以通过更改drawImage();

的x / y来随机化草的外观

是的,实际的草可能太过分散注意力,无法包含在你完成的游戏中,但学习合成将是宝贵的知识。

...和问题+1:对你挑战自己有好处!