您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Crea un juego de Snake totalmente funcional y optimizado para el canvas de Drawaria.online, con escenario de jardín y un panel arrastrable.
// ==UserScript== // @name Drawaria Snake Game // @namespace http://tampermonkey.net/ // @version 1.2 // @description Crea un juego de Snake totalmente funcional y optimizado para el canvas de Drawaria.online, con escenario de jardín y un panel arrastrable. // @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'; /* ---------- COMPONENTES COMPARTIDOS DEL SISTEMA ---------- */ let drawariaSocket = null; let drawariaCanvas = null; let drawariaCtx = null; // Cola de comandos optimizada con agrupamiento inteligente const commandQueue = []; let batchProcessor = null; const BATCH_SIZE = 8; const BATCH_INTERVAL = 60; // Intercepta WebSocket para capturar el socket del juego const originalWebSocketSend = WebSocket.prototype.send; WebSocket.prototype.send = function(...args) { if (!drawariaSocket && this.url && this.url.includes('drawaria')) { drawariaSocket = this; console.log('🔗 Drawaria WebSocket capturado para el juego de Snake.'); startBatchProcessor(); } return originalWebSocketSend.apply(this, args); }; function startBatchProcessor() { if (batchProcessor) return; batchProcessor = setInterval(() => { if (!drawariaSocket || drawariaSocket.readyState !== WebSocket.OPEN || commandQueue.length === 0) { return; } const batch = commandQueue.splice(0, BATCH_SIZE); batch.forEach(cmd => { try { drawariaSocket.send(cmd); } catch (e) { console.warn('⚠️ Fallo al enviar el comando:', e); } }); }, BATCH_INTERVAL); } /** * Función unificada para encolar comandos de dibujo. * Utiliza una línea muy corta con grosor negativo para dibujar formas rellenas. * @param {number} x1 - Coordenada X inicial * @param {number} y1 - Coordenada Y inicial * @param {number} x2 - Coordenada X final * @param {number} y2 - Coordenada Y final * @param {string} color - Color del objeto (ej. '#FFFFFF') * @param {number} thickness - Grosor efectivo (negativo para relleno) */ function enqueueDrawCommand(x1, y1, x2, y2, color, thickness) { if (!drawariaCanvas || !drawariaSocket) return; const normX1 = (x1 / drawariaCanvas.width).toFixed(4); const normY1 = (y1 / drawariaCanvas.height).toFixed(4); const normX2 = (x2 / drawariaCanvas.width).toFixed(4); const normY2 = (y2 / drawariaCanvas.height).toFixed(4); const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${-Math.abs(thickness)},"${color}",0,0,{}]]`; commandQueue.push(cmd); // Renderizado local para retroalimentación visual inmediata if (drawariaCtx) { drawariaCtx.strokeStyle = color; drawariaCtx.lineWidth = thickness; drawariaCtx.lineCap = 'round'; drawariaCtx.lineJoin = 'round'; drawariaCtx.beginPath(); drawariaCtx.moveTo(x1, y1); drawariaCtx.lineTo(x2, y2); drawariaCtx.stroke(); } } /* ---------- LÓGICA DEL JUEGO DE SNAKE ---------- */ class SnakeGame { constructor() { this.isActive = false; this.cellSize = 20; // Tamaño de cada segmento de la serpiente this.snake = []; this.food = {}; this.direction = 'right'; this.nextDirection = 'right'; this.score = 0; this.gameInterval = null; this.speed = 150; // Velocidad inicial en ms this.isGameOver = false; this.init(); } init() { const checkGameReady = () => { const gameCanvas = document.getElementById('canvas'); if (gameCanvas) { drawariaCanvas = gameCanvas; drawariaCtx = gameCanvas.getContext('2d'); this.createGamePanel(); console.log('✅ Juego de Snake inicializado.'); } else { setTimeout(checkGameReady, 100); } }; checkGameReady(); } createGamePanel() { const existingPanel = document.getElementById('snake-game-panel'); if (existingPanel) existingPanel.remove(); const panel = document.createElement('div'); panel.id = 'snake-game-panel'; panel.style.cssText = ` position: fixed !important; top: 250px !important; right: 20px !important; width: 250px !important; z-index: 2147483647 !important; background: linear-gradient(135deg, #2a2a3a, #1a1a2e) !important; border: 2px solid #5d5dff !important; border-radius: 12px !important; color: white !important; font-family: 'Segoe UI', Arial, sans-serif !important; box-shadow: 0 0 20px rgba(93, 93, 255, 0.3) !important; padding: 15px !important; text-align: center !important; `; panel.innerHTML = ` <h3 style="margin-top: 0; color: #5d5dff;">🐍 Snake Game</h3> <div style="margin-bottom: 10px;"> Score: <span id="snake-score">0</span> </div> <button id="toggle-game" style=" width: 100%; padding: 10px; background: #5d5dff; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: bold; ">▶️ Start Game</button> <div id="game-message" style=" margin-top: 10px; color: #ff4d4d; font-weight: bold; display: none; "></div> <div style=" margin-top: 15px; font-size: 10px; color: rgba(255,255,255,0.6); "> Use Arrow Keys to move.<br> Avoid walls and yourself! </div> `; document.body.appendChild(panel); this.setupEventListeners(); this.makePanelDraggable(panel); this.addDrawGardenButton(panel); } setupEventListeners() { document.getElementById('toggle-game').addEventListener('click', () => this.toggleGame()); document.addEventListener('keydown', (e) => this.handleKeyInput(e)); } toggleGame() { if (!this.isActive) { this.startGame(); document.getElementById('toggle-game').textContent = '⏸️ Pause Game'; document.getElementById('toggle-game').style.background = '#ffc107'; document.getElementById('game-message').style.display = 'none'; } else { this.pauseGame(); document.getElementById('toggle-game').textContent = '▶️ Resume Game'; document.getElementById('toggle-game').style.background = '#5d5dff'; } } startGame() { if (this.isActive) return; this.isActive = true; this.isGameOver = false; this.score = 0; this.direction = 'right'; this.nextDirection = 'right'; this.updateScoreDisplay(); this.resetSnake(); this.createFood(); this.gameLoop(); } pauseGame() { this.isActive = false; if (this.gameInterval) { clearInterval(this.gameInterval); this.gameInterval = null; } } endGame() { this.isGameOver = true; this.pauseGame(); document.getElementById('toggle-game').textContent = '🔄 Restart Game'; document.getElementById('toggle-game').style.background = '#cc0000'; const messageEl = document.getElementById('game-message'); messageEl.textContent = `GAME OVER! Score: ${this.score}`; messageEl.style.display = 'block'; console.log('💀 GAME OVER! Final Score:', this.score); } resetSnake() { this.snake = [ { x: 100, y: 100 }, { x: 80, y: 100 }, { x: 60, y: 100 } ]; } createFood() { const maxX = Math.floor(drawariaCanvas.width / this.cellSize) * this.cellSize; const maxY = Math.floor(drawariaCanvas.height / this.cellSize) * this.cellSize; this.food = { x: Math.floor(Math.random() * (maxX / this.cellSize)) * this.cellSize, y: Math.floor(Math.random() * (maxY / this.cellSize)) * this.cellSize }; } gameLoop() { if (!this.isActive || this.isGameOver) return; this.clearCanvas(); this.updateGame(); this.drawGame(); this.gameInterval = setTimeout(() => this.gameLoop(), this.speed); } updateGame() { const head = { x: this.snake[0].x, y: this.snake[0].y }; this.direction = this.nextDirection; if (this.direction === 'up') head.y -= this.cellSize; if (this.direction === 'down') head.y += this.cellSize; if (this.direction === 'left') head.x -= this.cellSize; if (this.direction === 'right') head.x += this.cellSize; this.snake.unshift(head); if (this.checkCollision(head)) { this.endGame(); return; } if (head.x === this.food.x && head.y === this.food.y) { this.score++; this.updateScoreDisplay(); this.createFood(); this.speed = Math.max(50, this.speed * 0.95); } else { this.snake.pop(); } } drawGame() { this.drawCell(this.food.x, this.food.y, '#FF4500'); // Naranja rojizo para la comida this.snake.forEach((segment, index) => { const color = index === 0 ? '#8BC34A' : '#8BC34A'; // Cabeza verde, cuerpo verde más claro this.drawCell(segment.x, segment.y, color); }); } drawCell(x, y, color) { enqueueDrawCommand(x, y, x + this.cellSize, y + this.cellSize, color, this.cellSize); } clearCanvas() { const oldTail = this.snake[this.snake.length - 1]; this.drawCell(oldTail.x, oldTail.y, '#4CAF50'); this.drawCell(this.food.x, this.food.y, '#4CAF50'); } checkCollision(head) { if (head.x < 0 || head.x >= drawariaCanvas.width || head.y < 0 || head.y >= drawariaCanvas.height) { return true; } for (let i = 1; i < this.snake.length; i++) { if (head.x === this.snake[i].x && head.y === this.snake[i].y) { return true; } } return false; } handleKeyInput(e) { const key = e.key; if (key === 'ArrowUp' && this.direction !== 'down') this.nextDirection = 'up'; if (key === 'ArrowDown' && this.direction !== 'up') this.nextDirection = 'down'; if (key === 'ArrowLeft' && this.direction !== 'right') this.nextDirection = 'left'; if (key === 'ArrowRight' && this.direction !== 'left') this.nextDirection = 'right'; } updateScoreDisplay() { const scoreDisplay = document.getElementById('snake-score'); if (scoreDisplay) scoreDisplay.textContent = this.score; } makePanelDraggable(panel) { let isDragging = false; let currentX; let currentY; let initialX; let initialY; let xOffset = 0; let yOffset = 0; const dragStart = (e) => { initialX = e.clientX - xOffset; initialY = e.clientY - yOffset; isDragging = true; panel.style.cursor = 'grabbing'; }; const dragEnd = () => { initialX = currentX; initialY = currentY; isDragging = false; panel.style.cursor = 'grab'; }; const drag = (e) => { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; xOffset = currentX; yOffset = currentY; panel.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`; } }; const header = panel.querySelector('h3'); if (header) { header.style.cursor = 'grab'; header.addEventListener("mousedown", dragStart); document.addEventListener("mouseup", dragEnd); document.addEventListener("mousemove", drag); } } addDrawGardenButton(panel) { const newButton = document.createElement('button'); newButton.id = 'draw-garden-btn'; newButton.textContent = '🖼️ Draw Garden'; newButton.style.cssText = ` width: 100%; padding: 10px; background: #27ae60; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: bold; margin-top: 10px; transition: background 0.3s ease; `; newButton.onmouseover = function() { this.style.background = '#219353'; }; newButton.onmouseout = function() { this.style.background = '#27ae60'; }; const toggleButton = document.getElementById('toggle-game'); panel.insertBefore(newButton, toggleButton.nextSibling); newButton.addEventListener('click', drawGardenScenario); } } // -------------------------------------------------------------------------------------------------- // --- LÓGICA DEL ESCENARIO DE JARDÍN --- // -------------------------------------------------------------------------------------------------- function drawGardenScenario() { if (!drawariaCanvas || !drawariaSocket) { console.log('Canvas or WebSocket not available.'); return; } // Borra todo el canvas con blanco enqueueDrawCommand(0, 0, drawariaCanvas.width, drawariaCanvas.height, '#FFFFFF', Math.max(drawariaCanvas.width, drawariaCanvas.height)); setTimeout(() => { const grassColor = '#4CAF50'; const flowerColors = ['#FFC107', '#E91E63', '#9C27B0', '#03A9F4']; const cellSize = 10; // Dibuja el fondo verde enqueueDrawCommand(0, 0, drawariaCanvas.width, drawariaCanvas.height, grassColor, Math.max(9999, 9999)); // Dibuja pequeños detalles para simular hierbas y flores for (let i = 0; i < 100; i++) { const x = Math.random() * drawariaCanvas.width; const y = Math.random() * drawariaCanvas.height; const color = flowerColors[Math.floor(Math.random() * flowerColors.length)]; // Dibuja un pequeño círculo (simula una flor) enqueueDrawCommand(x, y, x + 1, y + 1, color, 8); // Dibuja una mini-hierba (línea vertical) enqueueDrawCommand(x, y, x, y + 5, '#4CAF50', 3); } console.log('✅ Escenario de jardín dibujado con éxito.'); }, 200); } // -------------------------------------------------------------------------------------------------- // --- FIN DE CÓDIGO AÑADIDO --- // -------------------------------------------------------------------------------------------------- // Inicialización del juego const initSnakeGame = () => { const snakeGame = new SnakeGame(); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initSnakeGame); } else { setTimeout(initSnakeGame, 500); } })();