Meta Description" name="description" />
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Futbol Pro 2D - Edición Cordobesa</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Roboto:wght@400;700&display=swap');
body { margin: 0; overflow: hidden; background: #1a1a1a; font-family: 'Roboto', sans-serif; color: white; user-select: none; }
#game-container { position: relative; width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center; background: radial-gradient(circle, #333, #000); }
canvas {
box-shadow: 0 0 50px rgba(0,0,0,0.8);
cursor: none; /* Ocultar mouse en juego */
}
/* UI y Menus */
.overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; display: flex; flex-direction: column; justify-content: center; align-items: center; }
.menu-screen {
background: rgba(16, 20, 30, 0.95);
width: 100%; height: 100%;
position: absolute;
display: flex; flex-direction: column;
justify-content: center; align-items: center;
pointer-events: auto;
z-index: 10;
backdrop-filter: blur(5px);
}
.hidden { display: none !important; }
h1 { font-family: 'Bebas Neue', sans-serif; font-size: 80px; margin: 0; color: #ffce00; letter-spacing: 5px; text-shadow: 4px 4px 0 #000; transform: skew(-5deg); }
h2 { font-family: 'Bebas Neue', sans-serif; font-size: 40px; margin: 10px; color: #fff; text-shadow: 2px 2px 0 #000; }
p { color: #aaa; font-size: 14px; margin-bottom: 30px; }
.btn-group { display: flex; flex-wrap: wrap; justify-content: center; gap: 15px; max-width: 800px; }
.btn {
background: linear-gradient(180deg, #e91e63, #c2185b);
color: white; border: none; padding: 15px 40px;
font-size: 22px; font-family: 'Bebas Neue', sans-serif;
cursor: pointer; border-radius: 4px;
box-shadow: 0 4px 0 #880e4f;
transition: 0.1s;
min-width: 200px; text-align: center; letter-spacing: 1px;
}
.btn:active { transform: translateY(4px); box-shadow: 0 0 0 #880e4f; }
.btn:hover { filter: brightness(1.2); }
.btn-sec { background: linear-gradient(180deg, #3f51b5, #303f9f); box-shadow: 0 4px 0 #1a237e; }
.btn-back { background: #555; box-shadow: 0 4px 0 #222; margin-top: 20px;}
/* HUD */
#hud { position: absolute; top: 20px; width: 95%; display: flex; justify-content: space-between; align-items: flex-start; pointer-events: none; }
.scoreboard { background: rgba(0,0,0,0.6); padding: 10px 30px; border-radius: 8px; border: 2px solid rgba(255,255,255,0.1); display: flex; align-items: center; gap: 20px; }
.team-badge { width: 40px; height: 40px; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: bold; border: 2px solid white; box-shadow: 0 0 10px rgba(0,0,0,0.5); }
.score-txt { font-family: 'Bebas Neue', sans-serif; font-size: 50px; line-height: 40px; }
.time-box { background: rgba(0,0,0,0.8); color: #00ff00; font-family: 'Courier New', monospace; font-weight: bold; font-size: 30px; padding: 10px 20px; border: 2px solid #555; border-radius: 5px; }
#controls-hint { position: absolute; bottom: 10px; right: 20px; font-size: 12px; color: rgba(255,255,255,0.5); text-align: right; }
.notification {
position: absolute; top: 20%; left: 50%; transform: translateX(-50%);
font-family: 'Bebas Neue', sans-serif; font-size: 100px;
color: #fff; -webkit-text-stroke: 2px black; text-shadow: 5px 5px 0 red;
opacity: 0; transition: opacity 0.5s; pointer-events: none; z-index: 20; text-align: center;
}
.visible { opacity: 1 !important; }
.list-container { max-height: 50vh; overflow-y: auto; width: 600px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 10px; }
.list-item { background: #2c3e50; padding: 15px; cursor: pointer; border-radius: 4px; text-align: center; font-weight: bold; border: 1px solid #34495e; }
.list-item:hover { background: #34495e; border-color: #e91e63; }
.list-item.selected { background: #e91e63; color: white; border-color: white; }
/* Scrollbar */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: #111; }
::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; }
</style>
</head>
<body>
<div id="game-container">
<canvas id="gameCanvas"></canvas>
<div id="ui-layer" class="overlay hidden">
<div id="hud">
<div class="scoreboard">
<div class="team-badge" id="hud-badge1">L</div>
<div class="score-txt"><span id="score1">0</span> - <span id="score2">0</span></div>
<div class="team-badge" id="hud-badge2">V</div>
</div>
<div class="time-box" id="timer">00:00</div>
</div>
<div id="notification" class="notification">¡GOLAZO!</div>
<div id="controls-hint">
WASD: Mover | ESPACIO: Pase/Chute | F: Cambiar Jugador | X: Quitar/Falta
</div>
</div>
<div id="main-menu" class="menu-screen">
<h1>FÚTBOL TOTAL 2D</h1>
<p>Edición Hno Cordobés</p>
<div class="btn-group">
<button class="btn" onclick="startFlow('friendly')">AMISTOSO</button>
<button class="btn btn-sec" onclick="startFlow('cup')">COPAS</button>
</div>
</div>
<div id="league-select" class="menu-screen hidden">
<h2 id="league-title">Elegí Liga (Tu Equipo)</h2>
<div id="league-list" class="list-container"></div>
<button class="btn btn-back" onclick="backToMain()">Volver</button>
</div>
<div id="team-select" class="menu-screen hidden">
<h2 id="team-title">Elegí Tu Equipo</h2>
<div id="team-list" class="list-container"></div>
<button class="btn btn-back" onclick="backToLeagues()">Volver</button>
</div>
<div id="game-over" class="menu-screen hidden">
<h1 id="go-title">FIN DEL PARTIDO</h1>
<h2 id="go-score"></h2>
<button class="btn" onclick="backToMain()">Menú Principal</button>
</div>
</div>
<script>
/** --- BASE DE DATOS DE EQUIPOS --- **/
const DATABASE = {
"ARG": { name: "Liga Argentina", teams: ["Boca Jrs", "River Plate", "Talleres", "Belgrano", "Racing", "Independiente", "San Lorenzo", "Estudiantes", "Newells", "Rosario Central", "Velez", "Lanus", "Argentinos", "Instituto"] },
"ENG": { name: "Premier League", teams: ["Man City", "Arsenal", "Liverpool", "Aston Villa", "Tottenham", "Man Utd", "Newcastle", "Chelsea", "West Ham", "Brighton", "Leeds Utd", "Everton"] },
"ESP": { name: "La Liga", teams: ["Real Madrid", "Barcelona", "Girona", "Atletico Madrid", "Athletic Bilbao", "Real Sociedad", "Betis", "Valencia", "Sevilla", "Villarreal"] },
"ITA": { name: "Serie A", teams: ["Inter", "Juventus", "Milan", "Roma", "Bologna", "Atalanta", "Napoli", "Fiorentina", "Lazio", "Torino"] },
"GER": { name: "Bundesliga", teams: ["Leverkusen", "Bayern Munich", "Stuttgart", "Dortmund", "RB Leipzig", "Frankfurt", "Hoffenheim", "Werder Bremen"] },
"BRA": { name: "Brasileirao", teams: ["Palmeiras", "Flamengo", "Botafogo", "Atletico Mineiro", "Gremio", "Fluminense", "Sao Paulo", "Internacional", "Corinthians", "Cruzeiro"] },
"SUD": { name: "Resto de America", teams: ["Colo Colo", "U de Chile", "U Catolica", "Peñarol", "Nacional", "Olimpia", "Cerro Porteño", "Libertad", "Bolivar", "The Strongest", "LDU Quito", "Barcelona SC", "Universitario", "Alianza Lima"] },
"FRA": { name: "Ligue 1", teams: ["PSG", "Monaco", "Brest", "Lille", "Nice", "Lens", "Marseille", "Lyon"] }
};
const TEAM_COLORS = {
"Boca Jrs": ["#00388d", "#fcb900"], "River Plate": ["#ffffff", "#db0030"], "Talleres": ["#002664", "#ffffff"], "Belgrano": ["#68a3e5", "#000000"],
"Man City": ["#6cabdd", "#ffffff"], "Man Utd": ["#da291c", "#ffffff"], "Real Madrid": ["#ffffff", "#000000"], "Barcelona": ["#a50044", "#004d98"],
"Brasil": ["#ffee00", "#009c3b"], "Argentina": ["#75aadb", "#ffffff"]
};
// Generador de colores si no está en la lista
function getColors(name) {
if (TEAM_COLORS[name]) return TEAM_COLORS[name];
let hash = 0;
for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
let c = (hash & 0x00FFFFFF).toString(16).toUpperCase();
return ["#" + "00000".substring(0, 6 - c.length) + c, "#ffffff"];
}
/** --- MOTOR DEL JUEGO --- **/
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let W, H;
const TILE_SIZE = 100; // Para el pasto
function resize() {
W = canvas.width = window.innerWidth;
H = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Constantes Físicas
const PLAYER_R = 14;
const BALL_R = 6;
const GOAL_W = 140;
const FRICTION = 0.94;
const KICK_POWER = 12;
const DRIBBLE_DIST = 18;
// Estado Global
let state = {
mode: 'MENU', // MENU, PLAY, PAUSE, GOAL, FOUL, END
time: 300,
score: [0, 0],
teams: { home: "Equipo 1", away: "Equipo 2" },
colors: { home: ["#f00","#fff"], away: ["#00f","#fff"] },
ball: { x: 0, y: 0, vx: 0, vy: 0, owner: null }, // Owner is the player object
players: [],
controlledPlayer: 4, // Index in home team
camera: { x: 0, y: 0 },
selectionStep: 0, // 0: League Home, 1: Team Home, 2: League Away, 3: Team Away
tempSelection: {}
};
// Input
const keys = {};
window.addEventListener('keydown', e => {
keys[e.code] = true;
if (state.mode === 'PLAY') {
if (e.code === 'KeyF') switchPlayer();
if (e.code === 'KeyX') tryTackle();
}
});
window.addEventListener('keyup', e => {
keys[e.code] = false;
if (e.code === 'Space' && state.mode === 'PLAY') releaseKick();
});
let spacePressedTime = 0;
/** --- LOGICA DEL JUEGO --- **/
function initMatch(homeTeam, awayTeam) {
state.teams.home = homeTeam;
state.teams.away = awayTeam;
state.colors.home = getColors(homeTeam);
state.colors.away = getColors(awayTeam);
state.score = [0, 0];
state.time = 300; // 5 mins
// Configurar HUD
document.getElementById('hud-badge1').style.background = state.colors.home[0];
document.getElementById('hud-badge1').style.color = state.colors.home[1];
document.getElementById('hud-badge1').innerText = homeTeam.substring(0,1);
document.getElementById('hud-badge2').style.background = state.colors.away[0];
document.getElementById('hud-badge2').style.color = state.colors.away[1];
document.getElementById('hud-badge2').innerText = awayTeam.substring(0,1);
document.getElementById('score1').innerText = "0";
document.getElementById('score2').innerText = "0";
setupFormation();
resetPositions('kickoff');
document.getElementById('ui-layer').classList.remove('hidden');
document.getElementById('main-menu').classList.add('hidden');
document.getElementById('game-over').classList.add('hidden');
state.mode = 'PLAY';
lastTime = Date.now();
gameLoop();
}
function setupFormation() {
state.players = [];
// Formacion 1-2-1-1 (5 jugadores)
// Team 0 (Left/Home)
const t0 = 0; const c0 = state.colors.home;
state.players.push(createPlayer(t0, 'GK', 50, H/2, c0));
state.players.push(createPlayer(t0, 'DEF', 250, H/2 - 100, c0));
state.players.push(createPlayer(t0, 'DEF', 250, H/2 + 100, c0));
state.players.push(createPlayer(t0, 'MID', 450, H/2, c0));
state.players.push(createPlayer(t0, 'FWD', 600, H/2, c0));
// Team 1 (Right/Away)
const t1 = 1; const c1 = state.colors.away;
state.players.push(createPlayer(t1, 'GK', W-50, H/2, c1));
state.players.push(createPlayer(t1, 'DEF', W-250, H/2 - 100, c1));
state.players.push(createPlayer(t1, 'DEF', W-250, H/2 + 100, c1));
state.players.push(createPlayer(t1, 'MID', W-450, H/2, c1));
state.players.push(createPlayer(t1, 'FWD', W-600, H/2, c1));
state.controlledPlayer = 4; // FWD starts controlled
}
function createPlayer(team, role, x, y, colors) {
return {
team, role, x, y, startX: x, startY: y,
vx: 0, vy: 0,
color: colors[0], sColor: colors[1],
cooldown: 0
};
}
function resetPositions(type) {
state.ball.vx = 0; state.ball.vy = 0; state.ball.owner = null;
state.ball.x = W/2; state.ball.y = H/2;
state.players.forEach(p => {
p.vx = 0; p.vy = 0;
if(type === 'goal') {
// Reset to formation side
p.x = p.startX; p.y = p.startY;
} else {
p.x = p.startX; p.y = p.startY;
}
});
}
function switchPlayer() {
// Find next nearest player to ball in my team
let bestDist = Infinity;
let bestIdx = -1;
state.players.forEach((p, i) => {
if(p.team === 0 && i !== state.controlledPlayer) {
let d = Math.hypot(p.x - state.ball.x, p.y - state.ball.y);
// Prioritize players slightly closer to ball but not Gk unless necessary
if (d < bestDist) { bestDist = d; bestIdx = i; }
}
});
if (bestIdx !== -1) state.controlledPlayer = bestIdx;
}
function tryTackle() {
const me = state.players[state.controlledPlayer];
// Check collision with ball or opponent
let tackled = false;
// Check against opponents
state.players.forEach(p => {
if (p.team === 1) {
let d = Math.hypot(me.x - p.x, me.y - p.y);
if (d < PLAYER_R * 2.5) {
// If opponent has ball, steal it
if (state.ball.owner === p) {
state.ball.owner = null;
// Ball impulse
let angle = Math.atan2(p.y - me.y, p.x - me.x);
state.ball.vx = Math.cos(angle) * 8;
state.ball.vy = Math.sin(angle) * 8;
tackled = true; // Clean tackle
} else {
// Check if ball is close enough to be "legal" tackle
let dBall = Math.hypot(state.ball.x - me.x, state.ball.y - me.y);
if (dBall > 40) {
// FOUL!
callFoul(me.x, me.y);
tackled = true;
}
}
}
}
});
// Slide animation (visual fake)
if(!tackled) {
me.vx *= 3; me.vy *= 3; // Lunge
}
}
function callFoul(x, y) {
state.mode = 'FOUL';
showNotification("¡FALTA!", "#ffff00");
setTimeout(() => {
state.mode = 'PLAY';
// Give ball to opponent nearby
state.ball.x = x; state.ball.y = y; state.ball.vx = 0; state.ball.vy = 0; state.ball.owner = null;
// Move players away slightly
state.players.forEach(p => {
let d = Math.hypot(p.x - x, p.y - y);
if(d < 60) p.x += (p.x > x ? 60 : -60);
});
}, 1500);
}
function releaseKick() {
const p = state.players[state.controlledPlayer];
const now = Date.now();
let power = Math.min((now - spacePressedTime) / 1000, 1.0); // 0 to 1
if (state.ball.owner === p) {
state.ball.owner = null;
let kickSpeed = 5 + (power * KICK_POWER); // 5 to 17
// Direction based on movement or facing goal if still
let angle = 0;
if (Math.abs(p.vx) > 0.1 || Math.abs(p.vy) > 0.1) {
angle = Math.atan2(p.vy, p.vx);
} else {
angle = Math.atan2((H/2) - p.y, W - p.x); // Aim to goal
}
state.ball.vx = Math.cos(angle) * kickSpeed;
state.ball.vy = Math.sin(angle) * kickSpeed;
} else {
// Pass request logic if ball is far (not implemented in simple mode)
}
spacePressedTime = 0;
}
function updatePhysics() {
if (keys['Space'] && !spacePressedTime) spacePressedTime = Date.now();
// 1. Players Movement
state.players.forEach((p, idx) => {
let ax = 0, ay = 0;
let speed = 2.5;
// Human Control
if (p.team === 0 && idx === state.controlledPlayer) {
if(keys['KeyW'] || keys['ArrowUp']) ay = -1;
if(keys['KeyS'] || keys['ArrowDown']) ay = 1;
if(keys['KeyA'] || keys['ArrowLeft']) ax = -1;
if(keys['KeyD'] || keys['ArrowRight']) ax = 1;
// Sprint? Maybe later
}
// CPU AI (And Human Teammates)
else {
let targetX = p.startX, targetY = p.startY;
// Logic for Team 1 (CPU)
if (p.team === 1) {
// If own ball, Attack
if (state.ball.owner && state.ball.owner.team === 1) {
// Attack logic
if (state.ball.owner === p) {
// I have the ball. Run to goal
targetX = 50; targetY = H/2;
// Random Shoot
let distGoal = Math.hypot(p.x - 0, p.y - H/2);
if (distGoal < 250 && Math.random() < 0.02) {
state.ball.owner = null;
let angle = Math.atan2(H/2 - p.y, 0 - p.x) + (Math.random()-0.5)*0.2;
state.ball.vx = Math.cos(angle) * 15;
state.ball.vy = Math.sin(angle) * 15;
}
} else {
// Support
targetX = state.ball.x + (p.startX - W/2); // Relative formation
targetY = state.ball.y;
}
} else {
// Defense logic
// Only closest chases ball
let isClosest = true;
let myDist = Math.hypot(p.x - state.ball.x, p.y - state.ball.y);
for(let k=5; k<10; k++) { // CPU indices
let otherDist = Math.hypot(state.players[k].x - state.ball.x, state.players[k].y - state.ball.y);
if (otherDist < myDist) isClosest = false;
}
if (isClosest) {
targetX = state.ball.x;
targetY = state.ball.y;
speed = 2.6; // Sprint to mark
} else {
// Zone defense
targetX = p.startX * 0.5 + state.ball.x * 0.4; // Shift towards ball but keep shape
targetY = p.startY;
}
}
}
// Logic for Human AI Teammates
else {
// Simple stay in formation
targetX = p.startX + (state.ball.x - W/2)*0.5;
targetY = p.startY;
}
// Move towards target
let dx = targetX - p.x;
let dy = targetY - p.y;
let dist = Math.hypot(dx, dy);
if (dist > 5) {
let angle = Math.atan2(dy, dx);
ax = Math.cos(angle);
ay = Math.sin(angle);
}
}
// Apply velocity
p.vx += ax * 0.2;
p.vy += ay * 0.2;
p.vx *= 0.9; p.vy *= 0.9; // Friction
// Cap speed
let vel = Math.hypot(p.vx, p.vy);
if (vel > speed) {
p.vx = (p.vx/vel) * speed;
p.vy = (p.vy/vel) * speed;
}
p.x += p.vx;
p.y += p.vy;
// Bounds
if(p.x < PLAYER_R) p.x = PLAYER_R;
if(p.x > W-PLAYER_R) p.x = W-PLAYER_R;
if(p.y < PLAYER_R) p.y = PLAYER_R;
if(p.y > H-PLAYER_R) p.y = H-PLAYER_R;
// Player vs Player collision (simple push)
state.players.forEach((p2, idx2) => {
if (idx !== idx2) {
let pdx = p.x - p2.x;
let pdy = p.y - p2.y;
let pdist = Math.hypot(pdx, pdy);
if (pdist < PLAYER_R * 2) {
let angle = Math.atan2(pdy, pdx);
let push = 1;
p.vx += Math.cos(angle) * push;
p.vy += Math.sin(angle) * push;
}
}
});
});
// 2. Ball Logic
if (state.ball.owner) {
// Ball is stuck to player
let p = state.ball.owner;
let angle = Math.atan2(p.vy, p.vx);
if (Math.hypot(p.vx, p.vy) < 0.1) angle = Math.atan2(state.ball.y - p.y, state.ball.x - p.x); // Keep previous angle if stopped
state.ball.x = p.x + Math.cos(angle) * DRIBBLE_DIST;
state.ball.y = p.y + Math.sin(angle) * DRIBBLE_DIST;
state.ball.vx = p.vx;
state.ball.vy = p.vy;
} else {
// Free ball physics
state.ball.x += state.ball.vx;
state.ball.y += state.ball.vy;
state.ball.vx *= 0.98; // Ball rolls longer
state.ball.vy *= 0.98;
// Bounce Walls
if (state.ball.y < 0 || state.ball.y > H) state.ball.vy *= -1;
if (state.ball.x < 0) {
if (Math.abs(state.ball.y - H/2) < GOAL_W/2) scoreGoal(1); // Goal for Team 1
else state.ball.vx *= -1;
}
if (state.ball.x > W) {
if (Math.abs(state.ball.y - H/2) < GOAL_W/2) scoreGoal(0); // Goal for Team 0
else state.ball.vx *= -1;
}
// Check for possession
state.players.forEach(p => {
let d = Math.hypot(p.x - state.ball.x, p.y - state.ball.y);
if (d < PLAYER_R + BALL_R + 2) {
state.ball.owner = p;
}
});
}
}
function scoreGoal(teamIndex) {
state.mode = 'GOAL';
state.score[teamIndex]++;
document.getElementById('score1').innerText = state.score[0];
document.getElementById('score2').innerText = state.score[1];
showNotification("¡GOL!", teamIndex === 0 ? state.colors.home[0] : state.colors.away[0]);
setTimeout(() => {
if(state.score[0] >= 5 || state.score[1] >= 5) {
endGame();
} else {
resetPositions('goal');
state.mode = 'PLAY';
}
}, 2500);
}
function endGame() {
state.mode = 'END';
document.getElementById('ui-layer').classList.add('hidden');
document.getElementById('game-over').classList.remove('hidden');
document.getElementById('go-score').innerText = `${state.teams.home} ${state.score[0]} - ${state.score[1]} ${state.teams.away}`;
}
function showNotification(text, color) {
const el = document.getElementById('notification');
el.innerText = text;
el.style.color = color || "#fff";
el.classList.add('visible');
setTimeout(() => el.classList.remove('visible'), 2000);
}
/** --- RENDER --- **/
function draw() {
// 1. Campo (Pasto)
for (let x = 0; x < W; x+=TILE_SIZE) {
for (let y = 0; y < H; y+=TILE_SIZE) {
ctx.fillStyle = ((x+y)%200 === 0) ? "#2e7d32" : "#388e3c"; // Cuadros
ctx.fillRect(x,y,TILE_SIZE,TILE_SIZE);
}
}
// Lineas
ctx.lineWidth = 4;
ctx.strokeStyle = "rgba(255,255,255,0.8)";
// Mitad
ctx.beginPath(); ctx.moveTo(W/2, 0); ctx.lineTo(W/2, H); ctx.stroke();
ctx.beginPath(); ctx.arc(W/2, H/2, 70, 0, Math.PI*2); ctx.stroke();
// Areas
const areaH = 250; const areaW = 120;
ctx.strokeRect(0, H/2 - areaH/2, areaW, areaH); // Izq
ctx.strokeRect(W-areaW, H/2 - areaH/2, areaW, areaH); // Der
// Arcos (red)
ctx.fillStyle = "rgba(255,255,255,0.2)";
ctx.fillRect(0, H/2 - GOAL_W/2, 20, GOAL_W);
ctx.fillRect(W-20, H/2 - GOAL_W/2, 20, GOAL_W);
// Postes
ctx.fillStyle = "white";
ctx.beginPath(); ctx.arc(20, H/2 - GOAL_W/2, 4, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(20, H/2 + GOAL_W/2, 4, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(W-20, H/2 - GOAL_W/2, 4, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(W-20, H/2 + GOAL_W/2, 4, 0, Math.PI*2); ctx.fill();
// 2. Sombras Jugadores
ctx.fillStyle = "rgba(0,0,0,0.4)";
state.players.forEach(p => {
ctx.beginPath(); ctx.arc(p.x + 3, p.y + 3, PLAYER_R, 0, Math.PI*2); ctx.fill();
});
// 3. Jugadores
state.players.forEach((p, i) => {
// Cuerpo
ctx.beginPath();
ctx.arc(p.x, p.y, PLAYER_R, 0, Math.PI*2);
ctx.fillStyle = p.color;
ctx.fill();
// Borde
ctx.strokeStyle = (p.team === 0 && i === state.controlledPlayer) ? "#ffff00" : "#000";
ctx.lineWidth = (p.team === 0 && i === state.controlledPlayer) ? 3 : 1;
ctx.stroke();
// Numero/Detalle
ctx.fillStyle = p.sColor;
ctx.font = "bold 12px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(p.role === 'GK' ? "1" : (i+2), p.x, p.y);
// Marcador jugador controlado
if (p.team === 0 && i === state.controlledPlayer) {
ctx.beginPath();
ctx.moveTo(p.x - 5, p.y - 25);
ctx.lineTo(p.x + 5, p.y - 25);
ctx.lineTo(p.x, p.y - 18);
ctx.fillStyle = "#ffff00";
ctx.fill();
}
});
// 4. Balon
// Sombra balon
ctx.fillStyle = "rgba(0,0,0,0.3)";
ctx.beginPath(); ctx.arc(state.ball.x + 2, state.ball.y + 2, BALL_R, 0, Math.PI*2); ctx.fill();
// Bola
ctx.fillStyle = "white";
ctx.beginPath(); ctx.arc(state.ball.x, state.ball.y, BALL_R, 0, Math.PI*2); ctx.fill();
// Parches negros (estilo clasico)
ctx.fillStyle = "black";
ctx.beginPath(); ctx.arc(state.ball.x + 2, state.ball.y - 2, 2, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(state.ball.x - 3, state.ball.y + 1, 2, 0, Math.PI*2); ctx.fill();
// 5. HUD Barra de Potencia
if (keys['Space']) {
const p = state.players[state.controlledPlayer];
const power = Math.min((Date.now() - spacePressedTime) / 1000, 1.0);
ctx.fillStyle = "red";
ctx.fillRect(p.x - 15, p.y + 20, 30 * power, 4);
ctx.strokeStyle = "white";
ctx.strokeRect(p.x - 15, p.y + 20, 30, 4);
}
}
let lastTime = 0;
function gameLoop() {
if (state.mode === 'PLAY') {
let now = Date.now();
let dt = (now - lastTime) / 1000;
lastTime = now;
state.time -= dt;
let mins = Math.floor(state.time / 60);
let secs = Math.floor(state.time % 60);
document.getElementById('timer').innerText = `${mins}:${secs < 10 ? '0'+secs : secs}`;
if (state.time <= 0) endGame();
updatePhysics();
}
draw();
requestAnimationFrame(gameLoop);
}
/** --- MENU LOGICA --- **/
function startFlow(type) {
document.getElementById('main-menu').classList.add('hidden');
document.getElementById('league-select').classList.remove('hidden');
state.selectionStep = 0; // Elegir Liga PROPIA
document.getElementById('league-title').innerText = "1. Elegí la Liga de TU Equipo";
renderLeagues();
}
function renderLeagues() {
const list = document.getElementById('league-list');
list.innerHTML = "";
Object.keys(DATABASE).forEach(key => {
let div = document.createElement('div');
div.className = 'list-item';
div.innerText = DATABASE[key].name;
div.onclick = () => selectLeague(key);
list.appendChild(div);
});
}
function selectLeague(key) {
const teams = DATABASE[key].teams;
if (state.selectionStep === 0) { // Eligiendo mi liga
state.tempSelection.myLeague = teams;
state.selectionStep = 1;
document.getElementById('league-select').classList.add('hidden');
document.getElementById('team-select').classList.remove('hidden');
document.getElementById('team-title').innerText = "2. Elegí TU Equipo";
renderTeams(teams);
}
else if (state.selectionStep === 2) { // Eligiendo liga rival
state.tempSelection.rivalLeague = teams;
state.selectionStep = 3;
document.getElementById('league-select').classList.add('hidden');
document.getElementById('team-select').classList.remove('hidden');
document.getElementById('team-title').innerText = "4. Elegí Equipo RIVAL";
renderTeams(teams);
}
}
function renderTeams(teamList) {
const list = document.getElementById('team-list');
list.innerHTML = "";
teamList.forEach(t => {
let div = document.createElement('div');
div.className = 'list-item';
div.innerText = t;
div.style.borderLeft = `5px solid ${getColors(t)[0]}`;
div.onclick = () => selectTeam(t);
list.appendChild(div);
});
}
function selectTeam(t) {
if (state.selectionStep === 1) { // Elegí mi equipo
state.tempSelection.myTeam = t;
// Ahora elegir rival
state.selectionStep = 2;
document.getElementById('team-select').classList.add('hidden');
document.getElementById('league-select').classList.remove('hidden');
document.getElementById('league-title').innerText = "3. Elegí Liga del RIVAL";
renderLeagues();
}
else if (state.selectionStep === 3) { // Elegí rival
state.tempSelection.rivalTeam = t;
// Iniciar Juego
initMatch(state.tempSelection.myTeam, state.tempSelection.rivalTeam);
}
}
function backToMain() {
location.reload();
}
function backToLeagues() {
state.selectionStep--;
if (state.selectionStep < 0) state.selectionStep = 0;
document.getElementById('team-select').classList.add('hidden');
document.getElementById('league-select').classList.remove('hidden');
renderLeagues();
}
</script>
</body>
</html>4
3
85KB
95KB
172.0ms
100.0ms
242.0ms