2D Colored Dots Game

Add Dot
Weight Scale:

1.0

.game-container {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #f0f0f0;
border-radius: 10px;
}
.controls {
margin-bottom: 10px;
}
#gameCanvas {
border: 1px solid #ccc;
background-color: white;
}
#addDotBtn {
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#addDotBtn:hover {
background-color: #45a049;
}

document.addEventListener(‘DOMContentLoaded’, function() {
const canvas = document.getElementById(‘gameCanvas’);
const ctx = canvas.getContext(‘2d’);
const addDotBtn = document.getElementById(‘addDotBtn’);
const weightScaleInput = document.getElementById(‘weightScale’);
const weightScaleValue = document.getElementById(‘weightScaleValue’);

const canvasWidth = 600;
const canvasHeight = 400;
const dotRadius = 10;
const maxDistance = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);

let dots = [];
let selectedDot = null;
let weightScale = 1;

function addDot() {
const newColor = {
r: Math.floor(Math.random() * 256),
g: Math.floor(Math.random() * 256),
b: Math.floor(Math.random() * 256)
};
const newDot = {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight,
originalColor: newColor,
displayColor: newColor
};
dots.push(newDot);
drawGame();
}

function updateDotColors() {
return dots.map(dot => {
let totalWeight = 0;
const weightedColors = { r: 0, g: 0, b: 0 };

dots.forEach(otherDot => {
const distance = Math.sqrt(
Math.pow(dot.x – otherDot.x, 2) + Math.pow(dot.y – otherDot.y, 2)
);
const weight = Math.max(0, 1 – (distance / maxDistance) * weightScale);
totalWeight += weight;

weightedColors.r += otherDot.originalColor.r * weight;
weightedColors.g += otherDot.originalColor.g * weight;
weightedColors.b += otherDot.originalColor.b * weight;
});

const displayColor = totalWeight > 0 ? {
r: Math.round(weightedColors.r / totalWeight),
g: Math.round(weightedColors.g / totalWeight),
b: Math.round(weightedColors.b / totalWeight)
} : dot.originalColor;

return { …dot, displayColor };
});
}

function drawGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

const updatedDots = updateDotColors();

updatedDots.forEach((dot) => {
ctx.beginPath();
ctx.arc(dot.x, dot.y, dotRadius, 0, 2 * Math.PI);

ctx.fillStyle = `rgb(${dot.displayColor.r},${dot.displayColor.g},${dot.displayColor.b})`;
ctx.fill();

ctx.strokeStyle = `rgb(${dot.originalColor.r},${dot.originalColor.g},${dot.originalColor.b})`;
ctx.lineWidth = 2;
ctx.stroke();
});
}

function handleCanvasMouseDown(e) {
const rect = canvas.getBoundingClientRect();
const x = e.clientX – rect.left;
const y = e.clientY – rect.top;

selectedDot = dots.findIndex(dot =>
Math.sqrt(Math.pow(dot.x – x, 2) + Math.pow(dot.y – y, 2)) < dotRadius
);
}

function handleCanvasMouseMove(e) {
if (selectedDot !== -1) {
const rect = canvas.getBoundingClientRect();
const x = e.clientX – rect.left;
const y = e.clientY – rect.top;

dots[selectedDot].x = Math.max(dotRadius, Math.min(canvasWidth – dotRadius, x));
dots[selectedDot].y = Math.max(dotRadius, Math.min(canvasHeight – dotRadius, y));
drawGame();
}
}

function handleCanvasMouseUp() {
selectedDot = -1;
}

function handleWeightScaleChange() {
weightScale = parseFloat(weightScaleInput.value);
weightScaleValue.textContent = weightScale.toFixed(1);
drawGame();
}

addDotBtn.addEventListener('click', addDot);
weightScaleInput.addEventListener('input', handleWeightScaleChange);
canvas.addEventListener('mousedown', handleCanvasMouseDown);
canvas.addEventListener('mousemove', handleCanvasMouseMove);
canvas.addEventListener('mouseup', handleCanvasMouseUp);
canvas.addEventListener('mouseleave', handleCanvasMouseUp);

// Initialize the game
drawGame();
});