231 lines
7.9 KiB
JavaScript
231 lines
7.9 KiB
JavaScript
// main.js — point d'entree client, init Pixi et handlers reseau
|
|
|
|
import { Application, Container } from 'pixi.js';
|
|
import { connect, send, on } from './network.js';
|
|
import { showLeaderboard, hideLeaderboard } from './leaderboard.js';
|
|
import { updateIsoLayout, drawStaticArena, updatePlayers, updateProjectiles, updateEnemies, updateAoeZones, updateCamera, screenToWorld } from './renderer.js';
|
|
import { loadArenaMap } from './renderArena.js';
|
|
import { startInputTracking, isInputBlocked } from './input.js';
|
|
import { updatePlayerHud, updateSoulgateBar, updateWaveInfo, updateBossBar, updateUpgradePanel, checkGameEnd } from './hud.js';
|
|
import { bindEvents } from './bindings.js';
|
|
import { loadKaelAssets, loadSerisAssets, loadAldricAssets } from './renderPlayers.js';
|
|
import { loadFractureAssets, loadRampantAssets, loadColosseAssets, loadEclatAssets, loadVexarisAssets } from './renderEnemies.js';
|
|
|
|
let localUsername = null;
|
|
let localId = null;
|
|
let isHost = false;
|
|
let lobbyCode = '';
|
|
let camX = 0, camY = 0;
|
|
let gameStartTime = null;
|
|
|
|
|
|
async function main() {
|
|
const app = new Application();
|
|
await app.init({
|
|
canvas: document.getElementById('game-canvas'),
|
|
resizeTo: window,
|
|
backgroundAlpha: 0,
|
|
antialias: true,
|
|
resolution: window.devicePixelRatio || 1,
|
|
autoDensity: true,
|
|
});
|
|
|
|
let worldContainer = null;
|
|
let layerArena = null;
|
|
let layerAoe = null;
|
|
let layerEnemies = null;
|
|
let layerEntities = null;
|
|
let layerProjectiles = null;
|
|
|
|
const playerPool = {};
|
|
const projPool = {};
|
|
const enemyPool = {};
|
|
const aoePool = {};
|
|
|
|
async function initGameWorld() {
|
|
await loadArenaMap();
|
|
await loadKaelAssets();
|
|
await loadSerisAssets();
|
|
await loadAldricAssets();
|
|
await loadFractureAssets();
|
|
await loadRampantAssets();
|
|
await loadColosseAssets();
|
|
await loadEclatAssets();
|
|
await loadVexarisAssets();
|
|
|
|
worldContainer = new Container();
|
|
layerArena = new Container();
|
|
layerAoe = new Container();
|
|
layerEnemies = new Container();
|
|
layerEntities = new Container();
|
|
layerProjectiles = new Container();
|
|
|
|
// ordre d'affichage : arene tout en bas, projectiles tout en haut
|
|
worldContainer.addChild(layerArena, layerAoe, layerEnemies, layerEntities, layerProjectiles);
|
|
app.stage.addChild(worldContainer);
|
|
|
|
updateIsoLayout(app.screen.width, app.screen.height);
|
|
|
|
layerArena.removeChildren();
|
|
drawStaticArena(layerArena);
|
|
|
|
updateCamera(worldContainer, app.screen.width, app.screen.height, camX, camY);
|
|
|
|
app.renderer.on('resize', (w, h) => {
|
|
updateIsoLayout(w, h);
|
|
layerArena.removeChildren();
|
|
drawStaticArena(layerArena);
|
|
updateCamera(worldContainer, w, h, camX, camY);
|
|
});
|
|
}
|
|
|
|
connect();
|
|
|
|
on('_open', () => setStatus('ok', 'Connected'));
|
|
on('_close', () => setStatus('err', 'Disconnected'));
|
|
|
|
on('username_set', (msg) => {
|
|
if (msg.my_id) localId = msg.my_id;
|
|
document.getElementById('home-buttons').classList.remove('hidden');
|
|
document.getElementById('home-username').classList.add('hidden');
|
|
});
|
|
|
|
on('lobby_created', (msg) => {
|
|
isHost = true;
|
|
lobbyCode = msg.code;
|
|
document.getElementById('code-display').textContent = msg.code;
|
|
document.getElementById('start-btn').classList.remove('hidden');
|
|
switchToLobby();
|
|
notify('Lobby created — code: ' + msg.code);
|
|
});
|
|
|
|
on('lobby_joined', (msg) => {
|
|
lobbyCode = msg.code;
|
|
switchToLobby();
|
|
document.getElementById('code-display').textContent = msg.code;
|
|
notify('Joined lobby ' + msg.code);
|
|
});
|
|
|
|
on('player_joined', (msg) => notify(msg.player.username + ' joined'));
|
|
|
|
on('player_ready', () => {
|
|
const btn = document.getElementById('ready-btn');
|
|
btn.textContent = 'READY!';
|
|
btn.classList.add('mc-btn-gold');
|
|
btn.disabled = true;
|
|
});
|
|
|
|
on('game_starting', async () => {
|
|
gameStartTime = Date.now();
|
|
document.getElementById('home-screen').classList.add('hidden');
|
|
document.getElementById('lobby-screen').classList.add('hidden');
|
|
document.getElementById('loading-screen').classList.remove('hidden');
|
|
|
|
await initGameWorld();
|
|
|
|
document.getElementById('loading-screen').classList.add('hidden');
|
|
|
|
['player-hud', 'soulgate-hud', 'wave-hud', 'fullscreen-btn'].forEach(id =>
|
|
document.getElementById(id).classList.remove('hidden')
|
|
);
|
|
|
|
const getTarget = () => screenToWorld(mouseX, mouseY, worldContainer.x, worldContainer.y);
|
|
startInputTracking(getTarget);
|
|
|
|
app.canvas.addEventListener('click', (e) => {
|
|
if (isInputBlocked()) return;
|
|
const { wx, wy } = screenToWorld(e.clientX, e.clientY, worldContainer.x, worldContainer.y);
|
|
send('attack', { tx: wx, ty: wy });
|
|
});
|
|
|
|
app.canvas.addEventListener('contextmenu', e => e.preventDefault());
|
|
});
|
|
|
|
on('game_state', (msg) => {
|
|
if (!worldContainer) return;
|
|
|
|
updatePlayers(layerEntities, playerPool, msg.players);
|
|
updateEnemies(layerEnemies, enemyPool, msg.enemies);
|
|
updateProjectiles(layerProjectiles, projPool, msg.projectiles);
|
|
updateAoeZones(layerAoe, aoePool, msg.aoe_zones ?? []);
|
|
|
|
// retrouver le joueur local : par id si dispo (fiable meme avec pseudos en doublon), sinon par username
|
|
const local = localId
|
|
? msg.players.find(p => p.id === localId)
|
|
: localUsername
|
|
? msg.players.find(p => p.username === localUsername)
|
|
: null;
|
|
|
|
if (local) {
|
|
camX = local.x;
|
|
camY = local.y;
|
|
updateCamera(worldContainer, app.screen.width, app.screen.height, camX, camY);
|
|
updatePlayerHud(local);
|
|
}
|
|
|
|
updateSoulgateBar(msg.soulgate);
|
|
updateWaveInfo(msg.wave);
|
|
updateBossBar(msg.wave);
|
|
updateUpgradePanel(msg.wave, local);
|
|
checkGameEnd(msg, gameStartTime, isHost, lobbyCode, localId);
|
|
});
|
|
|
|
on('error', (msg) => notify(msg.message, true));
|
|
|
|
bindEvents({
|
|
setUsername: (v) => { localUsername = v; },
|
|
switchToHome,
|
|
notify,
|
|
showLeaderboard,
|
|
hideLeaderboard,
|
|
});
|
|
}
|
|
|
|
|
|
let mouseX = 0, mouseY = 0;
|
|
document.addEventListener('mousemove', e => {
|
|
mouseX = e.clientX;
|
|
mouseY = e.clientY;
|
|
});
|
|
|
|
|
|
function switchToLobby() {
|
|
document.getElementById('home-screen').classList.add('hidden');
|
|
document.getElementById('lobby-screen').classList.remove('hidden');
|
|
}
|
|
|
|
function switchToHome() {
|
|
isHost = false;
|
|
lobbyCode = '';
|
|
document.getElementById('lobby-screen').classList.add('hidden');
|
|
document.getElementById('home-screen').classList.remove('hidden');
|
|
document.getElementById('home-buttons').classList.remove('hidden');
|
|
document.getElementById('home-username').classList.add('hidden');
|
|
document.getElementById('join-row').classList.add('hidden');
|
|
document.getElementById('code-input').value = '';
|
|
document.getElementById('code-display').textContent = '------';
|
|
const readyBtn = document.getElementById('ready-btn');
|
|
readyBtn.disabled = true;
|
|
readyBtn.textContent = 'Ready';
|
|
readyBtn.classList.remove('mc-btn-gold');
|
|
document.getElementById('start-btn').classList.add('hidden');
|
|
document.querySelectorAll('.class-btn').forEach(b => b.classList.remove('active'));
|
|
}
|
|
|
|
|
|
function setStatus(cls, text) {
|
|
const el = document.getElementById('home-status');
|
|
el.className = 'home-status ' + cls;
|
|
el.textContent = text;
|
|
}
|
|
|
|
function notify(text, isError = false) {
|
|
const el = document.getElementById('overlay-msg');
|
|
if (!el) return;
|
|
el.textContent = text;
|
|
el.className = 'msg' + (isError ? ' err' : '');
|
|
}
|
|
|
|
|
|
main().catch(console.error);
|