你玩过“坦克大战”游戏吗?
我正在用 JavaScript + Canvas 编写这个游戏(针对个人挑战),我需要的是一种算法,用于在每次开始游戏时生成随机绿地,但我的数学不太好,所以我可以不要自己做。
我不想有人给我代码,我只想要算法的想法。
谢谢!
你玩过“坦克大战”游戏吗?
我正在用 JavaScript + Canvas 编写这个游戏(针对个人挑战),我需要的是一种算法,用于在每次开始游戏时生成随机绿地,但我的数学不太好,所以我可以不要自己做。
我不想有人给我代码,我只想要算法的想法。
谢谢!
(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
}
看看 perlin 噪声生成,这与一个好的平滑算法相结合可以产生一些非常好的地形,并且相当快。有一个参考版本的代码在网上流传,它应该为您提供一个相当大的开端
首先,您需要一个随机 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 中的行...看起来网络搜索是要走的路!
我相信有很多编码库可以用来简化这件事。但是,如果您想自己编写代码,这是我的想法。
您需要从其他所有内容中定义地形。例如,您环境的每个部分都是一个集群。您需要定义如何分隔这些集群,例如通过节点(点)。
你可以从一系列点创建一个多边形,这个多边形可以变成你想要的任何东西,在这种情况下是地形。
看到在您传递的图像上,有峰值,那些是节点(点)。请记住还要在环境边界上定义节点。
肯定有一种新颖的书面算法,如@DesertIvy 指出的分形或其他算法,也许还有库,但如果你想生成图像中的内容,它可以非常简单,因为它只是(稍微曲线)点之间的线。如果您分阶段进行,而不是立即尝试正确,则很容易:
leftmost.y = 0
从,开始slope = Math.random()-0.5;
。right.y = left.y + slope * (right.x-left.x);
,并在每个 y: 之后更新斜率slope += Math.random()-0.5;
。暂时不要打扰,如果这一切都适合游戏屏幕。mingeny
, maxgeny
)(您可以在第 4 点生成时跟踪它)。选择游戏屏幕中最大和最小 y 的位置 ( minscry
, maxscry
)(例如在顶部第四和底部第四)。然后变换生成的 ys 使其跨越minscry
和maxscry
:对于每个点,做apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny)
。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)
。哇...有一段时间我完全沉迷于坦克战。
既然你是在学习冒险...
您可能还会了解 context.globalCompositeOperation。
此画布操作将让您抓取实际草的图像并将其合成到您的游戏中。
您可以通过更改 drawImage() 的 x/y 来随机化草的外观;
是的,实际的草可能太分散注意力而无法包含在您完成的游戏中,但学习合成将是宝贵的知识。
...和 +1 的问题:有利于你挑战自己!