Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FIFA 2D - Creado por Lionel Navarro</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Arial', sans-serif; } body { background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%); color: #fff; overflow: hidden; height: 100vh; display: flex; justify-content: center; align-items: center; } #game-container { width: 1200px; height: 700px; position: relative; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.8); border-radius: 10px; overflow: hidden; background: #000; } /* Pantallas */ .screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; padding: 20px; display: flex; flex-direction: column; justify-content: center; align-items: center; background: linear-gradient(to bottom, #0a0a0a, #1a1a1a); transition: transform 0.5s ease; z-index: 10; } .hidden { transform: translateX(-100%); z-index: 1; } /* Pantalla de título */ #title-screen { background: linear-gradient(rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.9)), url('https://images.unsplash.com/photo-1575361204480-aadea25e6e68?ixlib=rb-1.2.1&auto=format&fit=crop&w=1200&q=80'); background-size: cover; background-position: center; } .game-title { font-size: 5rem; text-align: center; margin-bottom: 10px; background: linear-gradient(to right, #00a8ff, #0097e6); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 5px 20px rgba(0, 168, 255, 0.5); font-weight: 900; letter-spacing: 3px; font-family: 'Impact', 'Arial Black', sans-serif; } .creator { font-size: 1.2rem; color: #999; margin-bottom: 50px; font-style: italic; } .menu-button { width: 350px; padding: 18px 30px; margin: 15px; font-size: 1.5rem; font-weight: bold; background: linear-gradient(to right, #00a8ff, #005a8c); color: white; border: none; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); text-align: center; position: relative; overflow: hidden; } .menu-button:hover:not(:disabled) { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 168, 255, 0.4); background: linear-gradient(to right, #0097e6, #004d73); } .menu-button:disabled { opacity: 0.5; cursor: not-allowed; background: #333; } .menu-button:active:not(:disabled) { transform: translateY(0); } .coming-soon { position: relative; } .coming-soon::after { content: "PRÓXIMAMENTE"; position: absolute; top: -10px; right: -10px; background: #e84118; color: white; font-size: 0.8rem; padding: 3px 8px; border-radius: 10px; font-weight: bold; } /* Pantalla de selección de modo */ .screen-title { font-size: 3.2rem; margin-bottom: 40px; text-align: center; color: #00a8ff; text-shadow: 0 3px 10px rgba(0, 168, 255, 0.5); } .modes-container { display: grid; grid-template-columns: repeat(2, 1fr); gap: 25px; width: 90%; max-width: 900px; margin-bottom: 40px; } .mode-button { padding: 25px 20px; background: rgba(255, 255, 255, 0.05); border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 10px; color: white; font-size: 1.5rem; font-weight: bold; cursor: pointer; transition: all 0.3s ease; display: flex; flex-direction: column; align-items: center; justify-content: center; backdrop-filter: blur(5px); } .mode-button:hover { background: rgba(0, 168, 255, 0.1); border-color: #00a8ff; transform: translateY(-5px); } .mode-button.selected { background: rgba(0, 168, 255, 0.2); border-color: #00a8ff; box-shadow: 0 5px 20px rgba(0, 168, 255, 0.3); } .mode-icon { font-size: 3rem; margin-bottom: 15px; } /* Pantalla de selección de competición */ .competitions-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; width: 90%; max-width: 1000px; height: 400px; overflow-y: auto; padding: 15px; background: rgba(0, 0, 0, 0.5); border-radius: 10px; margin-bottom: 30px; scrollbar-width: thin; scrollbar-color: #00a8ff #222; } .competitions-container::-webkit-scrollbar { width: 8px; } .competitions-container::-webkit-scrollbar-track { background: #222; border-radius: 10px; } .competitions-container::-webkit-scrollbar-thumb { background: #00a8ff; border-radius: 10px; } .competition-button { padding: 20px 15px; background: rgba(255, 255, 255, 0.05); border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 10px; color: white; font-size: 1.2rem; cursor: pointer; transition: all 0.3s ease; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } .competition-button:hover { background: rgba(0, 168, 255, 0.1); border-color: #00a8ff; transform: scale(1.05); } .competition-button.selected { background: rgba(0, 168, 255, 0.2); border-color: #00a8ff; } .competition-logo { width: 60px; height: 60px; background: rgba(255, 255, 255, 0.1); border-radius: 50%; margin-bottom: 10px; display: flex; align-items: center; justify-content: center; font-size: 2rem; } /* Pantalla de selección de equipo */ .teams-container { display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px; width: 95%; max-width: 1100px; height: 400px; overflow-y: auto; padding: 15px; background: rgba(0, 0, 0, 0.5); border-radius: 10px; margin-bottom: 30px; scrollbar-width: thin; scrollbar-color: #00a8ff #222; } .team-button { padding: 15px 10px; background: rgba(255, 255, 255, 0.05); border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 10px; color: white; font-size: 0.9rem; cursor: pointer; transition: all 0.3s ease; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } .team-button:hover { background: rgba(0, 168, 255, 0.1); border-color: #00a8ff; transform: scale(1.05); } .team-button.selected { background: rgba(0, 168, 255, 0.2); border-color: #00a8ff; } .team-logo { width: 50px; height: 50px; background: rgba(255, 255, 255, 0.1); border-radius: 50%; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; } /* Pantalla de selección de dificultad */ .difficulty-container { display: flex; flex-direction: column; gap: 20px; width: 80%; max-width: 700px; margin-bottom: 40px; } .difficulty-button { padding: 20px 30px; background: rgba(255, 255, 255, 0.05); border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 10px; color: white; font-size: 1.4rem; font-weight: bold; cursor: pointer; transition: all 0.3s ease; text-align: center; position: relative; overflow: hidden; } .difficulty-button:hover { background: rgba(0, 168, 255, 0.1); transform: translateY(-3px); } .difficulty-button.selected { background: rgba(0, 168, 255, 0.2); border-color: #00a8ff; } .difficulty-very-easy { border-left: 8px solid #4CAF50; } .difficulty-easy { border-left: 8px solid #8BC34A; } .difficulty-normal { border-left: 8px solid #FFC107; } .difficulty-hard { border-left: 8px solid #FF9800; } .difficulty-extreme { border-left: 8px solid #F44336; } /* Pantalla de juego */ #game-screen { padding: 0; background: #2a623d; z-index: 5; } #canvas-container { width: 100%; height: 100%; position: relative; } canvas { display: block; width: 100%; height: 100%; } /* HUD del juego */ .game-hud { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10; } .scoreboard { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; background: rgba(0, 0, 0, 0.85); padding: 10px 40px; border-radius: 15px; font-size: 2.2rem; font-weight: bold; min-width: 300px; justify-content: center; border: 3px solid rgba(255, 255, 255, 0.2); box-shadow: 0 5px 20px rgba(0, 0, 0, 0.7); } .scoreboard.libertadores { border-color: #FFD700; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(139, 0, 0, 0.7)); } .scoreboard.sudamericana { border-color: #00a8ff; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(0, 50, 160, 0.7)); } .scoreboard.champions { border-color: #00a8ff; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(0, 20, 100, 0.7)); } .scoreboard.mundial { border-color: #F44336; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(200, 0, 0, 0.7)); } .scoreboard.copa-america { border-color: #00a8ff; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(0, 100, 200, 0.7)); } .scoreboard.eurocopa { border-color: #FFD700; background: linear-gradient(to right, rgba(0, 0, 0, 0.9), rgba(255, 215, 0, 0.2)); } .team-score { padding: 0 20px; font-size: 2.8rem; text-shadow: 0 0 10px currentColor; } .player-score { color: #00a8ff; } .cpu-score { color: #e84118; } .score-separator { color: #fff; font-size: 2.5rem; margin: 0 10px; } .team-name-hud { position: absolute; top: 90px; font-size: 1.4rem; font-weight: bold; background: rgba(0, 0, 0, 0.7); padding: 8px 20px; border-radius: 8px; border: 2px solid rgba(255, 255, 255, 0.2); } .team-name-hud.player { left: 30px; color: #00a8ff; border-color: #00a8ff; } .team-name-hud.cpu { right: 30px; color: #e84118; border-color: #e84118; } .game-time { position: absolute; top: 25px; right: 30px; background: rgba(0, 0, 0, 0.8); padding: 10px 20px; border-radius: 8px; font-size: 1.5rem; font-weight: bold; border: 2px solid rgba(255, 255, 255, 0.2); } .controls-info { position: absolute; bottom: 25px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.8); padding: 12px 25px; border-radius: 10px; font-size: 1.1rem; text-align: center; border: 2px solid rgba(255, 255, 255, 0.1); } .key { display: inline-block; background: rgba(0, 168, 255, 0.3); padding: 5px 12px; border-radius: 5px; margin: 0 5px; font-weight: bold; border: 1px solid rgba(0, 168, 255, 0.5); } /* Panel de mensajes */ .message-panel { position: absolute; bottom: 100px; left: 50%; transform: translateX(-50%); width: 70%; max-width: 700px; background: rgba(0, 0, 0, 0.9); padding: 15px; border-radius: 10px; font-size: 1.2rem; text-align: center; min-height: 60px; display: flex; align-items: center; justify-content: center; border-left: 5px solid #00a8ff; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.7); } /* Animaciones */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes goalAnimation { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } @keyframes passAnimation { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } @keyframes shotAnimation { 0% { transform: scale(1); } 50% { transform: scale(1.3); } 100% { transform: scale(1); } } .pulse { animation: pulse 0.5s ease; } .goal-animation { animation: goalAnimation 0.8s ease; } .pass-animation { animation: passAnimation 0.3s ease; } .shot-animation { animation: shotAnimation 0.4s ease; } /* Botones de navegación */ .nav-buttons { display: flex; gap: 25px; margin-top: 20px; } .nav-button { padding: 15px 30px; background: rgba(255, 255, 255, 0.1); border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 10px; color: white; font-size: 1.2rem; font-weight: bold; cursor: pointer; transition: all 0.3s ease; } .nav-button:hover { background: rgba(255, 255, 255, 0.2); } .nav-button.primary { background: linear-gradient(to right, #00a8ff, #005a8c); } .back-button { position: absolute; top: 20px; left: 20px; padding: 12px 25px; background: rgba(255, 255, 255, 0.1); border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 10px; color: white; font-size: 1rem; cursor: pointer; transition: all 0.3s ease; z-index: 20; } .back-button:hover { background: rgba(255, 255, 255, 0.2); } /* Responsive */ @media (max-width: 1250px) { #game-container { width: 1000px; height: 600px; } .teams-container { grid-template-columns: repeat(4, 1fr); } } @media (max-width: 1050px) { #game-container { width: 900px; height: 550px; } .game-title { font-size: 4rem; } .teams-container { grid-template-columns: repeat(3, 1fr); } .competitions-container { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 950px) { #game-container { width: 100%; height: 100%; border-radius: 0; } } </style> </head> <body> <div id="game-container"> <!-- Pantalla de título --> <div id="title-screen" class="screen"> <h1 class="game-title">FIFA 2D</h1> <p class="creator">Creado por Lionel Navarro</p> <button id="friendly-match" class="menu-button">Partido Amistoso</button> <button id="cups-mode" class="menu-button">Copas</button> <button id="career-mode" class="menu-button coming-soon" disabled>Modo Carrera</button> <button id="exit-game" class="menu-button">Salir del Juego</button> </div> <!-- Pantalla de selección de modo --> <div id="mode-screen" class="screen hidden"> <h2 class="screen-title">Selecciona un Modo</h2> <div class="modes-container" id="modes-container"> <!-- Los modos se generarán con JavaScript --> </div> <div class="nav-buttons"> <button id="back-from-mode" class="nav-button">Volver</button> <button id="select-mode" class="nav-button primary" disabled>Seleccionar</button> </div> </div> <!-- Pantalla de selección de competición --> <div id="competition-screen" class="screen hidden"> <h2 class="screen-title" id="competition-title">Selecciona una Competición</h2> <div class="competitions-container" id="competitions-container"> <!-- Las competiciones se generarán con JavaScript --> </div> <div class="nav-buttons"> <button id="back-from-competition" class="nav-button">Volver</button> <button id="select-competition" class="nav-button primary" disabled>Seleccionar</button> </div> </div> <!-- Pantalla de selección de equipo --> <div id="team-screen" class="screen hidden"> <h2 class="screen-title" id="team-selection-title">Selecciona tu Equipo</h2> <div class="teams-container" id="teams-container"> <!-- Los equipos se generarán con JavaScript --> </div> <div class="nav-buttons"> <button id="back-from-team" class="nav-button">Volver</button> <button id="select-team" class="nav-button primary" disabled>Seleccionar Equipo</button> </div> </div> <!-- Pantalla de selección de equipo rival --> <div id="opponent-screen" class="screen hidden"> <h2 class="screen-title" id="opponent-selection-title">Selecciona el Equipo Rival</h2> <div class="teams-container" id="opponent-teams-container"> <!-- Los equipos rivales se generarán con JavaScript --> </div> <div class="nav-buttons"> <button id="back-from-opponent" class="nav-button">Volver</button> <button id="select-opponent" class="nav-button primary" disabled>Seleccionar Rival</button> </div> </div> <!-- Pantalla de selección de dificultad --> <div id="difficulty-screen" class="screen hidden"> <h2 class="screen-title">Selecciona la Dificultad</h2> <div class="difficulty-container" id="difficulty-container"> <!-- Las dificultades se generarán con JavaScript --> </div> <div class="nav-buttons"> <button id="back-from-difficulty" class="nav-button">Volver</button> <button id="start-game" class="nav-button primary" disabled>Comenzar Partido</button> </div> </div> <!-- Pantalla de juego --> <div id="game-screen" class="screen hidden"> <button id="back-from-game" class="back-button">Menú Principal</button> <div id="canvas-container"> <canvas id="game-canvas"></canvas> <div class="game-hud"> <div class="scoreboard" id="scoreboard"> <div class="team-score player-score" id="player-score">0</div> <div class="score-separator">-</div> <div class="team-score cpu-score" id="cpu-score">0</div> </div> <div class="team-name-hud player" id="player-team-name">Jugador</div> <div class="team-name-hud cpu" id="cpu-team-name">CPU</div> <div class="game-time" id="game-time">00:00</div> <div class="controls-info"> <span>PASE: <span class="key">ESPACIO (rápido)</span></span> | <span>CHUTAR: <span class="key">ESPACIO (mantener)</span></span> | <span>MOVIMIENTO: <span class="key">W A S D</span></span> </div> <div class="message-panel" id="message-panel"> <div id="message-text">¡Comienza el partido!</div> </div> </div> </div> </div> </div> <script> // Datos del juego const gameData = { modes: { 'amistoso': { name: 'Partido Amistoso', icon: '⚽', competitions: ['amistoso'] }, 'copas': { name: 'Copas', icon: '🏆', competitions: ['libertadores', 'sudamericana', 'champions', 'mundial', 'copa-america', 'eurocopa'] } }, competitions: { 'amistoso': { name: 'Partido Amistoso', icon: '⚽', color: '#00a8ff', teams: { 'española': { name: 'LaLiga Española', teams: [ 'Real Madrid', 'Barcelona', 'Atlético Madrid', 'Sevilla', 'Real Sociedad', 'Betis', 'Villarreal', 'Athletic Club', 'Valencia', 'Osasuna', 'Celta Vigo', 'Mallorca', 'Rayo Vallecano', 'Girona', 'Getafe', 'Almería' ] }, 'premier': { name: 'Premier League', teams: [ 'Manchester City', 'Arsenal', 'Manchester United', 'Liverpool', 'Chelsea', 'Tottenham', 'Newcastle', 'Aston Villa', 'Brighton', 'West Ham', 'Brentford', 'Crystal Palace', 'Everton', 'Leicester', 'Leeds', 'Southampton' ] }, 'francesa': { name: 'Ligue 1', teams: [ 'PSG', 'Marsella', 'Mónaco', 'Lyon', 'Lille', 'Rennes', 'Niza', 'Lens', 'Montpellier', 'Toulouse', 'Strasbourg', 'Nantes', 'Reims', 'Ajaccio', 'Auxerre', 'Troyes' ] }, 'alemana': { name: 'Bundesliga', teams: [ 'Bayern Munich', 'Borussia Dortmund', 'RB Leipzig', 'Bayer Leverkusen', 'Union Berlin', 'Freiburg', 'Wolfsburg', 'Eintracht Frankfurt', 'Mainz', 'Borussia Mönchengladbach', 'Köln', 'Hoffenheim', 'Werder Bremen', 'Schalke 04', 'Augsburg', 'Stuttgart' ] }, 'italiana': { name: 'Serie A', teams: [ 'Juventus', 'Inter Milan', 'AC Milan', 'Napoli', 'Roma', 'Lazio', 'Atalanta', 'Fiorentina', 'Bologna', 'Torino', 'Udinese', 'Sassuolo', 'Empoli', 'Salernitana', 'Lecce', 'Spezia' ] }, 'argentina': { name: 'Torneo Betano 2025', teams: [ 'Racing Club', 'River Plate', 'Boca Juniors', 'San Lorenzo', 'Independiente', 'Estudiantes', 'Newells', 'Rosario Central', 'Lanús', 'Vélez Sarsfield', 'Talleres', 'Godoy Cruz', 'Argentinos Juniors', 'Banfield', 'Defensa y Justicia', 'Colón', 'Racing de Córdoba', 'Huracán', 'Central Córdoba', 'Gimnasia LP', 'Arsenal', 'Patronato', 'Sarmiento', 'Unión', 'Atl. Tucumán', 'Platense', 'Barracas Central', 'Tigre', 'Instituto', 'Belgrano' ] }, 'brasileña': { name: 'Brasileirão', teams: [ 'Flamengo', 'Palmeiras', 'Corinthians', 'São Paulo', 'Santos', 'Grêmio', 'Internacional', 'Atlético Mineiro', 'Cruzeiro', 'Fluminense', 'Botafogo', 'Vasco da Gama', 'Bahia', 'Sport Recife', 'Fortaleza', 'Ceará' ] }, 'especial': { name: 'Equipo Especial', teams: ['Equipo Especial'] } } }, 'libertadores': { name: 'Copa Libertadores', icon: '🏆', color: '#FFD700', teams: [ 'River Plate', 'Boca Juniors', 'Flamengo', 'Palmeiras', 'Atlético Mineiro', 'Corinthians', 'Nacional (URU)', 'Peñarol', 'Olimpia (PAR)', 'Cerro Porteño', 'Independiente del Valle', 'LDU Quito', 'Universidad de Chile', 'Colo-Colo', 'Atlético Nacional', 'Millonarios' ] }, 'sudamericana': { name: 'Copa Sudamericana', icon: '🌎', color: '#00a8ff', teams: [ 'Racing Club', 'San Lorenzo', 'Internacional', 'São Paulo', 'Athletico Paranaense', 'Emelec', 'Blooming', 'The Strongest', 'Deportivo Cali', 'Junior', 'Always Ready', 'Guaraní', 'Universitario', 'Sport Huancayo', 'Deportivo Lara', 'Metropolitano' ] }, 'champions': { name: 'Champions League', icon: '⭐', color: '#00a8ff', teams: [ 'Real Madrid', 'Barcelona', 'Manchester City', 'Liverpool', 'Bayern Munich', 'PSG', 'Chelsea', 'AC Milan', 'Inter Milan', 'Juventus', 'Borussia Dortmund', 'Atlético Madrid', 'Benfica', 'Porto', 'Ajax', 'RB Leipzig' ] }, 'mundial': { name: 'Mundial de Selecciones', icon: '🌍', color: '#F44336', teams: [ 'Argentina', 'Brasil', 'Francia', 'Alemania', 'España', 'Inglaterra', 'Italia', 'Portugal', 'Países Bajos', 'Bélgica', 'Croacia', 'Uruguay', 'México', 'Estados Unidos', 'Japón', 'Senegal' ] }, 'copa-america': { name: 'Copa América', icon: '🇦🇷', color: '#00a8ff', teams: [ 'Argentina', 'Brasil', 'Uruguay', 'Colombia', 'Chile', 'Perú', 'Paraguay', 'Ecuador', 'Venezuela', 'Bolivia', 'Costa Rica', 'México', 'Estados Unidos', 'Canadá', 'Jamaica', 'Panamá' ] }, 'eurocopa': { name: 'Eurocopa', icon: '🇪🇺', color: '#FFD700', teams: [ 'Francia', 'Alemania', 'España', 'Inglaterra', 'Italia', 'Portugal', 'Países Bajos', 'Bélgica', 'Croacia', 'Dinamarca', 'Suiza', 'Polonia', 'Suecia', 'Gales', 'Ucrania', 'Austria' ] } }, difficulties: [ { id: 'very-easy', name: 'Muy Fácil', color: '#4CAF50', speed: 0.7, aiDelay: 1000, aiAccuracy: 0.3 }, { id: 'easy', name: 'Fácil', color: '#8BC34A', speed: 0.9, aiDelay: 700, aiAccuracy: 0.5 }, { id: 'normal', name: 'Normal', color: '#FFC107', speed: 1.0, aiDelay: 500, aiAccuracy: 0.7 }, { id: 'hard', name: 'Difícil', color: '#FF9800', speed: 1.2, aiDelay: 300, aiAccuracy: 0.8 }, { id: 'extreme', name: 'Extremo', color: '#F44336', speed: 1.5, aiDelay: 150, aiAccuracy: 0.9 } ], selectedMode: null, selectedCompetition: null, selectedLeague: null, selectedTeam: null, selectedOpponent: null, selectedDifficulty: null, gameState: 'menu', score: { player: 0, cpu: 0 }, matchTime: 0, maxMatchTime: 300, messages: [ "¡Comienza el partido!", "El balón está en juego", "Qué jugada más interesante", "Se avecina una oportunidad de gol", "El portero está atento", "¡Cuidado con el contraataque!", "La defensa se mantiene firme", "El mediocampo controla el ritmo", "¡Qué pase tan preciso!", "La afición está vibrante", "Falta en una zona peligrosa", "¡Otra oportunidad desaprovechada!", "El entrenador da instrucciones", "Cambio de ritmo en el juego", "¡GOLAZO! ¡Increíble!", "El árbitro señala falta", "Tiempo de descuento", "El partido está muy parejo", "La posesión es clave en este encuentro", "¡Qué remate! Por poco y entra" ], specialTeamPlayers: { goalkeeper: { name: "Fran Burela", number: 1 }, defenders: [ { name: "Masma", number: 4 }, { name: "Benja Perez", number: 5 } ], forwards: [ { name: "Lio", number: 10 }, { name: "Chochi", number: 7 } ] } }; // Elementos del DOM const screens = { title: document.getElementById('title-screen'), mode: document.getElementById('mode-screen'), competition: document.getElementById('competition-screen'), team: document.getElementById('team-screen'), opponent: document.getElementById('opponent-screen'), difficulty: document.getElementById('difficulty-screen'), game: document.getElementById('game-screen') }; // Variables del juego let canvas, ctx; let gameLoopId; let keys = {}; let playerTeam = []; let cpuTeam = []; let ball = {}; let activePlayer = null; let lastMessageTime = 0; let messageInterval = 5000; let lastAIAction = 0; let aiActionDelay = 500; let gameActive = false; let animationTimer = 0; let celebrationTimer = 0; let isCelebrating = false; let celebratingTeam = null; let corners = 0; let freeKicks = 0; let lastGoalBy = null; let goalScorer = null; let ballTrail = []; // Inicialización del juego document.addEventListener('DOMContentLoaded', () => { initEventListeners(); renderModes(); renderDifficulties(); }); // Inicializar event listeners function initEventListeners() { // Botones de navegación document.getElementById('friendly-match').addEventListener('click', () => { gameData.selectedMode = 'amistoso'; showScreen('mode'); }); document.getElementById('cups-mode').addEventListener('click', () => { gameData.selectedMode = 'copas'; showScreen('mode'); }); document.getElementById('exit-game').addEventListener('click', () => { alert('¡Gracias por jugar FIFA 2D!'); }); // Navegación entre pantallas document.getElementById('back-from-mode').addEventListener('click', () => showScreen('title')); document.getElementById('select-mode').addEventListener('click', () => showScreen('competition')); document.getElementById('back-from-competition').addEventListener('click', () => showScreen('mode')); document.getElementById('select-competition').addEventListener('click', selectCompetition); document.getElementById('back-from-team').addEventListener('click', () => { if (gameData.selectedMode === 'amistoso' && gameData.selectedCompetition === 'amistoso') { showScreen('competition'); } else { showScreen('competition'); } }); document.getElementById('select-team').addEventListener('click', () => showScreen('opponent')); document.getElementById('back-from-opponent').addEventListener('click', () => showScreen('team')); document.getElementById('select-opponent').addEventListener('click', () => showScreen('difficulty')); document.getElementById('back-from-difficulty').addEventListener('click', () => showScreen('opponent')); document.getElementById('start-game').addEventListener('click', startGame); document.getElementById('back-from-game').addEventListener('click', () => { stopGame(); showScreen('title'); resetGameData(); }); // Controles de teclado document.addEventListener('keydown', (e) => { const key = e.key.toLowerCase(); keys[key] = true; // Espacio para pase/chute if (key === ' ' && gameActive && !isCelebrating) { e.preventDefault(); if (!ball.spacePressed) { ball.spacePressed = true; ball.spacePressTime = Date.now(); ball.spaceStartX = ball.x; ball.spaceStartY = ball.y; } } // Pausa con P if (key === 'p' && gameActive) { togglePause(); } }); document.addEventListener('keyup', (e) => { const key = e.key.toLowerCase(); keys[key] = false; // Espacio liberado if (key === ' ' && gameActive && !isCelebrating) { if (ball.spacePressed) { const pressDuration = Date.now() - ball.spacePressTime; // Si fue un tap rápido (menos de 200ms) es un pase if (pressDuration < 200) { passBall(); } else { // Si fue más largo, es un chute shootBall(pressDuration); } ball.spacePressed = false; ball.spacePressTime = 0; } } }); } // Renderizar modos function renderModes() { const container = document.getElementById('modes-container'); container.innerHTML = ''; Object.keys(gameData.modes).forEach(modeId => { const mode = gameData.modes[modeId]; const button = document.createElement('button'); button.className = 'mode-button'; button.innerHTML = ` <div class="mode-icon">${mode.icon}</div> <div>${mode.name}</div> `; button.addEventListener('click', () => { document.querySelectorAll('.mode-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedMode = modeId; document.getElementById('select-mode').disabled = false; // Renderizar competiciones para este modo renderCompetitions(); }); container.appendChild(button); }); } // Renderizar competiciones function renderCompetitions() { const container = document.getElementById('competitions-container'); container.innerHTML = ''; if (!gameData.selectedMode) return; const mode = gameData.modes[gameData.selectedMode]; mode.competitions.forEach(compId => { const comp = gameData.competitions[compId]; const button = document.createElement('button'); button.className = 'competition-button'; button.innerHTML = ` <div class="competition-logo">${comp.icon}</div> <div>${comp.name}</div> `; button.addEventListener('click', () => { document.querySelectorAll('.competition-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedCompetition = compId; document.getElementById('select-competition').disabled = false; }); container.appendChild(button); }); // Actualizar título document.getElementById('competition-title').textContent = `Selecciona una Competición - ${mode.name}`; } // Seleccionar competición function selectCompetition() { if (gameData.selectedCompetition === 'amistoso') { // Para amistoso, mostrar pantalla de selección de liga renderLeaguesForAmistoso(); showScreen('team'); } else { // Para copas, mostrar equipos directamente renderTeamsForCompetition(); showScreen('team'); } } // Renderizar ligas para amistoso function renderLeaguesForAmistoso() { const container = document.getElementById('teams-container'); container.innerHTML = ''; document.getElementById('team-selection-title').textContent = 'Selecciona una Liga'; Object.keys(gameData.competitions.amistoso.teams).forEach(leagueId => { const league = gameData.competitions.amistoso.teams[leagueId]; const button = document.createElement('button'); button.className = 'team-button'; button.innerHTML = ` <div class="team-logo">${league.name.charAt(0)}</div> <div>${league.name}</div> `; button.addEventListener('click', () => { document.querySelectorAll('#teams-container .team-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedLeague = leagueId; document.getElementById('select-team').disabled = false; // Renderizar equipos de esta liga renderTeamsFromLeague(); }); container.appendChild(button); }); } // Renderizar equipos desde liga seleccionada function renderTeamsFromLeague() { const container = document.getElementById('teams-container'); container.innerHTML = ''; document.getElementById('team-selection-title').textContent = `Selecciona tu Equipo - ${gameData.competitions.amistoso.teams[gameData.selectedLeague].name}`; const league = gameData.competitions.amistoso.teams[gameData.selectedLeague]; league.teams.forEach(team => { const button = document.createElement('button'); button.className = 'team-button'; button.innerHTML = ` <div class="team-logo">${team.charAt(0)}</div> <div>${team}</div> `; button.addEventListener('click', () => { document.querySelectorAll('#teams-container .team-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedTeam = team; document.getElementById('select-team').disabled = false; // Renderizar oponentes renderOpponentsFromLeague(); }); container.appendChild(button); }); } // Renderizar equipos para competición function renderTeamsForCompetition() { const container = document.getElementById('teams-container'); container.innerHTML = ''; document.getElementById('team-selection-title').textContent = `Selecciona tu Equipo - ${gameData.competitions[gameData.selectedCompetition].name}`; const competition = gameData.competitions[gameData.selectedCompetition]; competition.teams.forEach(team => { const button = document.createElement('button'); button.className = 'team-button'; button.innerHTML = ` <div class="team-logo">${team.charAt(0)}</div> <div>${team}</div> `; button.addEventListener('click', () => { document.querySelectorAll('#teams-container .team-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedTeam = team; document.getElementById('select-team').disabled = false; // Renderizar oponentes renderOpponentsForCompetition(); }); container.appendChild(button); }); } // Renderizar oponentes desde liga function renderOpponentsFromLeague() { const container = document.getElementById('opponent-teams-container'); container.innerHTML = ''; document.getElementById('opponent-selection-title').textContent = `Selecciona Rival - ${gameData.selectedTeam}`; const league = gameData.competitions.amistoso.teams[gameData.selectedLeague]; league.teams.forEach(team => { if (team === gameData.selectedTeam) return; const button = document.createElement('button'); button.className = 'team-button'; button.innerHTML = ` <div class="team-logo">${team.charAt(0)}</div> <div>${team}</div> `; button.addEventListener('click', () => { document.querySelectorAll('#opponent-teams-container .team-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedOpponent = team; document.getElementById('select-opponent').disabled = false; }); container.appendChild(button); }); } // Renderizar oponentes para competición function renderOpponentsForCompetition() { const container = document.getElementById('opponent-teams-container'); container.innerHTML = ''; document.getElementById('opponent-selection-title').textContent = `Selecciona Rival - ${gameData.selectedTeam}`; const competition = gameData.competitions[gameData.selectedCompetition]; competition.teams.forEach(team => { if (team === gameData.selectedTeam) return; const button = document.createElement('button'); button.className = 'team-button'; button.innerHTML = ` <div class="team-logo">${team.charAt(0)}</div> <div>${team}</div> `; button.addEventListener('click', () => { document.querySelectorAll('#opponent-teams-container .team-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedOpponent = team; document.getElementById('select-opponent').disabled = false; }); container.appendChild(button); }); } // Renderizar dificultades function renderDifficulties() { const container = document.getElementById('difficulty-container'); container.innerHTML = ''; gameData.difficulties.forEach(diff => { const button = document.createElement('button'); button.className = `difficulty-button difficulty-${diff.id}`; button.textContent = diff.name; button.addEventListener('click', () => { document.querySelectorAll('.difficulty-button').forEach(btn => btn.classList.remove('selected')); button.classList.add('selected'); gameData.selectedDifficulty = diff; document.getElementById('start-game').disabled = false; }); container.appendChild(button); }); } // Mostrar pantalla específica function showScreen(screenName) { Object.values(screens).forEach(screen => { screen.classList.add('hidden'); }); screens[screenName].classList.remove('hidden'); // Configuraciones específicas para la pantalla de juego if (screenName === 'game') { document.getElementById('player-team-name').textContent = gameData.selectedTeam; document.getElementById('cpu-team-name').textContent = gameData.selectedOpponent; // Configurar color del marcador según la competición const scoreboard = document.getElementById('scoreboard'); scoreboard.className = 'scoreboard'; if (gameData.selectedCompetition && gameData.selectedCompetition !== 'amistoso') { scoreboard.classList.add(gameData.selectedCompetition); } } } // Iniciar el juego function startGame() { showScreen('game'); initCanvas(); initGameObjects(); gameActive = true; gameData.gameState = 'playing'; gameData.matchTime = 0; gameData.score = { player: 0, cpu: 0 }; updateScoreboard(); updateMessage("¡Comienza el partido!"); gameLoopId = requestAnimationFrame(gameLoop); } // Detener el juego function stopGame() { gameActive = false; if (gameLoopId) { cancelAnimationFrame(gameLoopId); } } // Pausar/reanudar juego function togglePause() { if (gameData.gameState === 'playing') { gameData.gameState = 'paused'; updateMessage("Partido en pausa"); } else if (gameData.gameState === 'paused') { gameData.gameState = 'playing'; updateMessage("El partido se reanuda"); gameLoopId = requestAnimationFrame(gameLoop); } } // Reiniciar datos del juego function resetGameData() { gameData.selectedMode = null; gameData.selectedCompetition = null; gameData.selectedLeague = null; gameData.selectedTeam = null; gameData.selectedOpponent = null; gameData.selectedDifficulty = null; document.getElementById('select-mode').disabled = true; document.getElementById('select-competition').disabled = true; document.getElementById('select-team').disabled = true; document.getElementById('select-opponent').disabled = true; document.getElementById('start-game').disabled = true; document.querySelectorAll('.selected').forEach(el => el.classList.remove('selected')); } // Inicializar canvas function initCanvas() { canvas = document.getElementById('game-canvas'); ctx = canvas.getContext('2d'); canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; } // Inicializar objetos del juego function initGameObjects() { const fieldWidth = canvas.width; const fieldHeight = canvas.height; const centerX = fieldWidth / 2; const centerY = fieldHeight / 2; // Limpiar equipos playerTeam = []; cpuTeam = []; // Crear equipo especial si está seleccionado const isSpecialTeam = gameData.selectedTeam === 'Equipo Especial' || gameData.selectedOpponent === 'Equipo Especial'; // Formación 2-2 (2 defensores, 2 delanteros + arquero) // Equipo del jugador (lado izquierdo) const playerFormation = [ // Arquero { x: 60, y: centerY, type: 'gk', number: 1, name: isSpecialTeam && gameData.selectedTeam === 'Equipo Especial' ? gameData.specialTeamPlayers.goalkeeper.name : 'Arquero' }, // Defensores { x: 200, y: centerY - 80, type: 'df', number: 4, name: isSpecialTeam && gameData.selectedTeam === 'Equipo Especial' ? gameData.specialTeamPlayers.defenders[0].name : 'Defensor 1' }, { x: 200, y: centerY + 80, type: 'df', number: 5, name: isSpecialTeam && gameData.selectedTeam === 'Equipo Especial' ? gameData.specialTeamPlayers.defenders[1].name : 'Defensor 2' }, // Delanteros { x: 350, y: centerY - 60, type: 'fw', number: 10, name: isSpecialTeam && gameData.selectedTeam === 'Equipo Especial' ? gameData.specialTeamPlayers.forwards[0].name : 'Delantero 1' }, { x: 350, y: centerY + 60, type: 'fw', number: 7, name: isSpecialTeam && gameData.selectedTeam === 'Equipo Especial' ? gameData.specialTeamPlayers.forwards[1].name : 'Delantero 2' } ]; playerFormation.forEach((pos, i) => { playerTeam.push({ x: pos.x, y: pos.y, radius: 18, color: '#00a8ff', type: pos.type, number: pos.number, name: pos.name, speed: 4, hasBall: i === 3, // El primer delantero tiene la pelota al inicio isGoalkeeper: pos.type === 'gk', targetX: pos.x, targetY: pos.y, isMoving: false, passTarget: null }); }); // Equipo de la CPU (lado derecho) const cpuFormation = [ // Arquero { x: fieldWidth - 60, y: centerY, type: 'gk', number: 1, name: isSpecialTeam && gameData.selectedOpponent === 'Equipo Especial' ? gameData.specialTeamPlayers.goalkeeper.name : 'Arquero' }, // Defensores { x: fieldWidth - 200, y: centerY - 80, type: 'df', number: 4, name: isSpecialTeam && gameData.selectedOpponent === 'Equipo Especial' ? gameData.specialTeamPlayers.defenders[0].name : 'Defensor 1' }, { x: fieldWidth - 200, y: centerY + 80, type: 'df', number: 5, name: isSpecialTeam && gameData.selectedOpponent === 'Equipo Especial' ? gameData.specialTeamPlayers.defenders[1].name : 'Defensor 2' }, // Delanteros { x: fieldWidth - 350, y: centerY - 60, type: 'fw', number: 10, name: isSpecialTeam && gameData.selectedOpponent === 'Equipo Especial' ? gameData.specialTeamPlayers.forwards[0].name : 'Delantero 1' }, { x: fieldWidth - 350, y: centerY + 60, type: 'fw', number: 7, name: isSpecialTeam && gameData.selectedOpponent === 'Equipo Especial' ? gameData.specialTeamPlayers.forwards[1].name : 'Delantero 2' } ]; cpuFormation.forEach((pos, i) => { cpuTeam.push({ x: pos.x, y: pos.y, radius: 18, color: '#e84118', type: pos.type, number: pos.number, name: pos.name, speed: 4, hasBall: false, isGoalkeeper: pos.type === 'gk', targetX: pos.x, targetY: pos.y, isMoving: false, passTarget: null }); }); // Crear pelota const playerWithBall = playerTeam.find(player => player.hasBall); ball = { x: playerWithBall ? playerWithBall.x + 25 : centerX, y: playerWithBall ? playerWithBall.y : centerY, radius: 12, color: '#FFFFFF', speed: 0, direction: 0, owner: playerWithBall ? 'player' : null, spacePressed: false, spacePressTime: 0, spaceStartX: 0, spaceStartY: 0, isMoving: false, trail: [] }; // Establecer jugador activo activePlayer = playerWithBall; // Configurar IA según dificultad if (gameData.selectedDifficulty) { aiActionDelay = gameData.selectedDifficulty.aiDelay; cpuTeam.forEach(player => { player.speed = 4 * gameData.selectedDifficulty.speed; }); } // Inicializar rastro de la pelota ballTrail = []; isCelebrating = false; celebratingTeam = null; celebrationTimer = 0; corners = 0; freeKicks = 0; lastGoalBy = null; goalScorer = null; } // Bucle principal del juego function gameLoop(timestamp) { if (gameData.gameState !== 'playing') return; // Actualizar tiempo del partido updateMatchTime(); // Actualizar animaciones animationTimer += 1/60; // Actualizar celebración si está activa if (isCelebrating) { updateCelebration(); drawField(); drawPlayers(); drawBall(); requestAnimationFrame(gameLoop); return; } // Actualizar posiciones updatePlayers(); updateBall(); updateAI(); // Dibujar todo drawField(); drawPlayers(); drawBall(); // Verificar colisiones y goles checkCollisions(); checkGoal(); checkOutOfBounds(); // Mensajes aleatorios if (timestamp - lastMessageTime > messageInterval) { randomMessage(); lastMessageTime = timestamp; } // Continuar el bucle gameLoopId = requestAnimationFrame(gameLoop); } // Actualizar tiempo del partido function updateMatchTime() { gameData.matchTime += 1/60; const minutes = Math.floor(gameData.matchTime / 60); const seconds = Math.floor(gameData.matchTime % 60); document.getElementById('game-time').textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; if (gameData.matchTime >= gameData.maxMatchTime) { endMatch(); } } // Actualizar jugadores function updatePlayers() { // Mover jugador activo con teclado if (activePlayer && activePlayer.hasBall && !isCelebrating) { let moveX = 0, moveY = 0; if (keys['w'] || keys['arrowup']) moveY -= activePlayer.speed; if (keys['s'] || keys['arrowdown']) moveY += activePlayer.speed; if (keys['a'] || keys['arrowleft']) moveX -= activePlayer.speed; if (keys['d'] || keys['arrowright']) moveX += activePlayer.speed; // Normalizar movimiento diagonal if (moveX !== 0 && moveY !== 0) { moveX *= 0.7071; moveY *= 0.7071; } // Mover jugador const newX = activePlayer.x + moveX; const newY = activePlayer.y + moveY; // Verificar que no salga del campo del jugador (lado izquierdo) const fieldWidth = canvas.width; if (newX >= 50 && newX <= fieldWidth / 2 - 50) { activePlayer.x = newX; } if (newY >= 50 && newY <= canvas.height - 50) { activePlayer.y = newY; } // Mover pelota junto al jugador (no dentro) if (ball.owner === 'player') { const angle = Math.atan2(moveY, moveX); ball.x = activePlayer.x + Math.cos(angle) * 30; ball.y = activePlayer.y + Math.sin(angle) * 30; // Añadir al rastro de la pelota ballTrail.push({x: ball.x, y: ball.y, alpha: 1}); if (ballTrail.length > 10) ballTrail.shift(); } } // Actualizar rastro de la pelota for (let i = 0; i < ballTrail.length; i++) { ballTrail[i].alpha -= 0.1; } ballTrail = ballTrail.filter(point => point.alpha > 0); // Mover jugadores hacia sus posiciones objetivo playerTeam.forEach(player => { if (player.isMoving && !player.hasBall) { const dx = player.targetX - player.x; const dy = player.targetY - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance > 5) { player.x += (dx / distance) * player.speed * 0.5; player.y += (dy / distance) * player.speed * 0.5; } else { player.isMoving = false; } } }); cpuTeam.forEach(player => { if (player.isMoving && !player.hasBall) { const dx = player.targetX - player.x; const dy = player.targetY - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance > 5) { player.x += (dx / distance) * player.speed * 0.5; player.y += (dy / distance) * player.speed * 0.5; } else { player.isMoving = false; } } }); } // Actualizar pelota function updateBall() { // Si la pelota tiene dueño, sigue al jugador (pero no dentro de él) if (ball.owner && !isCelebrating) { const team = ball.owner === 'player' ? playerTeam : cpuTeam; const playerWithBall = team.find(player => player.hasBall); if (playerWithBall) { // Calcular posición al lado del jugador const angle = Math.atan2(playerWithBall.y - ball.y, playerWithBall.x - ball.x); const targetX = playerWithBall.x + Math.cos(angle) * 30; const targetY = playerWithBall.y + Math.sin(angle) * 30; // Suavizar movimiento hacia el jugador const dx = targetX - ball.x; const dy = targetY - ball.y; ball.x += dx * 0.2; ball.y += dy * 0.2; } } else if (ball.speed > 0.1 && !isCelebrating) { // Si no tiene dueño y tiene velocidad, moverse ball.x += Math.cos(ball.direction) * ball.speed; ball.y += Math.sin(ball.direction) * ball.speed; // Reducir velocidad por fricción ball.speed *= 0.98; // Añadir al rastro ballTrail.push({x: ball.x, y: ball.y, alpha: 1}); if (ballTrail.length > 10) ballTrail.shift(); // Rebotar en los bordes del campo if (ball.x <= ball.radius || ball.x >= canvas.width - ball.radius) { ball.direction = Math.PI - ball.direction; ball.speed *= 0.8; updateMessage("¡La pelota sale por la línea!"); } if (ball.y <= ball.radius || ball.y >= canvas.height - ball.radius) { ball.direction = -ball.direction; ball.speed *= 0.8; updateMessage("¡La pelota sale por la línea!"); } // Mantener dentro del campo ball.x = Math.max(ball.radius, Math.min(canvas.width - ball.radius, ball.x)); ball.y = Math.max(ball.radius, Math.min(canvas.height - ball.radius, ball.y)); } } // Actualizar IA de la CPU function updateAI() { const now = Date.now(); if (now - lastAIAction < aiActionDelay || isCelebrating) return; // Encontrar jugador de la CPU con la pelota const cpuWithBall = cpuTeam.find(player => player.hasBall); if (cpuWithBall) { // Si la CPU tiene la pelota if (Math.random() < 0.02) { // 2% de probabilidad por frame de chutar shootBallCPU(cpuWithBall); } else if (Math.random() < 0.05) { // 5% de probabilidad de pasar passBallCPU(cpuWithBall); } else { // Moverse hacia la portería del jugador const targetX = 60; const targetY = canvas.height / 2 + (Math.random() * 100 - 50); const dx = targetX - cpuWithBall.x; const dy = targetY - cpuWithBall.y; const distance = Math.sqrt(dx*dx + dy*dy); // Solo moverse si está en su lado del campo if (cpuWithBall.x > canvas.width / 2) { cpuWithBall.x -= cpuWithBall.speed * 0.7; } // Movimiento vertical hacia la portería if (Math.abs(dy) > 20) { cpuWithBall.y += (dy > 0 ? 1 : -1) * cpuWithBall.speed * 0.5; } // Mantener dentro de su lado del campo cpuWithBall.x = Math.max(canvas.width / 2, Math.min(canvas.width - 60, cpuWithBall.x)); cpuWithBall.y = Math.max(60, Math.min(canvas.height - 60, cpuWithBall.y)); } } else if (ball.owner === null) { // Si la pelota está libre, buscar el jugador más cercano let closestPlayer = null; let closestDistance = Infinity; cpuTeam.forEach(player => { if (player.isGoalkeeper) return; const dx = ball.x - player.x; const dy = ball.y - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < closestDistance) { closestDistance = distance; closestPlayer = player; } }); // Mover al jugador más cercano hacia la pelota if (closestPlayer && closestDistance > 30) { const dx = ball.x - closestPlayer.x; const dy = ball.y - closestPlayer.y; const distance = Math.sqrt(dx*dx + dy*dy); closestPlayer.x += (dx / distance) * closestPlayer.speed * 0.8; closestPlayer.y += (dy / distance) * closestPlayer.speed * 0.8; // Mantener en su lado del campo closestPlayer.x = Math.max(canvas.width / 2, Math.min(canvas.width - 60, closestPlayer.x)); closestPlayer.y = Math.max(60, Math.min(canvas.height - 60, closestPlayer.y)); } } else if (ball.owner === 'player') { // Si el jugador tiene la pelota, marcar al jugador activo const playerWithBall = playerTeam.find(player => player.hasBall); if (playerWithBall) { // Encontrar el defensor más cercano let closestDefender = null; let closestDistance = Infinity; cpuTeam.forEach(player => { if (player.type === 'df') { const dx = playerWithBall.x - player.x; const dy = playerWithBall.y - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < closestDistance) { closestDistance = distance; closestDefender = player; } } }); // Mover el defensor hacia el jugador con la pelota if (closestDefender && closestDistance > 20) { const dx = playerWithBall.x - closestDefender.x; const dy = playerWithBall.y - closestDefender.y; const distance = Math.sqrt(dx*dx + dy*dy); closestDefender.x += (dx / distance) * closestDefender.speed * 0.9; closestDefender.y += (dy / distance) * closestDefender.speed * 0.9; // Mantener en su lado del campo closestDefender.x = Math.max(canvas.width / 2, Math.min(canvas.width - 60, closestDefender.x)); closestDefender.y = Math.max(60, Math.min(canvas.height - 60, closestDefender.y)); } } } lastAIAction = now; } // Dibujar campo function drawField() { const width = canvas.width; const height = canvas.height; // Césped con patrón ctx.fillStyle = '#2a623d'; ctx.fillRect(0, 0, width, height); // Patrón de césped ctx.strokeStyle = '#3a7d4d'; ctx.lineWidth = 1; for (let i = 0; i < width; i += 40) { ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, height); ctx.stroke(); } for (let i = 0; i < height; i += 40) { ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(width, i); ctx.stroke(); } // Líneas del campo ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 3; // Líneas exteriores ctx.strokeRect(20, 20, width - 40, height - 40); // Línea de mitad de cancha ctx.beginPath(); ctx.moveTo(width / 2, 20); ctx.lineTo(width / 2, height - 20); ctx.stroke(); // Círculo central ctx.beginPath(); ctx.arc(width / 2, height / 2, 80, 0, Math.PI * 2); ctx.stroke(); // Punto central ctx.beginPath(); ctx.arc(width / 2, height / 2, 5, 0, Math.PI * 2); ctx.fillStyle = '#FFFFFF'; ctx.fill(); // Áreas // Área izquierda (jugador) ctx.strokeRect(20, height / 2 - 120, 100, 240); // Área derecha (CPU) ctx.strokeRect(width - 120, height / 2 - 120, 100, 240); // Porterías ctx.lineWidth = 4; // Portería izquierda ctx.strokeRect(10, height / 2 - 60, 10, 120); // Portería derecha ctx.strokeRect(width - 20, height / 2 - 60, 10, 120); // Tribuna (gradas) ctx.fillStyle = '#333333'; ctx.fillRect(0, 0, width, 20); ctx.fillRect(0, height - 20, width, 20); ctx.fillRect(0, 0, 20, height); ctx.fillRect(width - 20, 0, 20, height); // Detalles de la tribuna ctx.fillStyle = '#555555'; for (let i = 40; i < width - 40; i += 40) { ctx.fillRect(i, 5, 20, 10); ctx.fillRect(i, height - 15, 20, 10); } for (let i = 40; i < height - 40; i += 40) { ctx.fillRect(5, i, 10, 20); ctx.fillRect(width - 15, i, 10, 20); } // Línea de medio campo resaltada ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 5; ctx.setLineDash([10, 10]); ctx.beginPath(); ctx.moveTo(width / 2, 20); ctx.lineTo(width / 2, height - 20); ctx.stroke(); ctx.setLineDash([]); } // Dibujar jugadores function drawPlayers() { // Dibujar rastro de la pelota for (let i = 0; i < ballTrail.length; i++) { const point = ballTrail[i]; ctx.beginPath(); ctx.arc(point.x, point.y, 3, 0, Math.PI * 2); ctx.fillStyle = `rgba(255, 255, 255, ${point.alpha})`; ctx.fill(); } // Dibujar jugadores del equipo del jugador playerTeam.forEach(player => { // Cuerpo del jugador ctx.beginPath(); ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2); ctx.fillStyle = player.color; ctx.fill(); // Borde ctx.strokeStyle = player.hasBall ? '#FFD700' : '#FFFFFF'; ctx.lineWidth = player.hasBall ? 4 : 2; ctx.stroke(); // Número y nombre ctx.fillStyle = '#FFFFFF'; ctx.font = player.hasBall ? 'bold 12px Arial' : '10px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(player.number, player.x, player.y); // Nombre pequeño arriba ctx.font = '8px Arial'; ctx.fillText(player.name, player.x, player.y - player.radius - 5); }); // Dibujar jugadores de la CPU cpuTeam.forEach(player => { // Cuerpo del jugador ctx.beginPath(); ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2); ctx.fillStyle = player.color; ctx.fill(); // Borde ctx.strokeStyle = player.hasBall ? '#FFD700' : '#FFFFFF'; ctx.lineWidth = player.hasBall ? 4 : 2; ctx.stroke(); // Número y nombre ctx.fillStyle = '#FFFFFF'; ctx.font = player.hasBall ? 'bold 12px Arial' : '10px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(player.number, player.x, player.y); // Nombre pequeño arriba ctx.font = '8px Arial'; ctx.fillText(player.name, player.x, player.y - player.radius - 5); }); } // Dibujar pelota function drawBall() { // Pelota con efecto de animación si está en movimiento const ballScale = ball.speed > 5 ? 1.2 : 1.0; ctx.save(); ctx.translate(ball.x, ball.y); ctx.scale(ballScale, ballScale); // Cuerpo de la pelota ctx.beginPath(); ctx.arc(0, 0, ball.radius, 0, Math.PI * 2); ctx.fillStyle = ball.color; ctx.fill(); // Diseño de la pelota ctx.strokeStyle = '#000000'; ctx.lineWidth = 1.5; // Líneas decorativas ctx.beginPath(); ctx.arc(0, 0, ball.radius - 2, 0, Math.PI * 2); ctx.stroke(); // Pentágonos (simplificado) ctx.beginPath(); ctx.moveTo(0, -ball.radius + 3); ctx.lineTo(-3, -1); ctx.lineTo(-2, 3); ctx.lineTo(2, 3); ctx.lineTo(3, -1); ctx.closePath(); ctx.stroke(); ctx.restore(); // Efecto de velocidad if (ball.speed > 8) { ctx.beginPath(); const trailLength = ball.speed * 2; const trailX = ball.x - Math.cos(ball.direction) * trailLength; const trailY = ball.y - Math.sin(ball.direction) * trailLength; const gradient = ctx.createLinearGradient(trailX, trailY, ball.x, ball.y); gradient.addColorStop(0, 'rgba(255, 255, 255, 0)'); gradient.addColorStop(1, 'rgba(255, 255, 255, 0.5)'); ctx.strokeStyle = gradient; ctx.lineWidth = 3; ctx.beginPath(); ctx.moveTo(trailX, trailY); ctx.lineTo(ball.x, ball.y); ctx.stroke(); } } // Verificar colisiones function checkCollisions() { // Colisiones entre jugadores y pelota (cuando la pelota no tiene dueño) if (!ball.owner && ball.speed < 5 && !isCelebrating) { // Con jugadores del equipo del jugador playerTeam.forEach(player => { if (!player.hasBall) { const dx = ball.x - player.x; const dy = ball.y - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < player.radius + ball.radius + 5) { // El jugador toma la pelota player.hasBall = true; ball.owner = 'player'; activePlayer = player; ball.speed = 0; // Quitar la pelota a cualquier otro jugador playerTeam.forEach(p => { if (p !== player) p.hasBall = false; }); cpuTeam.forEach(p => p.hasBall = false); updateMessage("¡Recuperación del balón!"); animatePass(); } } }); // Con jugadores de la CPU cpuTeam.forEach(player => { if (!player.hasBall) { const dx = ball.x - player.x; const dy = ball.y - player.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < player.radius + ball.radius + 5) { // La CPU toma la pelota player.hasBall = true; ball.owner = 'cpu'; ball.speed = 0; // Quitar la pelota a cualquier otro jugador cpuTeam.forEach(p => { if (p !== player) p.hasBall = false; }); playerTeam.forEach(p => p.hasBall = false); updateMessage("¡La CPU recupera el balón!"); animatePass(); } } }); } // Colisiones entre jugadores if (!isCelebrating) { playerTeam.forEach(player => { cpuTeam.forEach(cpuPlayer => { const dx = player.x - cpuPlayer.x; const dy = player.y - cpuPlayer.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < player.radius + cpuPlayer.radius) { // Empujar a los jugadores separados const angle = Math.atan2(dy, dx); const force = 2; player.x += Math.cos(angle) * force; player.y += Math.sin(angle) * force; cpuPlayer.x -= Math.cos(angle) * force; cpuPlayer.y -= Math.sin(angle) * force; } }); }); } } // Verificar goles function checkGoal() { const goalWidth = 120; const goalHeight = 60; const goalY = canvas.height / 2 - goalHeight / 2; // Gol del jugador (portería derecha) if (ball.x > canvas.width - 25 && ball.x < canvas.width - 15 && ball.y > goalY && ball.y < goalY + goalHeight) { scoreGoal('player'); return; } // Gol de la CPU (portería izquierda) if (ball.x < 25 && ball.x > 15 && ball.y > goalY && ball.y < goalY + goalHeight) { scoreGoal('cpu'); return; } } // Verificar si la pelota sale del campo function checkOutOfBounds() { // Si la pelota sale por los laterales (no por las porterías) if ((ball.x <= 15 || ball.x >= canvas.width - 15) && (ball.y < canvas.height / 2 - 60 || ball.y > canvas.height / 2 + 60)) { if (ball.x <= 15) { // Saque de banda para la CPU updateMessage("¡Saque de banda para la CPU!"); ball.x = 30; ball.y = Math.max(50, Math.min(canvas.height - 50, ball.y)); ball.speed = 0; ball.owner = null; // Posicionar a un jugador de la CPU cerca const nearestCPU = cpuTeam.reduce((nearest, player) => { const dist = Math.abs(player.y - ball.y); return dist < nearest.dist ? {player, dist} : nearest; }, {player: cpuTeam[0], dist: Infinity}); nearestCPU.player.x = ball.x + 40; nearestCPU.player.y = ball.y; } else { // Saque de banda para el jugador updateMessage("¡Saque de banda para el jugador!"); ball.x = canvas.width - 30; ball.y = Math.max(50, Math.min(canvas.height - 50, ball.y)); ball.speed = 0; ball.owner = null; // Posicionar al jugador activo cerca if (activePlayer) { activePlayer.x = ball.x - 40; activePlayer.y = ball.y; } } } // Corner if (ball.x <= 20 && ball.y >= canvas.height / 2 - 60 && ball.y <= canvas.height / 2 + 60) { corners++; updateMessage("¡Corner para la CPU!"); ball.x = 30; ball.y = Math.random() > 0.5 ? canvas.height / 2 - 50 : canvas.height / 2 + 50; ball.speed = 0; ball.owner = null; } else if (ball.x >= canvas.width - 20 && ball.y >= canvas.height / 2 - 60 && ball.y <= canvas.height / 2 + 60) { corners++; updateMessage("¡Corner para el jugador!"); ball.x = canvas.width - 30; ball.y = Math.random() > 0.5 ? canvas.height / 2 - 50 : canvas.height / 2 + 50; ball.speed = 0; ball.owner = null; } } // Marcar gol function scoreGoal(team) { if (isCelebrating) return; goalScorer = team === 'player' ? playerTeam.find(p => p.hasBall)?.name || "Un jugador" : cpuTeam.find(p => p.hasBall)?.name || "Un jugador"; if (team === 'player') { gameData.score.player++; updateMessage(`¡GOOOOOOL! ${goalScorer} marca para ${gameData.selectedTeam}!`); lastGoalBy = 'player'; } else { gameData.score.cpu++; updateMessage(`¡GOOOOOOL! ${goalScorer} marca para ${gameData.selectedOpponent}!`); lastGoalBy = 'cpu'; } updateScoreboard(); // Efecto visual en el marcador const playerScore = document.getElementById('player-score'); const cpuScore = document.getElementById('cpu-score'); playerScore.classList.add('goal-animation'); cpuScore.classList.add('goal-animation'); setTimeout(() => { playerScore.classList.remove('goal-animation'); cpuScore.classList.remove('goal-animation'); }, 800); // Iniciar celebración startCelebration(team); // Verificar si hay ganador (5 goles) if (gameData.score.player >= 5 || gameData.score.cpu >= 5) { setTimeout(() => endMatch(), 3000); } else { setTimeout(() => resetAfterGoal(), 3000); } } // Iniciar celebración function startCelebration(team) { isCelebrating = true; celebratingTeam = team; celebrationTimer = 0; // Si es gol en contra, no hay celebración if ((team === 'player' && lastGoalBy === 'cpu') || (team === 'cpu' && lastGoalBy === 'player')) { updateMessage("Gol en contra... sin celebración"); return; } // Posicionar jugadores para la celebración if (team === 'player') { const scorer = playerTeam.find(p => p.hasBall) || playerTeam[3]; const celebrationX = canvas.width * 0.3; const celebrationY = canvas.height / 2; playerTeam.forEach(player => { player.targetX = celebrationX + (Math.random() * 80 - 40); player.targetY = celebrationY + (Math.random() * 80 - 40); player.isMoving = true; }); } else { const scorer = cpuTeam.find(p => p.hasBall) || cpuTeam[3]; const celebrationX = canvas.width * 0.7; const celebrationY = canvas.height / 2; cpuTeam.forEach(player => { player.targetX = celebrationX + (Math.random() * 80 - 40); player.targetY = celebrationY + (Math.random() * 80 - 40); player.isMoving = true; }); } } // Actualizar celebración function updateCelebration() { celebrationTimer += 1/60; // La celebración dura 3 segundos if (celebrationTimer >= 3) { isCelebrating = false; celebratingTeam = null; } } // Actualizar marcador function updateScoreboard() { document.getElementById('player-score').textContent = gameData.score.player; document.getElementById('cpu-score').textContent = gameData.score.cpu; } // Reiniciar después de un gol function resetAfterGoal() { // Colocar la pelota en el centro ball.x = canvas.width / 2; ball.y = canvas.height / 2; ball.owner = null; ball.speed = 0; ballTrail = []; // Quitar la pelota a todos los jugadores playerTeam.forEach(player => player.hasBall = false); cpuTeam.forEach(player => player.hasBall = false); // Volver a posiciones iniciales initGameObjects(); updateMessage("¡Reanudación del partido!"); } // Finalizar partido function endMatch() { gameActive = false; gameData.gameState = 'finished'; let resultMessage = ""; if (gameData.score.player > gameData.score.cpu) { resultMessage = `¡Victoria del ${gameData.selectedTeam}! ${gameData.score.player} - ${gameData.score.cpu}`; } else if (gameData.score.player < gameData.score.cpu) { resultMessage = `Derrota contra ${gameData.selectedOpponent}. ${gameData.score.player} - ${gameData.score.cpu}`; } else { resultMessage = `Empate. ¡Buen partido! ${gameData.score.player} - ${gameData.score.cpu}`; } updateMessage("¡Fin del partido! " + resultMessage); setTimeout(() => { alert(`Partido finalizado\n\n${gameData.selectedTeam} ${gameData.score.player} - ${gameData.score.cpu} ${gameData.selectedOpponent}\n\n${resultMessage}`); stopGame(); showScreen('title'); resetGameData(); }, 2000); } // Pasar la pelota function passBall() { if (!activePlayer || !activePlayer.hasBall || isCelebrating) return; // Encontrar el jugador más cercano en línea de pase let closestTeammate = null; let closestDistance = Infinity; playerTeam.forEach(player => { if (player !== activePlayer && !player.isGoalkeeper) { const dx = player.x - activePlayer.x; const dy = player.y - activePlayer.y; const distance = Math.sqrt(dx*dx + dy*dy); // Verificar que esté dentro de un rango razonable y en el mismo lado if (distance < 200 && player.x < canvas.width / 2 && distance < closestDistance) { closestTeammate = player; closestDistance = distance; } } }); if (closestTeammate) { // Calcular dirección del pase const dx = closestTeammate.x - activePlayer.x; const dy = closestTeammate.y - activePlayer.y; const distance = Math.sqrt(dx*dx + dy*dy); const direction = Math.atan2(dy, dx); // Pasar la pelota activePlayer.hasBall = false; closestTeammate.hasBall = true; activePlayer = closestTeammate; ball.owner = 'player'; ball.speed = 10; ball.direction = direction; // Animación de pase animatePass(); updateMessage("¡Pase preciso!"); } else { updateMessage("¡No hay compañeros para pasar!"); } } // Pasar la pelota (CPU) function passBallCPU(player) { if (!player || !player.hasBall || isCelebrating) return; // Encontrar un compañero const teammates = cpuTeam.filter(p => p !== player && !p.isGoalkeeper); if (teammates.length > 0) { const teammate = teammates[Math.floor(Math.random() * teammates.length)]; const dx = teammate.x - player.x; const dy = teammate.y - player.y; const distance = Math.sqrt(dx*dx + dy*dy); const direction = Math.atan2(dy, dx); player.hasBall = false; teammate.hasBall = true; ball.owner = 'cpu'; ball.speed = 10; ball.direction = direction; animatePass(); updateMessage("¡La CPU pasa el balón!"); } } // Chutar la pelota function shootBall(pressDuration) { if (!activePlayer || !activePlayer.hasBall || isCelebrating) return; // Calcular potencia del chute const power = Math.min(pressDuration / 500, 2.0); // Dirección hacia la portería rival const goalX = canvas.width - 30; const goalY = canvas.height / 2 + (Math.random() * 40 - 20); const dx = goalX - activePlayer.x; const dy = goalY - activePlayer.y; const distance = Math.sqrt(dx*dx + dy*dy); // Soltar la pelota activePlayer.hasBall = false; ball.owner = null; // Aplicar velocidad a la pelota ball.speed = 12 + power * 8; ball.direction = Math.atan2(dy, dx) + (Math.random() * 0.3 - 0.15); animateShot(); updateMessage("¡Chute al arco!"); } // Chutar la pelota (CPU) function shootBallCPU(player) { if (!player || !player.hasBall || isCelebrating) return; // Dirección hacia la portería del jugador const goalX = 30; const goalY = canvas.height / 2 + (Math.random() * 80 - 40); const dx = goalX - player.x; const dy = goalY - player.y; const distance = Math.sqrt(dx*dx + dy*dy); // Soltar la pelota player.hasBall = false; ball.owner = null; // Aplicar velocidad a la pelota ball.speed = 10 + Math.random() * 6; ball.direction = Math.atan2(dy, dx); animateShot(); updateMessage("¡La CPU chuta al arco!"); } // Animar pase function animatePass() { const passElements = document.querySelectorAll('.team-score'); passElements.forEach(el => { el.classList.add('pass-animation'); setTimeout(() => el.classList.remove('pass-animation'), 300); }); } // Animar chute function animateShot() { const shotElements = document.querySelectorAll('.team-score'); shotElements.forEach(el => { el.classList.add('shot-animation'); setTimeout(() => el.classList.remove('shot-animation'), 400); }); } // Actualizar mensaje function updateMessage(text) { const messageElement = document.getElementById('message-text'); messageElement.textContent = text; const panel = document.getElementById('message-panel'); panel.classList.add('pulse'); setTimeout(() => panel.classList.remove('pulse'), 300); } // Mensaje aleatorio function randomMessage() { const randomIndex = Math.floor(Math.random() * gameData.messages.length); updateMessage(gameData.messages[randomIndex]); } </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

2

Requests

2

Domains

392KB

Transfer Size

391KB

Content Size

125.0ms

Dom Content Loaded

292.0ms

First Paint

285.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...