<html><head><title>Crypto Collision Physics Simulation</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
#container {
width: 400px;
height: 400px;
border-radius: 50%;
border: 2px solid #333;
position: relative;
overflow: hidden;
}
.crypto-ball {
width: 40px;
height: 40px;
border-radius: 50%;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 10px;
color: #fff;
text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
}
#controls {
position: absolute;
top: 20px;
left: 20px;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px;
border-radius: 5px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="range"] {
width: 200px;
}
button {
margin-top: 10px;
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="controls">
<label for="gravity">Gravity: <span id="gravityValue">0.5</span></label>
<input type="range" id="gravity" min="0" max="2" step="0.1" value="0.5">
<label for="friction">Friction: <span id="frictionValue">0.99</span></label>
<input type="range" id="friction" min="0.9" max="1" step="0.01" value="0.99">
<label for="restitution">Restitution: <span id="restitutionValue">0.7</span></label>
<input type="range" id="restitution" min="0" max="1" step="0.1" value="0.7">
<button id="resetBalls">Reset Crypto</button>
</div>
<script>
const container = document.getElementById('container');
const containerRect = container.getBoundingClientRect();
let cryptoBalls = [];
let gravity = 0.5;
let friction = 0.99;
let restitution = 0.7;
const cryptoSymbols = ['BTC', 'ETH', 'ADA', 'SOL', 'DOGE', 'QQ', 'NO', 'PEPE', 'GF', 'PANDA', 'YAYA', 'SATOSHI', 'CAT', 'ORD', 'CLOWN', 'YY', 'JUMP', 'DONALD', 'A', 'MIMI', 'MIQI', 'RABBIT', 'SHEEP', 'SNAKE', 'PEACE', 'RAT', 'MONKEY', 'DRAGON', 'X', 'SEAL', 'COW', 'OTTER', 'ORD(', 'ORD{', 'ORD%', 'ORD<'];
const gravitySlider = document.getElementById('gravity');
const frictionSlider = document.getElementById('friction');
const restitutionSlider = document.getElementById('restitution');
const gravityValue = document.getElementById('gravityValue');
const frictionValue = document.getElementById('frictionValue');
const restitutionValue = document.getElementById('restitutionValue');
const resetButton = document.getElementById('resetBalls');
gravitySlider.addEventListener('input', updatePhysics);
frictionSlider.addEventListener('input', updatePhysics);
restitutionSlider.addEventListener('input', updatePhysics);
resetButton.addEventListener('click', resetCryptoBalls);
function updatePhysics() {
gravity = parseFloat(gravitySlider.value);
friction = parseFloat(frictionSlider.value);
restitution = parseFloat(restitutionSlider.value);
gravityValue.textContent = gravity.toFixed(1);
frictionValue.textContent = friction.toFixed(2);
restitutionValue.textContent = restitution.toFixed(1);
}
function resetCryptoBalls() {
cryptoBalls.forEach(ball => container.removeChild(ball.element));
cryptoBalls = [];
createCryptoBall();
}
function createCryptoBall() {
if (cryptoBalls.length >= 50) return null; // Limit the number of crypto balls
const ballElement = document.createElement('div');
ballElement.className = 'crypto-ball';
const symbol = cryptoSymbols[Math.floor(Math.random() * cryptoSymbols.length)];
ballElement.textContent = symbol;
ballElement.style.backgroundColor = getRandomColor();
container.appendChild(ballElement);
const ball = {
element: ballElement,
x: containerRect.width / 2 - 20,
y: containerRect.height / 2 - 20,
vx: (Math.random() - 0.5) * 10,
vy: (Math.random() - 0.5) * 10,
radius: 20,
lastBounceTime: 0,
symbol: symbol
};
cryptoBalls.push(ball);
return ball;
}
function getRandomColor() {
const hue = Math.floor(Math.random() * 360);
return `hsl(${hue}, 70%, 50%)`;
}
function animate() {
const containerRadius = containerRect.width / 2;
const centerX = containerRect.width / 2;
const centerY = containerRect.height / 2;
const currentTime = Date.now();
cryptoBalls.forEach(ball => {
// Apply gravity
ball.vy += gravity;
// Apply friction
ball.vx *= friction;
ball.vy *= friction;
// Update position
ball.x += ball.vx;
ball.y += ball.vy;
// Check for collisions with container
const distanceFromCenter = Math.sqrt(Math.pow(ball.x - centerX, 2) + Math.pow(ball.y - centerY, 2));
if (distanceFromCenter + ball.radius > containerRadius) {
const angle = Math.atan2(ball.y - centerY, ball.x - centerX);
const normalX = Math.cos(angle);
const normalY = Math.sin(angle);
const dotProduct = ball.vx * normalX + ball.vy * normalY;
ball.vx -= (1 + restitution) * dotProduct * normalX;
ball.vy -= (1 + restitution) * dotProduct * normalY;
ball.x = centerX + (containerRadius - ball.radius) * Math.cos(angle);
ball.y = centerY + (containerRadius - ball.radius) * Math.sin(angle);
// Check if the ball is moving fast enough to consider it a bounce
const speed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy);
if (speed > 1 && currentTime - ball.lastBounceTime > 500) {
ball.lastBounceTime = currentTime;
createCryptoBall(); // Instantly create a new crypto ball on bounce
}
}
// Check for collisions with other crypto balls
cryptoBalls.forEach(otherBall => {
if (ball === otherBall) return;
const dx = otherBall.x - ball.x;
const dy = otherBall.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < ball.radius + otherBall.radius) {
// Collision detected
const angle = Math.atan2(dy, dx);
const sin = Math.sin(angle);
const cos = Math.cos(angle);
// Rotate ball velocities
const vx1 = ball.vx * cos + ball.vy * sin;
const vy1 = ball.vy * cos - ball.vx * sin;
const vx2 = otherBall.vx * cos + otherBall.vy * sin;
const vy2 = otherBall.vy * cos - otherBall.vx * sin;
// Swap ball velocities
const temp_vx1 = vx2;
const temp_vy1 = vy1;
const temp_vx2 = vx1;
const temp_vy2 = vy2;
// Rotate velocities back
ball.vx = temp_vx1 * cos - temp_vy1 * sin;
ball.vy = temp_vy1 * cos + temp_vx1 * sin;
otherBall.vx = temp_vx2 * cos - temp_vy2 * sin;
otherBall.vy = temp_vy2 * cos + temp_vx2 * sin;
// Move balls apart
const overlap = ball.radius + otherBall.radius - distance;
const moveX = overlap * cos / 2;
const moveY = overlap * sin / 2;
ball.x -= moveX;
ball.y -= moveY;
otherBall.x += moveX;
otherBall.y += moveY;
}
});
// Update ball position
ball.element.style.left = `${ball.x - ball.radius}px`;
ball.element.style.top = `${ball.y - ball.radius}px`;
});
requestAnimationFrame(animate);
}
// Initialize with one crypto ball
createCryptoBall();
animate();
// Add interactivity to the crypto balls
let isDragging = false;
let draggedBall = null;
let startX, startY;
container.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', endDrag);
container.addEventListener('touchstart', startDrag);
document.addEventListener('touchmove', drag);
document.addEventListener('touchend', endDrag);
function startDrag(e) {
const clientX = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX;
const clientY = e.type === 'mousedown' ? e.clientY : e.touches[0].clientY;
cryptoBalls.forEach(ball => {
const rect = ball.element.getBoundingClientRect();
if (clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom) {
isDragging = true;
draggedBall = ball;
startX = clientX - ball.x;
startY = clientY - ball.y;
e.preventDefault();
return;
}
});
}
function drag(e) {
if (!isDragging || !draggedBall) return;
const clientX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX;
const clientY = e.type === 'mousemove' ? e.clientY : e.touches[0].clientY;
draggedBall.x = clientX - startX;
draggedBall.y = clientY - startY;
const containerRadius = containerRect.width / 2;
const centerX = containerRect.width / 2;
const centerY = containerRect.height / 2;
const distanceFromCenter = Math.sqrt(Math.pow(draggedBall.x - centerX, 2) + Math.pow(draggedBall.y - centerY, 2));
if (distanceFromCenter + draggedBall.radius > containerRadius) {
const angle = Math.atan2(draggedBall.y - centerY, draggedBall.x - centerX);
draggedBall.x = centerX + (containerRadius - draggedBall.radius) * Math.cos(angle);
draggedBall.y = centerY + (containerRadius - draggedBall.radius) * Math.sin(angle);
}
draggedBall.element.style.left = `${draggedBall.x - draggedBall.radius}px`;
draggedBall.element.style.top = `${draggedBall.y - draggedBall.radius}px`;
}
function endDrag() {
if (isDragging && draggedBall) {
isDragging = false;
draggedBall.vx = 0;
draggedBall.vy = 0;
draggedBall = null;
}
}
</script>
</body></html>