您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A highly ambitious, experimental Tampermonkey script to simulate a pilotable aircraft on Drawaria.online.
// ==UserScript== // @name Drawaria.online - Aircraft Script // @namespace http://tampermonkey.net/ // @version 1.0 // @description A highly ambitious, experimental Tampermonkey script to simulate a pilotable aircraft on Drawaria.online. // @author YouTubeDrawaria / Your AI Assistant // @match https://drawaria.online/* // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // --- Configuration --- const SCRIPT_ID = 'drawaria-aircraft-script'; const Z_INDEX_OVERLAY = 9999; // Ensure our canvas is on top // --- Game State --- const aircraft = { x: window.innerWidth / 2, y: window.innerHeight / 2, speed: 0, // Current forward speed maxSpeed: 8, acceleration: 0.1, deceleration: 0.05, turnSpeed: 0.05, // Radians per frame pitchAngle: 0, // Rotation around X-axis (up/down) rollAngle: 0, // Rotation around Z-axis (sideways tilt) yawAngle: 0, // Rotation around Y-axis (heading) maxPitchRoll: Math.PI / 4, // Max +/- 45 degrees enginePower: 0, // 0-1, affects sound fuel: 1000, maxFuel: 1000, altitude: 0, // Basic altitude simulation verticalSpeed: 0 // How fast altitude changes }; const controls = { forward: false, backward: false, turnLeft: false, turnRight: false, pitchUp: false, pitchDown: false, rollLeft: false, rollRight: false, engineUp: false, engineDown: false }; const particles = []; const MAX_PARTICLES = 100; // --- Audio Context & Generators --- let audioContext; let engineOscillator; let engineGain; function initAudio() { try { audioContext = new (window.AudioContext || window.webkitAudioContext)(); // Engine sound: Basic oscillator with gain controlled by enginePower engineOscillator = audioContext.createOscillator(); engineOscillator.type = 'sawtooth'; // A bit harsher, more like an engine engineOscillator.frequency.value = 50; // Base frequency engineGain = audioContext.createGain(); engineGain.gain.value = 0; // Start silent engineOscillator.connect(engineGain); engineGain.connect(audioContext.destination); engineOscillator.start(); // Background ambient sound (very subtle, procedural "wind") const noiseBuffer = audioContext.createBuffer(1, audioContext.sampleRate * 2, audioContext.sampleRate); const output = noiseBuffer.getChannelData(0); for (let i = 0; i < output.length; i++) { output[i] = Math.random() * 2 - 1; // White noise } const noiseSource = audioContext.createBufferSource(); noiseSource.buffer = noiseBuffer; noiseSource.loop = true; const ambientGain = audioContext.createGain(); ambientGain.gain.value = 0.01; // Very subtle noiseSource.connect(ambientGain); ambientGain.connect(audioContext.destination); noiseSource.start(); } catch (e) { console.warn(`[${SCRIPT_ID}] Web Audio API not supported or failed to initialize:`, e); } } // --- Canvas Setup --- let canvas, ctx; function setupCanvas() { canvas = document.createElement('canvas'); canvas.id = SCRIPT_ID + '-canvas'; canvas.style.position = 'fixed'; canvas.style.top = '0'; canvas.style.left = '0'; canvas.style.zIndex = Z_INDEX_OVERLAY; canvas.style.pointerEvents = 'none'; // Allow clicking through to Drawaria elements document.body.appendChild(canvas); ctx = canvas.getContext('2d'); resizeCanvas(); window.addEventListener('resize', resizeCanvas); } function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } // --- Drawing Functions --- // A utility to draw a glowing effect function applyGlow(color, blur) { ctx.shadowColor = color; ctx.shadowBlur = blur; } function clearGlow() { ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; } // Draws the aircraft model (simplified 2D representation) function drawAircraft() { ctx.save(); ctx.translate(aircraft.x, aircraft.y); // Apply yaw for overall heading ctx.rotate(aircraft.yawAngle); // Apply roll and pitch transformations // For a 2D projection, pitch affects Y-scale, roll affects X-scale/skew // This is a simplified projection for visual effect, not true 3D const scaleY = Math.cos(aircraft.pitchAngle); // Squish vertically for pitch const skewX = Math.sin(aircraft.rollAngle); // Skew horizontally for roll // Base aircraft body ctx.fillStyle = 'rgba(100, 100, 120, 0.9)'; // Dark grey ctx.strokeStyle = 'rgba(200, 200, 255, 0.8)'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(-40 * scaleY + 20 * skewX, 0); // Nose (adjusted for roll/pitch) ctx.lineTo(-20 * scaleY + 50 * skewX, -20); // Wing left front ctx.lineTo(20 * scaleY + 50 * skewX, -20); // Wing left back ctx.lineTo(40 * scaleY + 20 * skewX, 0); // Tail (body end) ctx.lineTo(20 * scaleY + 50 * skewX, 20); // Wing right back ctx.lineTo(-20 * scaleY + 50 * skewX, 20); // Wing right front ctx.closePath(); ctx.fill(); ctx.stroke(); // Cockpit (simulated transparency/reflection) ctx.fillStyle = 'rgba(150, 200, 255, 0.4)'; ctx.beginPath(); ctx.arc(0, 0, 10 * Math.abs(scaleY), 0, Math.PI * 2); ctx.fill(); applyGlow('rgba(150, 200, 255, 0.6)', 15); ctx.arc(0, 0, 10 * Math.abs(scaleY), 0, Math.PI * 2); // Redraw for glow ctx.fill(); clearGlow(); // Engine exhaust glow/particles if (aircraft.enginePower > 0.1) { applyGlow(`rgba(255, 150, 0, ${aircraft.enginePower * 0.8})`, aircraft.enginePower * 20 + 5); ctx.fillStyle = `rgba(255, 100, 0, ${aircraft.enginePower})`; ctx.beginPath(); ctx.arc(-30 * scaleY, 0, 5 + aircraft.enginePower * 5, 0, Math.PI * 2); ctx.fill(); clearGlow(); } // Propeller/Jet effect (simple spin) ctx.strokeStyle = 'white'; ctx.lineWidth = 1; const propLength = 15; const spinAngle = Date.now() * 0.05 * aircraft.enginePower * 10; for (let i = 0; i < 6; i++) { ctx.beginPath(); ctx.moveTo(-45 * scaleY, 0); ctx.lineTo(-45 * scaleY + propLength * Math.cos(spinAngle + i * Math.PI / 3), propLength * Math.sin(spinAngle + i * Math.PI / 3)); ctx.stroke(); } ctx.restore(); } // Draws the interactive UI elements function drawUI() { ctx.save(); // --- Info Panel --- ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; ctx.fillRect(10, 10, 200, 150); ctx.strokeStyle = '#00FF00'; ctx.lineWidth = 1; ctx.strokeRect(10, 10, 200, 150); ctx.font = '16px "Press Start 2P", monospace'; // A retro font if available, else monospace ctx.fillStyle = '#00FF00'; let textY = 30; const lineHeight = 20; ctx.fillText('FLIGHT DATA', 20, textY); textY += lineHeight; ctx.fillText(`Speed: ${aircraft.speed.toFixed(1)} km/h`, 20, textY); textY += lineHeight; ctx.fillText(`Altitude: ${aircraft.altitude.toFixed(0)} m`, 20, textY); textY += lineHeight; ctx.fillText(`Fuel: ${aircraft.fuel.toFixed(0)}/${aircraft.maxFuel}`, 20, textY); textY += lineHeight; ctx.fillText(`Engine: ${(aircraft.enginePower * 100).toFixed(0)}%`, 20, textY); textY += lineHeight; ctx.fillText(`Pitch: ${(aircraft.pitchAngle * 180 / Math.PI).toFixed(0)}°`, 20, textY); textY += lineHeight; ctx.fillText(`Roll: ${(aircraft.rollAngle * 180 / Math.PI).toFixed(0)}°`, 20, textY); // --- Controls Overlay (visual representation) --- const controlsPanelX = canvas.width - 210; const controlsPanelY = 10; ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; ctx.fillRect(controlsPanelX, controlsPanelY, 200, 250); ctx.strokeStyle = '#00FFFF'; ctx.strokeRect(controlsPanelX, controlsPanelY, 200, 250); ctx.fillStyle = '#00FFFF'; ctx.fillText('CONTROLS', controlsPanelX + 10, controlsPanelY + 20); const drawButton = (text, x, y, isPressed) => { const width = 80; const height = 25; ctx.fillStyle = isPressed ? '#00FF00' : 'rgba(50, 50, 50, 0.8)'; applyGlow(isPressed ? '#00FF00' : 'transparent', isPressed ? 10 : 0); ctx.fillRect(x, y, width, height); clearGlow(); ctx.strokeStyle = isPressed ? '#FFFFFF' : '#AAAAAA'; ctx.strokeRect(x, y, width, height); ctx.fillStyle = isPressed ? '#000000' : '#CCCCCC'; ctx.font = '14px "Press Start 2P", monospace'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(text, x + width / 2, y + height / 2); ctx.textAlign = 'left'; // Reset }; let btnX = controlsPanelX + 10; let btnY = controlsPanelY + 40; drawButton('W (Fwd)', btnX, btnY, controls.forward); drawButton('S (Bwd)', btnX + 90, btnY, controls.backward); btnY += 30; drawButton('A (Yaw L)', btnX, btnY, controls.turnLeft); drawButton('D (Yaw R)', btnX + 90, btnY, controls.turnRight); btnY += 30; drawButton('Up (Pitch D)', btnX, btnY, controls.pitchDown); // Up arrow means pitch down (nose down) drawButton('Down (Pitch U)', btnX + 90, btnY, controls.pitchUp); // Down arrow means pitch up (nose up) btnY += 30; drawButton('Left (Roll L)', btnX, btnY, controls.rollLeft); drawButton('Right (Roll R)', btnX + 90, btnY, controls.rollRight); btnY += 30; drawButton('+ (Eng Up)', btnX, btnY, controls.engineUp); drawButton('- (Eng Down)', btnX + 90, btnY, controls.engineDown); btnY += 30; ctx.fillStyle = '#FFF'; ctx.fillText('NUMPAD +/- for Engine', btnX, btnY); // --- Animated Compass/Horizon Line --- const compassX = canvas.width / 2; const compassY = canvas.height - 100; const compassRadius = 80; ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(compassX, compassY, compassRadius, 0, Math.PI * 2); ctx.stroke(); // Horizon line (relative to pitch and roll) ctx.save(); ctx.translate(compassX, compassY); ctx.rotate(-aircraft.rollAngle); // Rotate horizon opposite to roll ctx.translate(0, aircraft.pitchAngle * compassRadius * 2); // Shift horizon based on pitch ctx.strokeStyle = '#ADD8E6'; // Sky blue ctx.fillStyle = '#8B4513'; // Earth brown ctx.beginPath(); ctx.moveTo(-compassRadius * 2, 0); // Extend beyond compass for visual effect ctx.lineTo(compassRadius * 2, 0); ctx.stroke(); ctx.fillRect(-compassRadius * 2, 0, compassRadius * 4, compassRadius * 2); // Earth ctx.restore(); // Compass markings ctx.fillStyle = 'white'; ctx.font = '12px Arial'; const headingDeg = (aircraft.yawAngle * 180 / Math.PI + 360) % 360; for (let i = 0; i < 360; i += 45) { const angle = (i - headingDeg + 360) % 360; // Relative to current heading const rad = (angle - 90) * Math.PI / 180; // Adjust for canvas 0deg right const text = (i === 0 ? 'N' : i === 90 ? 'E' : i === 180 ? 'S' : i === 270 ? 'W' : i.toString()); const textX = compassX + Math.cos(rad) * (compassRadius - 20); const textY = compassY + Math.sin(rad) * (compassRadius - 20); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(text, textX, textY); } // Aircraft indicator on compass ctx.beginPath(); ctx.moveTo(compassX, compassY - compassRadius + 5); ctx.lineTo(compassX - 5, compassY - compassRadius + 15); ctx.lineTo(compassX + 5, compassY - compassRadius + 15); ctx.closePath(); ctx.fillStyle = 'red'; ctx.fill(); ctx.restore(); } // Draws particles (e.g., exhaust, engine trail) function drawParticles() { for (let i = particles.length - 1; i >= 0; i--) { const p = particles[i]; p.x += p.vx; p.y += p.vy; p.alpha -= p.fadeRate; p.size += p.growRate; if (p.alpha <= 0 || p.size >= 20) { particles.splice(i, 1); continue; } ctx.fillStyle = `rgba(${p.color.r}, ${p.color.g}, ${p.color.b}, ${p.alpha})`; ctx.beginPath(); ctx.arc(p.x, p.y, p.size / 2, 0, Math.PI * 2); ctx.fill(); // Simple glow for particles applyGlow(`rgba(${p.color.r}, ${p.color.g}, ${p.color.b}, ${p.alpha * 0.5})`, p.size); ctx.fill(); // Redraw for glow clearGlow(); } } function createParticle(x, y) { if (particles.length >= MAX_PARTICLES) return; const angle = aircraft.yawAngle + Math.PI; // Opposite direction of flight const speedFactor = aircraft.speed / aircraft.maxSpeed; particles.push({ x: x + Math.cos(angle) * 10, y: y + Math.sin(angle) * 10, vx: (Math.random() - 0.5) * 2 - Math.cos(angle) * (speedFactor * 2), vy: (Math.random() - 0.5) * 2 - Math.sin(angle) * (speedFactor * 2), alpha: 1, size: 3 + Math.random() * 3, fadeRate: 0.01 + Math.random() * 0.01, growRate: 0.1 + Math.random() * 0.1, color: { r: 255, g: 150 + Math.random() * 50, b: 0 } // Orange-red for exhaust }); } // --- Game Logic --- function updateGame() { // Engine power control if (controls.engineUp) { aircraft.enginePower = Math.min(1, aircraft.enginePower + 0.01); } else if (controls.engineDown) { aircraft.enginePower = Math.max(0, aircraft.enginePower - 0.01); } // Adjust engine sound if (audioContext && engineOscillator && engineGain) { engineOscillator.frequency.value = 50 + aircraft.enginePower * 200; // 50Hz to 250Hz engineGain.gain.value = aircraft.enginePower * 0.5; // 0 to 0.5 volume } // Speed calculation based on engine power, drag aircraft.speed += aircraft.acceleration * aircraft.enginePower; aircraft.speed -= aircraft.deceleration * (1 - aircraft.enginePower); // Natural deceleration aircraft.speed = Math.max(0, Math.min(aircraft.maxSpeed, aircraft.speed)); // Fuel consumption if (aircraft.enginePower > 0.05 && aircraft.fuel > 0) { aircraft.fuel -= 0.1 * aircraft.enginePower; if (aircraft.fuel <= 0) { aircraft.fuel = 0; aircraft.enginePower = 0; // Engine stalls aircraft.speed *= 0.9; // Rapid deceleration } } // Yaw (turn left/right) if (controls.turnLeft) { aircraft.yawAngle -= aircraft.turnSpeed * (aircraft.speed / aircraft.maxSpeed); } if (controls.turnRight) { aircraft.yawAngle += aircraft.turnSpeed * (aircraft.speed / aircraft.maxSpeed); } // Pitch (nose up/down) if (controls.pitchUp) { aircraft.pitchAngle = Math.min(aircraft.maxPitchRoll, aircraft.pitchAngle + aircraft.turnSpeed * 0.5); } else if (controls.pitchDown) { aircraft.pitchAngle = Math.max(-aircraft.maxPitchRoll, aircraft.pitchAngle - aircraft.turnSpeed * 0.5); } else { // Self-leveling pitch aircraft.pitchAngle *= 0.95; // Gradually return to level } // Roll (sideways tilt) if (controls.rollLeft) { aircraft.rollAngle = Math.max(-aircraft.maxPitchRoll, aircraft.rollAngle - aircraft.turnSpeed * 0.7); } else if (controls.rollRight) { aircraft.rollAngle = Math.min(aircraft.maxPitchRoll, aircraft.rollAngle + aircraft.turnSpeed * 0.7); } else { // Self-leveling roll aircraft.rollAngle *= 0.9; // Gradually return to level } // Update position based on yaw and speed aircraft.x += Math.cos(aircraft.yawAngle) * aircraft.speed; aircraft.y += Math.sin(aircraft.yawAngle) * aircraft.speed; // Altitude simulation (simple lift/gravity) const lift = aircraft.speed * Math.sin(-aircraft.pitchAngle) * 0.5; // Lift based on speed and pitch aircraft.verticalSpeed += lift * 0.1 - 0.05; // Gravity effect aircraft.altitude += aircraft.verticalSpeed; aircraft.altitude = Math.max(0, aircraft.altitude); // Can't go below 0 // Wrap around screen edges if (aircraft.x < 0) aircraft.x = canvas.width; if (aircraft.x > canvas.width) aircraft.x = 0; if (aircraft.y < 0) aircraft.y = canvas.height; if (aircraft.y > canvas.height) aircraft.y = 0; // Generate particles if engine is on if (aircraft.enginePower > 0.3 && Math.random() < aircraft.enginePower * 0.5) { // Particle origin: behind the aircraft, adjusted for yaw const particleOriginX = aircraft.x - Math.cos(aircraft.yawAngle) * 40; const particleOriginY = aircraft.y - Math.sin(aircraft.yawAngle) * 40; createParticle(particleOriginX, particleOriginY); } } // --- Input Handling --- function handleKeyDown(event) { switch (event.key) { case 'w': controls.forward = true; break; case 's': controls.backward = true; break; case 'a': controls.turnLeft = true; break; case 'd': controls.turnRight = true; break; case 'ArrowUp': controls.pitchDown = true; break; case 'ArrowDown': controls.pitchUp = true; break; case 'ArrowLeft': controls.rollLeft = true; break; case 'ArrowRight': controls.rollRight = true; break; case '+': case 'NumpadAdd': controls.engineUp = true; break; case '-': case 'NumpadSubtract': controls.engineDown = true; break; } // Prevent default browser actions for arrow keys etc. if (['w', 's', 'a', 'd', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', '+', '-', 'NumpadAdd', 'NumpadSubtract'].includes(event.key)) { event.preventDefault(); } } function handleKeyUp(event) { switch (event.key) { case 'w': controls.forward = false; break; case 's': controls.backward = false; break; case 'a': controls.turnLeft = false; break; case 'd': controls.turnRight = false; break; case 'ArrowUp': controls.pitchDown = false; break; case 'ArrowDown': controls.pitchUp = false; break; case 'ArrowLeft': controls.rollLeft = false; break; case 'ArrowRight': controls.rollRight = false; break; case '+': case 'NumpadAdd': controls.engineUp = false; break; case '-': case 'NumpadSubtract': controls.engineDown = false; break; } } // --- Main Game Loop --- function gameLoop() { updateGame(); ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear entire canvas drawAircraft(); drawParticles(); drawUI(); requestAnimationFrame(gameLoop); } // --- Initialization --- function init() { console.log(`[${SCRIPT_ID}] Initializing script...`); setupCanvas(); initAudio(); // Initialize audio context window.addEventListener('keydown', handleKeyDown); window.addEventListener('keyup', handleKeyUp); gameLoop(); // Start the game loop console.log(`[${SCRIPT_ID}] Script initialized. Use WASD, Arrow Keys, Numpad +/- to control the aircraft.`); } // Ensure the script runs after the page is loaded if (document.readyState === 'complete' || document.readyState === 'interactive') { init(); } else { window.addEventListener('DOMContentLoaded', init); } })();