6

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

在此处输入图像描述

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

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

谢谢!

4

6 回答 6

5

在此处输入图像描述
(9 段)

小提琴演示

在此处输入图像描述
(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
}
于 2013-06-12T22:08:37.383 回答
3

看看 perlin 噪声生成,这与一个好的平滑算法相结合可以产生一些非常好的地形,并且相当快。有一个参考版本的代码在网上流传,它应该为您提供一个相当大的开端

于 2013-06-12T17:22:59.393 回答
1

首先,您需要一个随机 y 点(在 55,65 之间);得到 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,如果它越过它,那么就走另一条路 -> 这将是一个校正类型公式 3。

Xn 不断增加,直到其 >= 板的宽度。

加入 eclipse 中的行...看起来网络搜索是要走的路!

于 2013-06-12T17:23:07.580 回答
1

我相信有很多编码库可以用来简化这件事。但是,如果您想自己编写代码,这是我的想法。

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

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

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

于 2013-06-12T17:23:48.933 回答
1

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

  1. 使用随机将游戏屏幕的 x 区域分成多个部分(具有一些最小和最大宽度)(您可能在最后一个部分略有偏离,但我认为这并不重要)。记住部分相交的 x-es(包括游戏屏幕边框处的那些)
  2. 在先前记住的 xs 上准备一些数据结构以包含 ys。leftmost.y = 0从,开始slope = Math.random()-0.5;
  3. 生成从 1: 开始的每个下一个未定义的 y right.y = left.y + slope * (right.x-left.x);,并在每个 y: 之后更新斜率slope += Math.random()-0.5;。暂时不要打扰,如果这一切都适合游戏屏幕。
  4. 如果你想要弧线,你可以为每个部分随机生成“曲线”参数,它表示与直线相比,线的中间有多少凹凸。
  5. 将 y 拟合到游戏屏幕中:首先找到生成的最大和最小 y ( mingeny, maxgeny)(您可以在第 4 点生成时跟踪它)。选择游戏屏幕中最大和最小 y 的位置 ( minscry, maxscry)(例如在顶部第四和底部第四)。然后变换生成的 ys 使其跨越minscrymaxscry:对于每个点,做apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny)
  6. 现在使用 [x,y] 点之间的线作为地形,如果你想使用“曲线”,而不是curvemodifier为 leftx 和 rightx 之间的部分中的任何特定 x 添加到 y。弧不必是圆:我建议使用易于产生的抛物线或余弦: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)
于 2013-06-12T18:27:46.860 回答
1

哇...有一段时间我完全沉迷于坦克战

既然你是在学习冒险...

您可能还会了解 context.globalCompositeOperation。

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

您可以通过更改 drawImage() 的 x/y 来随机化草的外观;

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

...和 ​​+1 的问题:有利于你挑战自己!

于 2013-06-12T20:08:37.080 回答