Guest User

WaterMelon

a guest
Apr 14th, 2025
357
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.34 KB | Source Code | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Watermelon Physics Simulation</title>
  7. <style>
  8. body {
  9. margin: 0;
  10. padding: 0;
  11. display: flex;
  12. justify-content: center;
  13. align-items: center;
  14. height: 100vh;
  15. background-color: #f0f0f0;
  16. font-family: Arial, sans-serif;
  17. }
  18. #canvas-container {
  19. position: relative;
  20. width: 800px;
  21. height: 800px;
  22. box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  23. }
  24. canvas {
  25. background-color: #ffffff;
  26. }
  27. #controls {
  28. position: absolute;
  29. bottom: 10px;
  30. left: 10px;
  31. }
  32. button {
  33. padding: 8px 16px;
  34. background-color: #4CAF50;
  35. color: white;
  36. border: none;
  37. border-radius: 4px;
  38. cursor: pointer;
  39. font-size: 14px;
  40. }
  41. button:hover {
  42. background-color: #45a049;
  43. }
  44. </style>
  45. </head>
  46. <body>
  47. <div id="canvas-container">
  48. <canvas id="simulation" width="800" height="800"></canvas>
  49. <div id="controls">
  50. <button id="restart">Restart Simulation</button>
  51. </div>
  52. </div>
  53.  
  54. <script>
  55. // Canvas setup
  56. const canvas = document.getElementById('simulation');
  57. const ctx = canvas.getContext('2d');
  58. const width = canvas.width;
  59. const height = canvas.height;
  60. const restartBtn = document.getElementById('restart');
  61.  
  62. // Physics constants
  63. const GRAVITY = 0.5;
  64. const GROUND_Y = height - 50;
  65. const FRICTION = 0.95;
  66. const BOUNCE = 0.6;
  67. const ELASTICITY = 0.7;
  68.  
  69. // Watermelon properties
  70. const WATERMELON_RADIUS = 40;
  71. const FRAGMENT_COUNT = 12;
  72. const SEED_COUNT = 30;
  73. const SEED_SIZE = 3;
  74.  
  75. // Simulation state
  76. let watermelon = null;
  77. let fragments = [];
  78. let seeds = [];
  79. let simulationStarted = false;
  80. let simulationFinished = false;
  81.  
  82. // Watermelon class
  83. class Watermelon {
  84. constructor() {
  85. this.x = width / 2;
  86. this.y = 100;
  87. this.radius = WATERMELON_RADIUS;
  88. this.velocityY = 0;
  89. this.velocityX = 0;
  90. this.rotation = 0;
  91. this.rotationSpeed = 0;
  92. this.burst = false;
  93. }
  94.  
  95. update() {
  96. if (this.burst) return;
  97.  
  98. this.velocityY += GRAVITY;
  99. this.y += this.velocityY;
  100. this.x += this.velocityX;
  101. this.rotation += this.rotationSpeed;
  102.  
  103. // Check ground collision
  104. if (this.y + this.radius >= GROUND_Y) {
  105. this.y = GROUND_Y - this.radius;
  106.  
  107. // If velocity is high enough, burst the watermelon
  108. if (this.velocityY > 10) {
  109. this.burst = true;
  110. createFragments();
  111. createSeeds();
  112. } else {
  113. // Otherwise just bounce
  114. this.velocityY = -this.velocityY * BOUNCE;
  115. this.velocityX *= FRICTION;
  116. }
  117. }
  118.  
  119. // Check wall collisions
  120. if (this.x - this.radius <= 0 || this.x + this.radius >= width) {
  121. this.velocityX = -this.velocityX * BOUNCE;
  122. this.x = this.x - this.radius <= 0 ? this.radius : width - this.radius;
  123. }
  124. }
  125.  
  126. draw() {
  127. if (this.burst) return;
  128.  
  129. ctx.save();
  130. ctx.translate(this.x, this.y);
  131. ctx.rotate(this.rotation);
  132.  
  133. // Draw watermelon (ellipse)
  134. ctx.beginPath();
  135. ctx.ellipse(0, 0, this.radius, this.radius * 0.8, 0, 0, Math.PI * 2);
  136.  
  137. // Create gradient for 3D effect
  138. const gradient = ctx.createRadialGradient(
  139. -this.radius * 0.3, -this.radius * 0.3, 0,
  140. 0, 0, this.radius
  141. );
  142. gradient.addColorStop(0, '#ff6b6b');
  143. gradient.addColorStop(1, '#e74c3c');
  144.  
  145. ctx.fillStyle = gradient;
  146. ctx.fill();
  147.  
  148. // Draw green rind
  149. ctx.beginPath();
  150. ctx.ellipse(0, 0, this.radius, this.radius * 0.8, 0, 0, Math.PI * 2);
  151. ctx.strokeStyle = '#2ecc71';
  152. ctx.lineWidth = this.radius * 0.15;
  153. ctx.stroke();
  154.  
  155. // Draw rind patterns
  156. ctx.strokeStyle = '#27ae60';
  157. ctx.lineWidth = 1;
  158. for (let i = 0; i < 8; i++) {
  159. const angle = (i / 8) * Math.PI * 2;
  160. ctx.beginPath();
  161. ctx.moveTo(0, 0);
  162. ctx.lineTo(
  163. Math.cos(angle) * (this.radius - this.radius * 0.15),
  164. Math.sin(angle) * (this.radius * 0.8 - this.radius * 0.15 * 0.8)
  165. );
  166. ctx.stroke();
  167. }
  168.  
  169. ctx.restore();
  170. }
  171. }
  172.  
  173. // Fragment class
  174. class Fragment {
  175. constructor(x, y, size, angle) {
  176. this.x = x;
  177. this.y = y;
  178. this.size = size;
  179. this.velocityX = Math.cos(angle) * (Math.random() * 10 + 5);
  180. this.velocityY = Math.sin(angle) * (Math.random() * 10 - 15);
  181. this.rotation = Math.random() * Math.PI * 2;
  182. this.rotationSpeed = (Math.random() - 0.5) * 0.2;
  183. this.color = Math.random() > 0.5 ? '#e74c3c' : '#c0392b';
  184. this.shape = Math.random() > 0.5 ? 'circle' : 'polygon';
  185. this.polygonPoints = Math.floor(Math.random() * 3) + 3; // 3-5 points
  186. this.bounceCount = 0;
  187. this.active = true;
  188. }
  189.  
  190. update() {
  191. if (!this.active) return;
  192.  
  193. this.velocityY += GRAVITY;
  194. this.x += this.velocityX;
  195. this.y += this.velocityY;
  196. this.rotation += this.rotationSpeed;
  197.  
  198. // Ground collision
  199. if (this.y + this.size >= GROUND_Y) {
  200. this.y = GROUND_Y - this.size;
  201. this.velocityY = -this.velocityY * BOUNCE;
  202. this.velocityX *= FRICTION;
  203. this.rotationSpeed *= FRICTION;
  204. this.bounceCount++;
  205.  
  206. // Stop after a few bounces
  207. if (this.bounceCount > 3 || Math.abs(this.velocityY) < 1) {
  208. this.velocityY = 0;
  209. this.velocityX *= 0.8;
  210. }
  211. }
  212.  
  213. // Wall collisions
  214. if (this.x - this.size <= 0 || this.x + this.size >= width) {
  215. this.velocityX = -this.velocityX * BOUNCE;
  216. this.x = this.x - this.size <= 0 ? this.size : width - this.size;
  217. }
  218.  
  219. // Deactivate if nearly stopped
  220. if (Math.abs(this.velocityX) < 0.1 && Math.abs(this.velocityY) < 0.1 &&
  221. this.y + this.size >= GROUND_Y - 1) {
  222. this.velocityX = 0;
  223. this.velocityY = 0;
  224. }
  225. }
  226.  
  227. draw() {
  228. if (!this.active) return;
  229.  
  230. ctx.save();
  231. ctx.translate(this.x, this.y);
  232. ctx.rotate(this.rotation);
  233.  
  234. if (this.shape === 'circle') {
  235. ctx.beginPath();
  236. ctx.arc(0, 0, this.size, 0, Math.PI * 2);
  237. ctx.fillStyle = this.color;
  238. ctx.fill();
  239.  
  240. // Add rind effect
  241. ctx.beginPath();
  242. ctx.arc(0, 0, this.size, 0, Math.PI * 2);
  243. ctx.strokeStyle = '#2ecc71';
  244. ctx.lineWidth = this.size * 0.2;
  245. ctx.stroke();
  246. } else {
  247. // Draw polygon
  248. ctx.beginPath();
  249. const angleStep = (Math.PI * 2) / this.polygonPoints;
  250. for (let i = 0; i < this.polygonPoints; i++) {
  251. const x = Math.cos(i * angleStep) * this.size;
  252. const y = Math.sin(i * angleStep) * this.size;
  253. if (i === 0) {
  254. ctx.moveTo(x, y);
  255. } else {
  256. ctx.lineTo(x, y);
  257. }
  258. }
  259. ctx.closePath();
  260. ctx.fillStyle = this.color;
  261. ctx.fill();
  262.  
  263. // Add rind effect
  264. ctx.beginPath();
  265. const angleStep2 = (Math.PI * 2) / this.polygonPoints;
  266. for (let i = 0; i < this.polygonPoints; i++) {
  267. const x = Math.cos(i * angleStep2) * (this.size * 0.8);
  268. const y = Math.sin(i * angleStep2) * (this.size * 0.8);
  269. if (i === 0) {
  270. ctx.moveTo(x, y);
  271. } else {
  272. ctx.lineTo(x, y);
  273. }
  274. }
  275. ctx.closePath();
  276. ctx.strokeStyle = '#2ecc71';
  277. ctx.lineWidth = this.size * 0.2;
  278. ctx.stroke();
  279. }
  280.  
  281. ctx.restore();
  282. }
  283. }
  284.  
  285. // Seed class
  286. class Seed {
  287. constructor(x, y) {
  288. this.x = x;
  289. this.y = y;
  290. this.size = SEED_SIZE;
  291. this.velocityX = (Math.random() - 0.5) * 20;
  292. this.velocityY = (Math.random() - 0.5) * 20 - 10;
  293. this.rotation = Math.random() * Math.PI * 2;
  294. this.rotationSpeed = (Math.random() - 0.5) * 0.2;
  295. this.active = true;
  296. }
  297.  
  298. update() {
  299. if (!this.active) return;
  300.  
  301. this.velocityY += GRAVITY * 0.8;
  302. this.x += this.velocityX;
  303. this.y += this.velocityY;
  304. this.rotation += this.rotationSpeed;
  305.  
  306. // Ground collision
  307. if (this.y + this.size >= GROUND_Y) {
  308. this.y = GROUND_Y - this.size;
  309. this.velocityY = -this.velocityY * 0.4;
  310. this.velocityX *= FRICTION;
  311. this.rotationSpeed *= FRICTION;
  312.  
  313. // Stop if velocity is very low
  314. if (Math.abs(this.velocityY) < 0.5) {
  315. this.velocityY = 0;
  316. }
  317. }
  318.  
  319. // Wall collisions
  320. if (this.x - this.size <= 0 || this.x + this.size >= width) {
  321. this.velocityX = -this.velocityX * 0.4;
  322. this.x = this.x - this.size <= 0 ? this.size : width - this.size;
  323. }
  324. }
  325.  
  326. draw() {
  327. if (!this.active) return;
  328.  
  329. ctx.save();
  330. ctx.translate(this.x, this.y);
  331. ctx.rotate(this.rotation);
  332.  
  333. // Draw seed
  334. ctx.beginPath();
  335. ctx.ellipse(0, 0, this.size, this.size * 2, 0, 0, Math.PI * 2);
  336. ctx.fillStyle = '#5d4037';
  337. ctx.fill();
  338.  
  339. ctx.restore();
  340. }
  341. }
  342.  
  343. // Create fragments when watermelon bursts
  344. function createFragments() {
  345. const centerX = watermelon.x;
  346. const centerY = watermelon.y;
  347.  
  348. for (let i = 0; i < FRAGMENT_COUNT; i++) {
  349. const angle = (i / FRAGMENT_COUNT) * Math.PI * 2;
  350. const size = watermelon.radius * (0.3 + Math.random() * 0.3);
  351. fragments.push(new Fragment(centerX, centerY, size, angle));
  352. }
  353. }
  354.  
  355. // Create seeds when watermelon bursts
  356. function createSeeds() {
  357. const centerX = watermelon.x;
  358. const centerY = watermelon.y;
  359.  
  360. for (let i = 0; i < SEED_COUNT; i++) {
  361. seeds.push(new Seed(
  362. centerX + (Math.random() - 0.5) * watermelon.radius * 1.5,
  363. centerY + (Math.random() - 0.5) * watermelon.radius * 1.5
  364. ));
  365. }
  366. }
  367.  
  368. // Draw ground
  369. function drawGround() {
  370. ctx.fillStyle = '#8B4513';
  371. ctx.fillRect(0, GROUND_Y, width, height - GROUND_Y);
  372.  
  373. // Add grass texture
  374. ctx.fillStyle = '#3a5f0b';
  375. for (let i = 0; i < width; i += 5) {
  376. const height = 5 + Math.random() * 5;
  377. ctx.fillRect(i, GROUND_Y - height, 3, height);
  378. }
  379. }
  380.  
  381. // Initialize simulation
  382. function initSimulation() {
  383. watermelon = new Watermelon();
  384. fragments = [];
  385. seeds = [];
  386. simulationStarted = true;
  387. simulationFinished = false;
  388. }
  389.  
  390. // Animation loop
  391. function animate() {
  392. ctx.clearRect(0, 0, width, height);
  393.  
  394. // Draw ground
  395. drawGround();
  396.  
  397. // Update and draw watermelon
  398. if (watermelon && !watermelon.burst) {
  399. watermelon.update();
  400. watermelon.draw();
  401. }
  402.  
  403. // Update and draw fragments
  404. fragments.forEach(fragment => {
  405. fragment.update();
  406. fragment.draw();
  407. });
  408.  
  409. // Update and draw seeds
  410. seeds.forEach(seed => {
  411. seed.update();
  412. seed.draw();
  413. });
  414.  
  415. // Check if simulation is finished (all fragments and seeds have stopped)
  416. if (watermelon && watermelon.burst) {
  417. const allStopped = fragments.every(f =>
  418. Math.abs(f.velocityX) < 0.1 && Math.abs(f.velocityY) < 0.1) &&
  419. seeds.every(s =>
  420. Math.abs(s.velocityX) < 0.1 && Math.abs(s.velocityY) < 0.1);
  421.  
  422. if (allStopped && !simulationFinished) {
  423. simulationFinished = true;
  424. console.log("Simulation finished");
  425. }
  426. }
  427.  
  428. requestAnimationFrame(animate);
  429. }
  430.  
  431. // Start simulation
  432. restartBtn.addEventListener('click', initSimulation);
  433. initSimulation();
  434. animate();
  435. </script>
  436. </body>
  437. </html>
Tags: GLM4
Advertisement
Add Comment
Please, Sign In to add comment