xxxxxxxxxx
154
let w = 2;
let islands = [];
let sandPile = [];
let img;
let startX = 50,
startY = 10;
function preload() {
img = loadImage("assets/train.png");
}
function setup() {
createCanvas(500, 300);
let v = [];
for (let x = 0; x < img.width; x += w)
for (let y = 0; y < img.height; y += w) {
let h = img.get(x, y);
if (h[0] != 0)
v.push(
new Sand({
x: startX + x,
y: startY + y,
w,
h,
})
);
}
islands = groupConnectedByColorAndCoordinates(v, 0.0006, w);
}
function addIsland(startX, startY, sizeX, sizeY, h) {
let island = [];
for (let i = -sizeX; i < sizeX; i++) {
for (let j = -sizeY; j < sizeY; j++) {
island.push(new Sand({ x: startX + i * w, y: startY + j * w, w, h }));
}
}
islands.push(island);
}
function draw() {
background(0);
// image(img, startX, startY);
for (const island of islands) {
for (const sand of island) {
if (sand.updateStatus(sandPile)) {
sandPile.push(sand);
}
sand.step();
sand.draw();
}
}
if (islands.length > 0)
islands = islands
.map((island) => island.filter((sand) => sand.status !== "stopped"))
.filter((islands) => islands.length > 0);
for (const sand of sandPile) sand.draw();
}
function mousePressed() {
const islandIndex = getIslandByCoords(mouseX, mouseY);
if (islandIndex === -1) return;
for (let i = 0; i < islands[islandIndex].length; i++) {
islands[islandIndex][i].pressed();
}
}
function getIslandByCoords(x, y) {
return islands.findIndex(
(island) => island.findIndex((sand) => sand.isInside(x, y)) !== -1
);
}
// ChatGPT Generated function below
function groupConnectedByColorAndCoordinates(objects, hueThreshold, distanceThreshold) {
// Convert RGB to HSL to extract hue
function rgbToHsl(rgb) {
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
break;
case g:
h = ((b - r) / d + 2) / 6;
break;
case b:
h = ((r - g) / d + 4) / 6;
break;
}
}
return [h, s, l];
}
// Helper function to check if two hue values are close
function areHuesClose(hue1, hue2) {
return Math.abs(hue1 - hue2) <= hueThreshold;
}
// Helper function to check if two objects are close enough in coordinates
function areObjectsClose(obj1, obj2) {
const distance = Math.sqrt(Math.pow(obj1.x - obj2.x, 2) + Math.pow(obj1.y - obj2.y, 2));
return distance <= distanceThreshold;
}
// Initialize visited flag for each object
const visited = new Array(objects.length).fill(false);
// Depth-first search to find connected objects
function dfs(index, island) {
visited[index] = true;
island.push(objects[index]);
// Check neighbors for connectivity
for (let i = 0; i < objects.length; i++) {
if (!visited[i] && areHuesClose(rgbToHsl(objects[index].h)[0], rgbToHsl(objects[i].h)[0]) &&
areObjectsClose(objects[index], objects[i])) {
dfs(i, island);
}
}
}
const islands = [];
// Find islands
for (let i = 0; i < objects.length; i++) {
if (!visited[i]) {
const island = [];
dfs(i, island);
islands.push(island);
}
}
return islands;
}