您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Advanced liquid physics simulation with interactive bubbles, fluid dynamics, and collaborative drawing effects for drawaria.online!
// ==UserScript== // @name Drawaria Liquid Bubble Canvas & Interactive Physics // @namespace http://tampermonkey.net/ // @version 1.1 // @description Advanced liquid physics simulation with interactive bubbles, fluid dynamics, and collaborative drawing effects for drawaria.online! // @author YouTubeDrawaria // @match https://drawaria.online/* // @grant none // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // ==/UserScript== (function() { 'use strict'; // Physics simulation state const physicsState = { bubbles: [], liquidDrops: [], gravityStrength: 0.1, viscosity: 0.99, tension: 0.1, interactionRadius: 80, maxBubbles: 50, liquidMode: true, magneticMode: false, antigravityMode: false, colorMixing: true, trailMode: false }; // Advanced bubble with liquid physics class LiquidBubble { constructor(x, y, radius = null, color = null) { this.x = x || Math.random() * window.innerWidth; this.y = y || Math.random() * window.innerHeight; this.vx = (Math.random() - 0.5) * 4; this.vy = (Math.random() - 0.5) * 4; this.radius = radius || Math.random() * 30 + 15; this.originalRadius = this.radius; this.mass = this.radius * 0.1; this.color = color || this.generateColor(); this.alpha = Math.random() * 0.6 + 0.4; this.life = 1.0; this.age = 0; this.elasticity = 0.8; this.temperature = Math.random() * 100 + 50; this.magneticCharge = Math.random() > 0.5 ? 1 : -1; this.trailPoints = []; this.maxTrailLength = 20; this.connections = []; this.vibrationPhase = Math.random() * Math.PI * 2; } generateColor() { const colors = [ 'rgba(64, 224, 255, 0.7)', // Deep sky blue 'rgba(255, 105, 180, 0.7)', // Hot pink 'rgba(50, 255, 126, 0.7)', // Spring green 'rgba(255, 215, 0, 0.7)', // Gold 'rgba(138, 43, 226, 0.7)', // Blue violet 'rgba(255, 69, 0, 0.7)' // Red orange ]; return colors[Math.floor(Math.random() * colors.length)]; } update(bubbles, mouseX, mouseY) { this.age++; // Update trail if (physicsState.trailMode) { this.trailPoints.push({ x: this.x, y: this.y, alpha: 0.8 }); if (this.trailPoints.length > this.maxTrailLength) { this.trailPoints.shift(); } // Fade trail points this.trailPoints.forEach((point, index) => { point.alpha *= 0.95; }); } // Mouse interaction if (mouseX !== undefined && mouseY !== undefined) { const dx = this.x - mouseX; const dy = this.y - mouseY; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < physicsState.interactionRadius) { const force = (physicsState.interactionRadius - distance) / physicsState.interactionRadius; const angle = Math.atan2(dy, dx); if (physicsState.magneticMode) { // Magnetic attraction/repulsion const magneticForce = force * this.magneticCharge * 2; this.vx += Math.cos(angle) * magneticForce; this.vy += Math.sin(angle) * magneticForce; } else { // Normal repulsion this.vx += Math.cos(angle) * force * 3; this.vy += Math.sin(angle) * force * 3; } // Change temperature based on interaction this.temperature += force * 10; this.radius = this.originalRadius + Math.sin(this.age * 0.1) * 5; } } // Gravity or anti-gravity if (physicsState.antigravityMode) { this.vy -= physicsState.gravityStrength; } else { this.vy += physicsState.gravityStrength; } // Bubble-to-bubble interactions this.connections = []; bubbles.forEach(other => { if (other !== this) { const dx = other.x - this.x; const dy = other.y - this.y; const distance = Math.sqrt(dx * dx + dy * dy); const minDistance = this.radius + other.radius; if (distance < minDistance + 30) { // Surface tension effect const overlap = minDistance - distance; if (overlap > 0) { const force = overlap * physicsState.tension; const angle = Math.atan2(dy, dx); this.vx -= Math.cos(angle) * force * 0.5; this.vy -= Math.sin(angle) * force * 0.5; // Color mixing on collision if (physicsState.colorMixing && overlap > 10) { this.mixColors(other); } } // Create connection for visual effect if (distance < minDistance + 50) { this.connections.push({ bubble: other, distance: distance, strength: 1 - (distance / (minDistance + 50)) }); } } } }); // Apply viscosity (liquid resistance) this.vx *= physicsState.viscosity; this.vy *= physicsState.viscosity; // Update position this.x += this.vx; this.y += this.vy; // Temperature cooling this.temperature *= 0.995; // Size pulsation based on temperature const tempFactor = (this.temperature - 50) / 100; this.radius = this.originalRadius + tempFactor * 10 + Math.sin(this.vibrationPhase + this.age * 0.1) * 2; this.vibrationPhase += 0.1; // Wall collision with liquid deformation if (this.x - this.radius < 0 || this.x + this.radius > window.innerWidth) { this.vx *= -this.elasticity; this.x = Math.max(this.radius, Math.min(window.innerWidth - this.radius, this.x)); this.deform(); } if (this.y - this.radius < 0 || this.y + this.radius > window.innerHeight) { this.vy *= -this.elasticity; this.y = Math.max(this.radius, Math.min(window.innerHeight - this.radius, this.y)); this.deform(); } // Life decay if (this.age > 2000) { this.life *= 0.999; } return this.life > 0.1; } mixColors(other) { // Simple color mixing algorithm const thisColor = this.parseColor(this.color); const otherColor = other.parseColor(other.color); if (thisColor && otherColor) { const newR = Math.floor((thisColor.r + otherColor.r) / 2); const newG = Math.floor((thisColor.g + otherColor.g) / 2); const newB = Math.floor((thisColor.b + otherColor.b) / 2); this.color = `rgba(${newR}, ${newG}, ${newB}, 0.7)`; } } parseColor(color) { const match = color.match(/rgba?$$(\d+),\s*(\d+),\s*(\d+)/); if (match) { return { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) }; } return null; } deform() { // Temporary deformation effect this.radius *= 1.2; setTimeout(() => { this.radius = this.originalRadius; }, 100); } draw(ctx) { ctx.save(); // Draw trail if (physicsState.trailMode && this.trailPoints.length > 1) { ctx.strokeStyle = this.color; ctx.lineWidth = 2; ctx.globalAlpha = 0.3; ctx.beginPath(); ctx.moveTo(this.trailPoints.x, this.trailPoints.y); for (let i = 1; i < this.trailPoints.length; i++) { ctx.lineTo(this.trailPoints[i].x, this.trailPoints[i].y); } ctx.stroke(); } // Draw connections this.connections.forEach(conn => { ctx.globalAlpha = conn.strength * 0.3; ctx.strokeStyle = this.color; ctx.lineWidth = conn.strength * 3; ctx.beginPath(); ctx.moveTo(this.x, this.y); ctx.lineTo(conn.bubble.x, conn.bubble.y); ctx.stroke(); }); // Main bubble ctx.globalAlpha = this.alpha * this.life; // Gradient fill for liquid effect const gradient = ctx.createRadialGradient( this.x - this.radius * 0.3, this.y - this.radius * 0.3, 0, this.x, this.y, this.radius ); gradient.addColorStop(0, this.color.replace('0.7', '0.9')); gradient.addColorStop(0.7, this.color); gradient.addColorStop(1, this.color.replace('0.7', '0.3')); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fill(); // Highlight for 3D effect ctx.globalAlpha = this.alpha * this.life * 0.6; ctx.fillStyle = 'rgba(255, 255, 255, 0.4)'; ctx.beginPath(); ctx.arc(this.x - this.radius * 0.3, this.y - this.radius * 0.3, this.radius * 0.3, 0, Math.PI * 2); ctx.fill(); // Temperature indicator if (this.temperature > 80) { ctx.globalAlpha = (this.temperature - 80) / 100; ctx.strokeStyle = '#ff4444'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(this.x, this.y, this.radius + 3, 0, Math.PI * 2); ctx.stroke(); } ctx.restore(); } } // Liquid drop class for additional effects class LiquidDrop { constructor(x, y) { this.x = x; this.y = y; this.vx = (Math.random() - 0.5) * 6; this.vy = Math.random() * -8 - 2; this.size = Math.random() * 8 + 4; this.color = `hsl(${Math.random() * 360}, 70%, 60%)`; this.life = 1.0; this.gravity = 0.3; } update() { this.vy += this.gravity; this.x += this.vx; this.y += this.vy; this.life -= 0.02; this.size *= 0.98; return this.y < window.innerHeight && this.life > 0; } draw(ctx) { ctx.save(); ctx.globalAlpha = this.life; ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } } // Control panel creation function createPhysicsPanel() { const panel = document.createElement('div'); panel.innerHTML = ` <div id="physics-panel" style=" position: fixed; top: 20px; right: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 20px; padding: 25px; box-shadow: 0 20px 40px rgba(0,0,0,0.4); color: white; font-family: 'Segoe UI', sans-serif; z-index: 10000; min-width: 320px; max-height: 80vh; overflow-y: auto; backdrop-filter: blur(15px); border: 1px solid rgba(255,255,255,0.2); "> <h2 style="margin: 0 0 25px 0; text-align: center;">🫧 Liquid Physics Lab</h2> <!-- Physics Controls --> <div class="physics-section" style=" background: rgba(255,255,255,0.1); padding: 15px; border-radius: 12px; margin-bottom: 20px; "> <h3 style="margin: 0 0 15px 0; color: #e0e6ff; font-size: 14px;">⚡ PHYSICS ENGINE</h3> <div style="margin: 10px 0;"> <label>Gravity: <span id="gravity-display">0.1</span></label> <input type="range" id="gravity-strength" min="0" max="0.5" step="0.01" value="0.1" style="width: 100%;"> </div> <div style="margin: 10px 0;"> <label>Viscosity: <span id="viscosity-display">0.99</span></label> <input type="range" id="viscosity" min="0.9" max="1" step="0.001" value="0.99" style="width: 100%;"> </div> <div style="margin: 10px 0;"> <label>Surface Tension: <span id="tension-display">0.1</span></label> <input type="range" id="surface-tension" min="0" max="0.5" step="0.01" value="0.1" style="width: 100%;"> </div> <div style="margin: 10px 0;"> <label>Interaction Radius: <span id="radius-display">80</span></label> <input type="range" id="interaction-radius" min="30" max="150" value="80" style="width: 100%;"> </div> </div> <!-- Bubble Controls --> <div class="physics-section" style=" background: rgba(255,255,255,0.1); padding: 15px; border-radius: 12px; margin-bottom: 20px; "> <h3 style="margin: 0 0 15px 0; color: #e0e6ff; font-size: 14px;">🫧 BUBBLE SYSTEM</h3> <div style="margin: 10px 0;"> <label>Max Bubbles: <span id="bubbles-display">50</span></label> <input type="range" id="max-bubbles" min="10" max="100" value="50" style="width: 100%;"> </div> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 15px 0;"> <button id="add-bubble" style="padding: 8px; font-size: 12px;">➕ Add Bubble</button> <button id="clear-bubbles" style="padding: 8px; font-size: 12px;">🗑️ Clear All</button> <button id="bubble-explosion" style="padding: 8px; font-size: 12px;">💥 Explosion</button> <button id="rainbow-mode" style="padding: 8px; font-size: 12px;">🌈 Rainbow</button> </div> </div> <!-- Special Modes --> <div class="physics-section" style=" background: rgba(255,255,255,0.1); padding: 15px; border-radius: 12px; margin-bottom: 20px; "> <h3 style="margin: 0 0 15px 0; color: #e0e6ff; font-size: 14px;">🔬 SPECIAL MODES</h3> <div style="display: grid; grid-template-columns: 1fr; gap: 8px;"> <button id="magnetic-mode" style="padding: 10px;">🧲 Magnetic Field</button> <button id="antigravity-mode" style="padding: 10px;">🚀 Anti-Gravity</button> <button id="color-mixing" style="padding: 10px;">🎨 Color Mixing</button> <button id="trail-mode" style="padding: 10px;">✨ Particle Trails</button> </div> </div> <!-- Environmental Presets --> <div class="physics-section" style=" background: rgba(255,255,255,0.1); padding: 15px; border-radius: 12px; "> <h3 style="margin: 0 0 15px 0; color: #e0e6ff; font-size: 14px;">🌍 ENVIRONMENTS</h3> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px;"> <button class="env-preset" data-env="water">🌊 Water</button> <button class="env-preset" data-env="space">🌌 Space</button> <button class="env-preset" data-env="lava">🌋 Lava</button> <button class="env-preset" data-env="ice">🧊 Ice</button> </div> </div> <!-- Real-time Stats --> <div style=" background: rgba(0,0,0,0.2); padding: 10px; border-radius: 8px; margin-top: 20px; font-size: 12px; "> <div>Active Bubbles: <span id="bubble-count">0</span></div> <div>Liquid Drops: <span id="drops-count">0</span></div> <div>Total Interactions: <span id="interactions-count">0</span></div> </div> </div> `; // Add styles const style = document.createElement('style'); style.textContent = ` #physics-panel button { background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.3); color: white; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; } #physics-panel button:hover { background: rgba(255, 255, 255, 0.25); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.2); } #physics-panel button.active { background: rgba(46, 213, 115, 0.4); border-color: #2ed573; } .env-preset { padding: 8px 4px !important; font-size: 11px !important; } #physics-panel input[type="range"] { background: rgba(255, 255, 255, 0.2); height: 6px; border-radius: 3px; margin: 5px 0; } `; document.head.appendChild(style); document.body.appendChild(panel); return panel; } // Main physics engine class LiquidPhysicsEngine { constructor() { this.canvas = this.createCanvas(); this.ctx = this.canvas.getContext('2d'); this.mouseX = 0; this.mouseY = 0; this.isMousePressed = false; this.lastBubbleSpawn = 0; this.interactionCount = 0; this.setupEventListeners(); this.initializeBubbles(); this.animate(); } createCanvas() { const canvas = document.createElement('canvas'); canvas.style.cssText = ` position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 9999; background: transparent; `; canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); return canvas; } setupEventListeners() { document.addEventListener('mousemove', (e) => { this.mouseX = e.clientX; this.mouseY = e.clientY; }); document.addEventListener('mousedown', () => { this.isMousePressed = true; }); document.addEventListener('mouseup', () => { this.isMousePressed = false; }); document.addEventListener('click', (e) => { // Spawn liquid drops on click for (let i = 0; i < 8; i++) { physicsState.liquidDrops.push(new LiquidDrop(e.clientX, e.clientY)); } }); window.addEventListener('resize', () => { this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight; }); } initializeBubbles() { physicsState.bubbles = []; for (let i = 0; i < 20; i++) { physicsState.bubbles.push(new LiquidBubble()); } } spawnBubble(x, y, radius, color) { if (physicsState.bubbles.length < physicsState.maxBubbles) { physicsState.bubbles.push(new LiquidBubble(x, y, radius, color)); } } createExplosion(x, y) { for (let i = 0; i < 15; i++) { const angle = (i / 15) * Math.PI * 2; const radius = Math.random() * 20 + 10; const bubbleX = x + Math.cos(angle) * (Math.random() * 100 + 50); const bubbleY = y + Math.sin(angle) * (Math.random() * 100 + 50); this.spawnBubble(bubbleX, bubbleY, radius); } } applyEnvironment(env) { switch(env) { case 'water': physicsState.gravityStrength = 0.05; physicsState.viscosity = 0.98; physicsState.tension = 0.2; break; case 'space': physicsState.gravityStrength = 0; physicsState.viscosity = 1; physicsState.tension = 0.05; break; case 'lava': physicsState.gravityStrength = 0.15; physicsState.viscosity = 0.95; physicsState.tension = 0.3; break; case 'ice': physicsState.gravityStrength = 0.2; physicsState.viscosity = 0.99; physicsState.tension = 0.1; break; } this.updateUIValues(); } updateUIValues() { document.getElementById('gravity-display').textContent = physicsState.gravityStrength; document.getElementById('viscosity-display').textContent = physicsState.viscosity; document.getElementById('tension-display').textContent = physicsState.tension; document.getElementById('gravity-strength').value = physicsState.gravityStrength; document.getElementById('viscosity').value = physicsState.viscosity; document.getElementById('surface-tension').value = physicsState.tension; } updateStats() { document.getElementById('bubble-count').textContent = physicsState.bubbles.length; document.getElementById('drops-count').textContent = physicsState.liquidDrops.length; document.getElementById('interactions-count').textContent = this.interactionCount; } animate() { // Clear canvas with fade effect this.ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); // Update and count interactions this.interactionCount = 0; // Update bubbles physicsState.bubbles = physicsState.bubbles.filter(bubble => { const alive = bubble.update(physicsState.bubbles, this.mouseX, this.mouseY); if (alive) { bubble.draw(this.ctx); this.interactionCount += bubble.connections.length; } return alive; }); // Update liquid drops physicsState.liquidDrops = physicsState.liquidDrops.filter(drop => { const alive = drop.update(); if (alive) drop.draw(this.ctx); return alive; }); // Spawn bubbles during mouse press if (this.isMousePressed && Date.now() - this.lastBubbleSpawn > 200) { this.spawnBubble(this.mouseX, this.mouseY, Math.random() * 25 + 15); this.lastBubbleSpawn = Date.now(); } // Update stats this.updateStats(); requestAnimationFrame(() => this.animate()); } } // Initialize the system function init() { const panel = createPhysicsPanel(); const engine = new LiquidPhysicsEngine(); // Physics control event listeners document.getElementById('gravity-strength').oninput = (e) => { physicsState.gravityStrength = parseFloat(e.target.value); document.getElementById('gravity-display').textContent = e.target.value; }; document.getElementById('viscosity').oninput = (e) => { physicsState.viscosity = parseFloat(e.target.value); document.getElementById('viscosity-display').textContent = e.target.value; }; document.getElementById('surface-tension').oninput = (e) => { physicsState.tension = parseFloat(e.target.value); document.getElementById('tension-display').textContent = e.target.value; }; document.getElementById('interaction-radius').oninput = (e) => { physicsState.interactionRadius = parseInt(e.target.value); document.getElementById('radius-display').textContent = e.target.value; }; document.getElementById('max-bubbles').oninput = (e) => { physicsState.maxBubbles = parseInt(e.target.value); document.getElementById('bubbles-display').textContent = e.target.value; }; // Bubble controls document.getElementById('add-bubble').onclick = () => { engine.spawnBubble(Math.random() * window.innerWidth, Math.random() * window.innerHeight); }; document.getElementById('clear-bubbles').onclick = () => { physicsState.bubbles = []; physicsState.liquidDrops = []; }; document.getElementById('bubble-explosion').onclick = () => { engine.createExplosion(window.innerWidth / 2, window.innerHeight / 2); }; document.getElementById('rainbow-mode').onclick = () => { physicsState.bubbles.forEach(bubble => { bubble.color = `hsl(${Math.random() * 360}, 70%, 60%)`; }); }; // Special modes const toggleMode = (buttonId, stateKey) => { const button = document.getElementById(buttonId); button.onclick = () => { physicsState[stateKey] = !physicsState[stateKey]; button.classList.toggle('active', physicsState[stateKey]); }; }; toggleMode('magnetic-mode', 'magneticMode'); toggleMode('antigravity-mode', 'antigravityMode'); toggleMode('color-mixing', 'colorMixing'); toggleMode('trail-mode', 'trailMode'); // Environment presets document.querySelectorAll('.env-preset').forEach(button => { button.onclick = () => { engine.applyEnvironment(button.dataset.env); document.querySelectorAll('.env-preset').forEach(b => b.classList.remove('active')); button.classList.add('active'); }; }); // Welcome message setTimeout(() => { const welcome = document.createElement('div'); welcome.innerHTML = ` <div style=" position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 30px; border-radius: 20px; text-align: center; z-index: 10001; box-shadow: 0 25px 50px rgba(0,0,0,0.4); animation: liquidWelcome 6s ease-in-out forwards; "> <h2>🫧 Liquid Physics Lab Activated! 🫧</h2> <p>🖱️ Click and drag to create bubbles!</p> <p>🧲 Try magnetic mode for crazy interactions!</p> <p>🌊 Experiment with different environments!</p> <p>💥 Create bubble explosions and watch them mix!</p> </div> `; const welcomeStyle = document.createElement('style'); welcomeStyle.textContent = ` @keyframes liquidWelcome { 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.3) rotate(10deg); } 15% { opacity: 1; transform: translate(-50%, -50%) scale(1.05) rotate(-2deg); } 25% { transform: translate(-50%, -50%) scale(0.95) rotate(1deg); } 35% { transform: translate(-50%, -50%) scale(1.02) rotate(-0.5deg); } 45% { transform: translate(-50%, -50%) scale(1) rotate(0deg); } 80% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0deg); } 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.7) rotate(5deg); } } `; document.head.appendChild(welcomeStyle); document.body.appendChild(welcome); setTimeout(() => welcome.remove(), 6000); }, 2000); console.log('🫧 Liquid Physics Lab initialized!'); } // Start the liquid physics system if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();