Created
November 14, 2024 08:41
-
-
Save p3nGu1nZz/3acdf783cf14ec21d678db6fc04cc8ee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Multiple Wobbly Plasma Bubbles</title> | |
</head> | |
<body> | |
<canvas id="cv"></canvas> | |
<script> | |
const cv = document.getElementById('cv'), | |
ctx = cv.getContext('2d'), | |
cs = ['255,0,0', '0,255,0', '0,0,255'], | |
sm = 50, | |
mv = 5, | |
sp = { | |
auto: true, | |
rate: 180, | |
check: true, | |
maxBubs: 10000, | |
maxTensors: 1000000 | |
}; | |
let dt = true, | |
ab = false, | |
rb = false, | |
fc = 0, | |
lt = (new Date()).getTime(), | |
ct = 0, | |
fps = 0, | |
tc = 0, | |
sd = true, | |
bs = cs.map(c => [cb(c), cb(c)]).flat(), | |
dbiVisible = true; // Control visibility of the dbi panel | |
cv.width = window.innerWidth; | |
cv.height = window.innerHeight; | |
function cb(c, x, y) { | |
const r = 20; | |
x = x || Math.random() * (cv.width - 2 * sm - 2 * r) + sm + r; | |
y = y || Math.random() * (cv.height - 2 * sm - 2 * r) + sm + r; | |
const vx = (Math.random() - 0.5) * mv; | |
const vy = (Math.random() - 0.5) * mv; | |
return { | |
x, | |
y, | |
r, | |
vx, | |
vy, | |
c | |
}; | |
} | |
// UI Layer | |
const uiLayer = { | |
modalBackground: { | |
visible: false, | |
draw: function(ctx) { | |
if (this.visible) { | |
ctx.save(); | |
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; | |
ctx.fillRect(0, 0, cv.width, cv.height); | |
ctx.restore(); | |
} | |
} | |
}, | |
settingsPanel: { | |
visible: false, | |
width: window.innerWidth / 3, | |
height: window.innerHeight / 2, | |
x: window.innerWidth / 2, | |
y: window.innerHeight / 2, | |
buttons: [], | |
draw: function(ctx) { | |
if (this.visible) { | |
// Draw modal background | |
uiLayer.modalBackground.draw(ctx); | |
// Draw settings panel | |
ctx.save(); | |
ctx.translate(this.x - this.width / 2, this.y - this.height / 2); | |
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; | |
ctx.fillRect(0, 0, this.width, this.height); | |
// Calculate button dimensions | |
const buttonHeight = (this.height - 8) / 7; // 7 buttons with 1px border space | |
const buttonWidth = this.width - 2; // Full width minus border space | |
// Create or update buttons | |
this.buttons = Array.from({ | |
length: 7 | |
}, (_, index) => ({ | |
text: 'Button ' + (index + 1), | |
x: 1, // 1px border space | |
y: 1 + index * (buttonHeight + 1), // 1px border space | |
width: buttonWidth, | |
height: buttonHeight, | |
hover: false | |
})); | |
// Draw buttons | |
this.buttons.forEach(button => { | |
ctx.fillStyle = button.hover ? '#333' : 'transparent'; | |
ctx.fillRect(button.x, button.y, button.width, button.height); | |
ctx.fillStyle = button.hover ? '#fff' : '#000'; | |
ctx.textAlign = 'center'; | |
ctx.textBaseline = 'middle'; | |
ctx.fillText(button.text, button.x + button.width / 2, button.y + button.height / 2); | |
}); | |
ctx.restore(); | |
} | |
} | |
}, | |
// ... Other UI elements ... | |
}; | |
// Event listeners for mouse movement and clicks | |
cv.addEventListener('mousemove', function(e) { | |
const rect = cv.getBoundingClientRect(); | |
const mouseX = e.clientX - rect.left; | |
const mouseY = e.clientY - rect.top; | |
uiLayer.settingsPanel.buttons.forEach((button, index) => { | |
button.hover = mouseX > button.x + uiLayer.settingsPanel.x - uiLayer.settingsPanel.width / 2 && | |
mouseX < button.x + button.width + uiLayer.settingsPanel.x - uiLayer.settingsPanel.width / 2 && | |
mouseY > button.y + (index * 60) + uiLayer.settingsPanel.y - uiLayer.settingsPanel.height / 2 && | |
mouseY < button.y + (index * 60) + button.height + uiLayer.settingsPanel.y - uiLayer.settingsPanel.height / 2; | |
}); | |
}); | |
cv.addEventListener('click', function(e) { | |
uiLayer.settingsPanel.buttons.forEach(button => { | |
if (button.hover) { | |
// Close the settings panel | |
uiLayer.settingsPanel.visible = false; | |
uiLayer.modalBackground.visible = false; | |
dbiVisible = true; | |
} | |
}); | |
}); | |
document.addEventListener('DOMContentLoaded', (event) => { | |
const cv = document.getElementById('cv'); | |
const ctx = cv.getContext('2d'); | |
// Set body style to a lighter grey | |
document.body.style.margin = '0'; | |
document.body.style.overflow = 'hidden'; | |
document.body.style.display = 'flex'; | |
document.body.style.justifyContent = 'center'; | |
document.body.style.alignItems = 'center'; | |
document.body.style.height = '100vh'; | |
document.body.style.backgroundColor = '#131313'; // Lighter grey color | |
// Set canvas style | |
cv.style.display = 'block'; | |
cv.style.position = 'absolute'; | |
cv.style.top = '0'; | |
cv.style.left = '0'; | |
// Your existing canvas setup and game logic here | |
}); | |
// Toggle settings panel visibility and dbi panel | |
document.addEventListener('keydown', function(e) { | |
if (e.key === 'Escape') { | |
if (uiLayer && uiLayer.settingsPanel) { | |
uiLayer.settingsPanel.visible = !uiLayer.settingsPanel.visible; | |
uiLayer.modalBackground.visible = uiLayer.settingsPanel.visible; | |
dbiVisible = !uiLayer.settingsPanel.visible; // Toggle dbi panel visibility | |
} else { | |
console.error('uiLayer or settingsPanel is not defined'); | |
} | |
} | |
}); | |
// Modify the mouse event listener | |
cv.addEventListener('mousedown', function(e) { | |
// Check if the escape window is not visible before allowing bubble creation | |
if (!uiLayer.settingsPanel.visible && e.button === 0) { | |
ab = true; // 'ab' is the flag for adding bubbles | |
} | |
}); | |
cv.addEventListener('mouseup', function(e) { | |
// Check if the escape window is not visible before allowing bubble creation | |
if (!uiLayer.settingsPanel.visible && e.button === 0) { | |
ab = false; // Reset the add bubble flag | |
} | |
}); | |
cv.addEventListener('contextmenu', e => { | |
e.preventDefault(); | |
rb = true; | |
setTimeout(() => rb = false, 100); | |
}); | |
// Modify the keyboard event listener | |
window.addEventListener('keydown', function(e) { | |
// Check if the escape window is not visible before allowing bubble creation or removal | |
if (!uiLayer.settingsPanel.visible) { | |
if (e.key === 'Delete' || e.key === 'Backspace') { | |
bs = cs.map(c => [cb(c), cb(c)]).flat(); // Reset bubbles | |
} else if (e.key === 't' || e.key === 'T') { | |
dt = !dt; // Toggle draw tensors | |
} else if (e.key === '+' || e.key === '=') { | |
ab = true; // Add bubbles | |
} else if (e.key === '-' || e.key === '_') { | |
rb = true; // Remove bubbles | |
} else if (e.key === 'd' || e.key === 'D') { | |
sd = !sd; // Toggle display info | |
} else if (e.key === 's' || e.key === 'S') { | |
sp.auto = !sp.auto; // Toggle auto-spawn | |
} | |
} | |
}); | |
window.addEventListener('keyup', function(e) { | |
// Check if the escape window is not visible before allowing bubble creation or removal | |
if (!uiLayer.settingsPanel.visible) { | |
if (['+', '=', '-', '_'].includes(e.key)) { | |
ab = rb = false; // Reset flags | |
} | |
} | |
}); | |
function dbi() { | |
if (!sd) return; | |
const pd = 8, | |
pr = 9, | |
pb = 4, | |
pt = 7, | |
bw = 160 + pr, | |
bh = 125; // No change in size | |
ctx.fillStyle = 'rgba(0, 0, 0, 0.11)'; | |
ctx.fillRect(pd, pd, bw, bh); | |
ctx.strokeStyle = '#ccc'; | |
ctx.lineWidth = 1; | |
ctx.strokeRect(pd, pd, bw, bh); | |
ctx.font = 'bold 12px monospace'; | |
ctx.fillStyle = 'white'; | |
ctx.shadowColor = 'black'; | |
ctx.shadowOffsetX = 1; | |
ctx.shadowOffsetY = 1; | |
ctx.shadowBlur = 0; | |
const tp = 18, | |
lh = 14; | |
ctx.fillText('FPS: ' + fps, 2 * pd, pd + tp); | |
ctx.fillText('Bubs: ' + bs.length, 2 * pd, pd + tp + lh); | |
ctx.fillText('Colors: ' + cs.length, 2 * pd, pd + tp + 2 * lh); | |
ctx.fillText('Tensors: ' + tc, 2 * pd, pd + tp + 3 * lh); | |
ctx.fillText('Frame Time: ' + (1000 / fps).toFixed(2) + 'ms', 2 * pd, pd + tp + 4 * lh); | |
ctx.fillText('Auto-Spawn: ' + (sp.auto ? 'On' : 'Off'), 2 * pd, pd + tp + 5 * lh); | |
ctx.fillText('Spawn Interval: ' + (sp.rate / 60) + 's', 2 * pd, pd + tp + 6 * lh); | |
// Display current scale | |
const currentScale = calculateScale(bs.length).toFixed(2); | |
ctx.fillText('Current Scale: ' + currentScale, 2 * pd, pd + tp + 7 * lh); | |
ctx.shadowColor = 'transparent'; | |
} | |
function calculateScale(totalBubs) { | |
const minScale = 1 / 7; // Minimum scale factor | |
const scaleFactor = 1 / (1 + 0.05 * totalBubs); // Diminishing returns scale factor | |
return Math.max(scaleFactor, minScale); | |
} | |
function update() { | |
ct = (new Date()).getTime(); | |
fps = Math.round(1000 / (ct - lt)); | |
lt = ct; | |
ctx.clearRect(0, 0, cv.width, cv.height); | |
tc = 0; | |
// Calculate the current scale based on the number of bubbles | |
const scale = calculateScale(bs.length); | |
// Draw and update bubbles | |
bs.forEach(b => { | |
ctx.fillStyle = `rgba(${b.c}, 0.7)`; | |
ctx.beginPath(); | |
ctx.arc(b.x, b.y, b.r * scale, 0, Math.PI * 2); | |
ctx.fill(); | |
b.x += b.vx; | |
b.y += b.vy; | |
if (b.x > cv.width - b.r * scale - sm || b.x < b.r * scale + sm) b.vx *= -1; | |
if (b.y > cv.height - b.r * scale - sm || b.y < b.r * scale + sm) b.vy *= -1; | |
}); | |
// Draw tensors if the limit has not been reached | |
if (dt && tc < sp.maxTensors) { | |
for (let i = 0; i < bs.length; i++) { | |
for (let j = i + 1; j < bs.length; j++) { | |
if (bs[i].c === bs[j].c) { | |
tc++; | |
ctx.strokeStyle = `rgba(${bs[i].c}, 0.5)`; | |
ctx.beginPath(); | |
ctx.moveTo(bs[i].x, bs[i].y); | |
ctx.lineTo(bs[j].x, bs[j].y); | |
ctx.stroke(); | |
} | |
} | |
} | |
} | |
// Spawn new bubbles if the tensor limit has not been reached | |
if (sp.auto && fc % sp.rate === 0 && (!sp.check || fps >= 30) && bs.length < sp.maxBubs && tc < sp.maxTensors) { | |
bs.push(cb(cs[Math.floor(Math.random() * cs.length)]), cb(cs[Math.floor(Math.random() * cs.length)])); | |
} | |
// Add or remove bubbles based on user input | |
if (ab && bs.length < sp.maxBubs && tc < sp.maxTensors) { | |
bs.push(cb(cs[Math.floor(Math.random() * cs.length)]), cb(cs[Math.floor(Math.random() * cs.length)])); | |
ab = false; // Reset the add bubble flag | |
} | |
if (rb && bs.length > 2) { | |
bs.splice(-2, 2); | |
rb = false; // Reset the remove bubble flag | |
} | |
dbi(); | |
fc++; | |
// Draw dbi panel if visible | |
if (dbiVisible) { | |
// TODO handle dbi panel drawing code here | |
} | |
// Draw UI layer | |
uiLayer.settingsPanel.draw(ctx); | |
// ... Other UI elements ... | |
requestAnimationFrame(update); | |
} | |
update(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment