我有一个看起来像这样的数组
tiles = [{
x: 0,
y: 0,
land: false //true = land false = water
}];
目标是在画布上自动生成一个行星,但是我想对陆地和海洋进行聚类(随机数量)。我已经取得了使它看起来不错的效果,但是我想要更大的陆地和海洋质量,而不是要有任何带有土地/水的“洞”单砖。
我尝试了一些if语句,其中的百分比是水或土地,但我无法将其聚类到比我现在所拥有的更多。我做了一个较小的,结果很好,我希望代码段中的一个可以对图像和链接中的内容进行聚类。 Codepen for the img example
tldr:我希望数组由布尔区域聚类
我该如何进行呢?
var tileNum = 0;
var tiles;
var colorsLand;
var colorsWater;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var tileSize = 1;
canvas.width = canvas.height = 730;
// 'size' is grid size, not the actual pixel size painted on screen
var size = Math.ceil(canvas.width / tileSize);
function generatePlanet() {
tileNum = 0;
tiles = [{
x: 0,
y: 0,
land: false
}];
//Retrive colors
colorsLand = interpolateColors(getColor(true), getColor(true), 6000);
colorsWater = interpolateColors(getColor(false), getColor(false), 6000);
//Creates a array of my tiles and sets either water or land to them and calculates the % of being water/land
for (var i = 0; i < (size * size); i++) {
var currentTile = tiles[tiles.length - 1];
if (currentTile.x <= (size - 1)) {
var isLand = false;
if (tiles.length >= (size * 2) && (
tiles[tiles.length - 1].land ||
tiles[tiles.length - 2].land ||
tiles[tiles.length - (size)].land ||
tiles[tiles.length - (size * 2)].land ||
tiles[tiles.length - (size - 1)].land ||
tiles[tiles.length - (size - 2)].land
)) {
isLand = (Math.floor(Math.random() * 100) + 1) > 66;
} else if (tiles.length >= (size * 2) && (!tiles[tiles.length - 1].land ||
!tiles[tiles.length - 2].land ||
!tiles[tiles.length - (size)].land ||
!tiles[tiles.length - (size * 2)].land ||
!tiles[tiles.length - (size - 1)].land ||
!tiles[tiles.length - (size - 2)].land
)) {
isLand = (Math.floor(Math.random() * 1000) + 1) > 999;
}
tiles.push({
x: currentTile.x + 1,
y: currentTile.y,
land: isLand
});
} else {
tiles.push({
x: 1,
y: currentTile.y + 1,
land: isLand
});
}
}
drawPlanet()
}
//retrive a random color if it's a land tile i want it dark water i want light
function getColor(land) {
while (true) {
var r = Math.floor(Math.random() * 256) + 1
var g = Math.floor(Math.random() * 256) + 1
var b = Math.floor(Math.random() * 256) + 1
var hsp = Math.sqrt(
0.299 * (r * r) +
0.587 * (g * g) +
0.114 * (b * b)
);
//light color
if (hsp > 127.5 && land == false) {
return [r, g, b];
}
//dark color
else if (hsp < 127.5 && land == true) {
return [r, g, b];
}
}
}
//these 2 functions interpolateColor(s) takes 2 colors and gives me 'steps' colors between
function interpolateColors(color1, color2, steps) {
var stepFactor = 1 / (steps - 1),
interpolatedColorArray = [];
for (var i = 0; i < steps; i++) {
interpolatedColorArray.push(toUint32AARRGGBB(interpolateColor(color1, color2, stepFactor * i)));
}
return interpolatedColorArray;
}
function toUint32AARRGGBB(arr) {
return Number('0xFF' + arr.map(toHexString2).join(''))
}
function toHexString2(val) {
return val.toString(16)
.padStart(2, '0'); // padStart may need a polyfill
}
function interpolateColor(color1, color2, factor) {
if (arguments.length < 3) {
factor = 0.5;
}
var result = color1.slice();
for (var i = 0; i < 3; i++) {
result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
}
return result;
};
//retrives a random color for land
function rndLandColor() {
return colorsLand[Math.floor(Math.random() * 5999) + 1];
}
//retrives a random color for water
function rndWaterColor() {
return colorsWater[Math.floor(Math.random() * 5999) + 1];
}
// now drawing synchronously:
function drawPlanet() {
var gridsize = size;
// var rad = gridsize / 2;
// generate an ImageData, the size of our pixel grid
var imgData = new ImageData(gridsize, gridsize);
// work directly on Uint32 values (0xAARRGGBB on LittleEndian)
var data = new Uint32Array(imgData.data.buffer);
var score, y, x;
for (y = 0; y < gridsize; y++) {
for (x = 0; x < gridsize; x++) {
score = 0;
//fill in holes in the land that is bigger then 1
if (tiles[tileNum - (gridsize + 1)] !== undefined && tiles[tileNum + (size + 1)] !== undefined) {
if (tiles[tileNum].land == false) {
score++;
}
if (tiles[tileNum - 1].land == true) {
score++;
}
if (tiles[tileNum + 1].land == true) {
score++;
}
if (tiles[tileNum + (gridsize + 1)].land == true) {
score++;
}
if (tiles[tileNum - (gridsize + 1)].land == true) {
score++;
}
}
if (score >= 2) {
color = rndLandColor();
}
//cover single land tiles with water (if water tile is up,down,left and right of this tile)
else if (
tiles[tileNum - (gridsize + 1)] !== undefined &&
tiles[tileNum + (gridsize + 1)] !== undefined &&
tiles[tileNum - 1].land == false &&
tiles[tileNum + 1].land == false &&
tiles[tileNum - (gridsize + 1)].land == false &&
tiles[tileNum + (gridsize + 1)].land == false) {
color = rndWaterColor();
}
//cover single water tiles with land (if land tile is up,down,left and right of this tile)
else if (
tiles[tileNum - (gridsize + 1)] !== undefined &&
tiles[tileNum + (gridsize + 1)] !== undefined &&
tiles[tileNum - 1].land == true &&
tiles[tileNum + 1].land == true &&
tiles[tileNum - (gridsize + 1)].land == true &&
tiles[tileNum + (gridsize + 1)].land == true) {
color = rndLandColor();
}
//cover tile with land
else if (tiles[tileNum] !== undefined && tiles[tileNum].land == true) {
color = rndLandColor();
}
//cover tile with water
else if (tiles[tileNum] !== undefined && tiles[tileNum].land == false) {
color = rndWaterColor();
}
tileNum++;
data[(y * gridsize) + x] = color;
}
}
// all done populating the ImageData
// put it on the context at scale(1,1)
ctx.putImageData(imgData, 0, 0);
// remove antialiasing
ctx.imageSmoothingEnabled = false;
// up-scale
ctx.scale(tileSize, tileSize);
// draw the canvas over itself
ctx.drawImage(ctx.canvas, 0, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
generatePlanet();
#canvas {
border: 10px solid #000000;
border-radius: 50%;
/* background-color: aquamarine; */
}
.container {
width: 720px;
height: 720px;
position: relative;
}
.gradient {
position: absolute;
height: 745px;
width: 745px;
top: 0;
left: 0;
border-radius: 50%;
opacity: 0.8;
}
<button onclick="generatePlanet()">GENERATE</button>
<div class="container">
<img class="gradient" src="https://www.mediafire.com/convkey/1f5a/cgu50lw1ehcp4fq6g.jpg" />
<canvas id="canvas" width="710" height="710"></canvas>
</div>