Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Watermelon Physics Simulation</title>
- <style>
- body {
- margin: 0;
- padding: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- background-color: #f0f0f0;
- font-family: Arial, sans-serif;
- }
- #canvas-container {
- position: relative;
- width: 800px;
- height: 800px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
- }
- canvas {
- background-color: #ffffff;
- }
- #controls {
- position: absolute;
- bottom: 10px;
- left: 10px;
- }
- button {
- padding: 8px 16px;
- background-color: #4CAF50;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- }
- button:hover {
- background-color: #45a049;
- }
- </style>
- </head>
- <body>
- <div id="canvas-container">
- <canvas id="simulation" width="800" height="800"></canvas>
- <div id="controls">
- <button id="restart">Restart Simulation</button>
- </div>
- </div>
- <script>
- // Canvas setup
- const canvas = document.getElementById('simulation');
- const ctx = canvas.getContext('2d');
- const width = canvas.width;
- const height = canvas.height;
- const restartBtn = document.getElementById('restart');
- // Physics constants
- const GRAVITY = 0.5;
- const GROUND_Y = height - 50;
- const FRICTION = 0.95;
- const BOUNCE = 0.6;
- const ELASTICITY = 0.7;
- // Watermelon properties
- const WATERMELON_RADIUS = 40;
- const FRAGMENT_COUNT = 12;
- const SEED_COUNT = 30;
- const SEED_SIZE = 3;
- // Simulation state
- let watermelon = null;
- let fragments = [];
- let seeds = [];
- let simulationStarted = false;
- let simulationFinished = false;
- // Watermelon class
- class Watermelon {
- constructor() {
- this.x = width / 2;
- this.y = 100;
- this.radius = WATERMELON_RADIUS;
- this.velocityY = 0;
- this.velocityX = 0;
- this.rotation = 0;
- this.rotationSpeed = 0;
- this.burst = false;
- }
- update() {
- if (this.burst) return;
- this.velocityY += GRAVITY;
- this.y += this.velocityY;
- this.x += this.velocityX;
- this.rotation += this.rotationSpeed;
- // Check ground collision
- if (this.y + this.radius >= GROUND_Y) {
- this.y = GROUND_Y - this.radius;
- // If velocity is high enough, burst the watermelon
- if (this.velocityY > 10) {
- this.burst = true;
- createFragments();
- createSeeds();
- } else {
- // Otherwise just bounce
- this.velocityY = -this.velocityY * BOUNCE;
- this.velocityX *= FRICTION;
- }
- }
- // Check wall collisions
- if (this.x - this.radius <= 0 || this.x + this.radius >= width) {
- this.velocityX = -this.velocityX * BOUNCE;
- this.x = this.x - this.radius <= 0 ? this.radius : width - this.radius;
- }
- }
- draw() {
- if (this.burst) return;
- ctx.save();
- ctx.translate(this.x, this.y);
- ctx.rotate(this.rotation);
- // Draw watermelon (ellipse)
- ctx.beginPath();
- ctx.ellipse(0, 0, this.radius, this.radius * 0.8, 0, 0, Math.PI * 2);
- // Create gradient for 3D effect
- const gradient = ctx.createRadialGradient(
- -this.radius * 0.3, -this.radius * 0.3, 0,
- 0, 0, this.radius
- );
- gradient.addColorStop(0, '#ff6b6b');
- gradient.addColorStop(1, '#e74c3c');
- ctx.fillStyle = gradient;
- ctx.fill();
- // Draw green rind
- ctx.beginPath();
- ctx.ellipse(0, 0, this.radius, this.radius * 0.8, 0, 0, Math.PI * 2);
- ctx.strokeStyle = '#2ecc71';
- ctx.lineWidth = this.radius * 0.15;
- ctx.stroke();
- // Draw rind patterns
- ctx.strokeStyle = '#27ae60';
- ctx.lineWidth = 1;
- for (let i = 0; i < 8; i++) {
- const angle = (i / 8) * Math.PI * 2;
- ctx.beginPath();
- ctx.moveTo(0, 0);
- ctx.lineTo(
- Math.cos(angle) * (this.radius - this.radius * 0.15),
- Math.sin(angle) * (this.radius * 0.8 - this.radius * 0.15 * 0.8)
- );
- ctx.stroke();
- }
- ctx.restore();
- }
- }
- // Fragment class
- class Fragment {
- constructor(x, y, size, angle) {
- this.x = x;
- this.y = y;
- this.size = size;
- this.velocityX = Math.cos(angle) * (Math.random() * 10 + 5);
- this.velocityY = Math.sin(angle) * (Math.random() * 10 - 15);
- this.rotation = Math.random() * Math.PI * 2;
- this.rotationSpeed = (Math.random() - 0.5) * 0.2;
- this.color = Math.random() > 0.5 ? '#e74c3c' : '#c0392b';
- this.shape = Math.random() > 0.5 ? 'circle' : 'polygon';
- this.polygonPoints = Math.floor(Math.random() * 3) + 3; // 3-5 points
- this.bounceCount = 0;
- this.active = true;
- }
- update() {
- if (!this.active) return;
- this.velocityY += GRAVITY;
- this.x += this.velocityX;
- this.y += this.velocityY;
- this.rotation += this.rotationSpeed;
- // Ground collision
- if (this.y + this.size >= GROUND_Y) {
- this.y = GROUND_Y - this.size;
- this.velocityY = -this.velocityY * BOUNCE;
- this.velocityX *= FRICTION;
- this.rotationSpeed *= FRICTION;
- this.bounceCount++;
- // Stop after a few bounces
- if (this.bounceCount > 3 || Math.abs(this.velocityY) < 1) {
- this.velocityY = 0;
- this.velocityX *= 0.8;
- }
- }
- // Wall collisions
- if (this.x - this.size <= 0 || this.x + this.size >= width) {
- this.velocityX = -this.velocityX * BOUNCE;
- this.x = this.x - this.size <= 0 ? this.size : width - this.size;
- }
- // Deactivate if nearly stopped
- if (Math.abs(this.velocityX) < 0.1 && Math.abs(this.velocityY) < 0.1 &&
- this.y + this.size >= GROUND_Y - 1) {
- this.velocityX = 0;
- this.velocityY = 0;
- }
- }
- draw() {
- if (!this.active) return;
- ctx.save();
- ctx.translate(this.x, this.y);
- ctx.rotate(this.rotation);
- if (this.shape === 'circle') {
- ctx.beginPath();
- ctx.arc(0, 0, this.size, 0, Math.PI * 2);
- ctx.fillStyle = this.color;
- ctx.fill();
- // Add rind effect
- ctx.beginPath();
- ctx.arc(0, 0, this.size, 0, Math.PI * 2);
- ctx.strokeStyle = '#2ecc71';
- ctx.lineWidth = this.size * 0.2;
- ctx.stroke();
- } else {
- // Draw polygon
- ctx.beginPath();
- const angleStep = (Math.PI * 2) / this.polygonPoints;
- for (let i = 0; i < this.polygonPoints; i++) {
- const x = Math.cos(i * angleStep) * this.size;
- const y = Math.sin(i * angleStep) * this.size;
- if (i === 0) {
- ctx.moveTo(x, y);
- } else {
- ctx.lineTo(x, y);
- }
- }
- ctx.closePath();
- ctx.fillStyle = this.color;
- ctx.fill();
- // Add rind effect
- ctx.beginPath();
- const angleStep2 = (Math.PI * 2) / this.polygonPoints;
- for (let i = 0; i < this.polygonPoints; i++) {
- const x = Math.cos(i * angleStep2) * (this.size * 0.8);
- const y = Math.sin(i * angleStep2) * (this.size * 0.8);
- if (i === 0) {
- ctx.moveTo(x, y);
- } else {
- ctx.lineTo(x, y);
- }
- }
- ctx.closePath();
- ctx.strokeStyle = '#2ecc71';
- ctx.lineWidth = this.size * 0.2;
- ctx.stroke();
- }
- ctx.restore();
- }
- }
- // Seed class
- class Seed {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- this.size = SEED_SIZE;
- this.velocityX = (Math.random() - 0.5) * 20;
- this.velocityY = (Math.random() - 0.5) * 20 - 10;
- this.rotation = Math.random() * Math.PI * 2;
- this.rotationSpeed = (Math.random() - 0.5) * 0.2;
- this.active = true;
- }
- update() {
- if (!this.active) return;
- this.velocityY += GRAVITY * 0.8;
- this.x += this.velocityX;
- this.y += this.velocityY;
- this.rotation += this.rotationSpeed;
- // Ground collision
- if (this.y + this.size >= GROUND_Y) {
- this.y = GROUND_Y - this.size;
- this.velocityY = -this.velocityY * 0.4;
- this.velocityX *= FRICTION;
- this.rotationSpeed *= FRICTION;
- // Stop if velocity is very low
- if (Math.abs(this.velocityY) < 0.5) {
- this.velocityY = 0;
- }
- }
- // Wall collisions
- if (this.x - this.size <= 0 || this.x + this.size >= width) {
- this.velocityX = -this.velocityX * 0.4;
- this.x = this.x - this.size <= 0 ? this.size : width - this.size;
- }
- }
- draw() {
- if (!this.active) return;
- ctx.save();
- ctx.translate(this.x, this.y);
- ctx.rotate(this.rotation);
- // Draw seed
- ctx.beginPath();
- ctx.ellipse(0, 0, this.size, this.size * 2, 0, 0, Math.PI * 2);
- ctx.fillStyle = '#5d4037';
- ctx.fill();
- ctx.restore();
- }
- }
- // Create fragments when watermelon bursts
- function createFragments() {
- const centerX = watermelon.x;
- const centerY = watermelon.y;
- for (let i = 0; i < FRAGMENT_COUNT; i++) {
- const angle = (i / FRAGMENT_COUNT) * Math.PI * 2;
- const size = watermelon.radius * (0.3 + Math.random() * 0.3);
- fragments.push(new Fragment(centerX, centerY, size, angle));
- }
- }
- // Create seeds when watermelon bursts
- function createSeeds() {
- const centerX = watermelon.x;
- const centerY = watermelon.y;
- for (let i = 0; i < SEED_COUNT; i++) {
- seeds.push(new Seed(
- centerX + (Math.random() - 0.5) * watermelon.radius * 1.5,
- centerY + (Math.random() - 0.5) * watermelon.radius * 1.5
- ));
- }
- }
- // Draw ground
- function drawGround() {
- ctx.fillStyle = '#8B4513';
- ctx.fillRect(0, GROUND_Y, width, height - GROUND_Y);
- // Add grass texture
- ctx.fillStyle = '#3a5f0b';
- for (let i = 0; i < width; i += 5) {
- const height = 5 + Math.random() * 5;
- ctx.fillRect(i, GROUND_Y - height, 3, height);
- }
- }
- // Initialize simulation
- function initSimulation() {
- watermelon = new Watermelon();
- fragments = [];
- seeds = [];
- simulationStarted = true;
- simulationFinished = false;
- }
- // Animation loop
- function animate() {
- ctx.clearRect(0, 0, width, height);
- // Draw ground
- drawGround();
- // Update and draw watermelon
- if (watermelon && !watermelon.burst) {
- watermelon.update();
- watermelon.draw();
- }
- // Update and draw fragments
- fragments.forEach(fragment => {
- fragment.update();
- fragment.draw();
- });
- // Update and draw seeds
- seeds.forEach(seed => {
- seed.update();
- seed.draw();
- });
- // Check if simulation is finished (all fragments and seeds have stopped)
- if (watermelon && watermelon.burst) {
- const allStopped = fragments.every(f =>
- Math.abs(f.velocityX) < 0.1 && Math.abs(f.velocityY) < 0.1) &&
- seeds.every(s =>
- Math.abs(s.velocityX) < 0.1 && Math.abs(s.velocityY) < 0.1);
- if (allStopped && !simulationFinished) {
- simulationFinished = true;
- console.log("Simulation finished");
- }
- }
- requestAnimationFrame(animate);
- }
- // Start simulation
- restartBtn.addEventListener('click', initSimulation);
- initSimulation();
- animate();
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment