Render authenticated multiplayer presence
This commit is contained in:
parent
7b90701434
commit
74ecc68b17
@ -144,6 +144,8 @@ class GameScene extends Phaser.Scene {
|
||||
this.tradeDeliveries = 0;
|
||||
this.tradeLosses = 0;
|
||||
this.playerTradeLosses = 0;
|
||||
this.remotePlayers = new Map();
|
||||
this.multiplayerSendAccumulatorMs = 0;
|
||||
|
||||
airshipLog('scene:init', {
|
||||
hull: this.playerHull,
|
||||
@ -182,6 +184,11 @@ class GameScene extends Phaser.Scene {
|
||||
this.player.setFrame(0);
|
||||
this.createPlayerSmoke();
|
||||
|
||||
this.handleMultiplayerSnapshot = (event) => {
|
||||
this.syncRemotePlayers(event.detail?.players || []);
|
||||
};
|
||||
window.addEventListener('airship:multiplayer-snapshot', this.handleMultiplayerSnapshot);
|
||||
|
||||
this.pirates = this.physics.add.group();
|
||||
this.merchants = this.physics.add.group();
|
||||
this.playerShots = this.physics.add.group();
|
||||
@ -276,6 +283,12 @@ class GameScene extends Phaser.Scene {
|
||||
registerDebugSnapshot(null);
|
||||
window.removeEventListener('airship:helm-vector', this.handleHelmVector);
|
||||
window.removeEventListener('airship:action', this.handleMobileAction);
|
||||
window.removeEventListener('airship:multiplayer-snapshot', this.handleMultiplayerSnapshot);
|
||||
for (const remote of this.remotePlayers.values()) {
|
||||
remote.sprite?.destroy();
|
||||
remote.label?.destroy();
|
||||
}
|
||||
this.remotePlayers.clear();
|
||||
airshipLog('scene:shutdown', {
|
||||
gameState: this.gameState,
|
||||
hull: this.playerHull,
|
||||
@ -1401,6 +1414,7 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
this.updateProgressionInteraction();
|
||||
this.updateMultiplayer(deltaMs);
|
||||
if (this.dockOpen) {
|
||||
this.player.setVelocity(0, 0);
|
||||
const hudState = this.buildHudState();
|
||||
@ -1437,6 +1451,85 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
syncRemotePlayers(players = []) {
|
||||
const seen = new Set();
|
||||
|
||||
for (const state of players) {
|
||||
if (!state?.id) continue;
|
||||
seen.add(state.id);
|
||||
|
||||
let remote = this.remotePlayers.get(state.id);
|
||||
if (!remote) {
|
||||
const sprite = this.add.sprite(
|
||||
Number(state.x) || this.world.spawn.x,
|
||||
Number(state.y) || this.world.spawn.y,
|
||||
'player-airship',
|
||||
0,
|
||||
);
|
||||
sprite
|
||||
.setDepth(5.5)
|
||||
.setDisplaySize(60, 114)
|
||||
.setTint(0x8cd3ff)
|
||||
.setAlpha(0.86);
|
||||
sprite.play('player-forward');
|
||||
sprite.anims.timeScale = 0.72;
|
||||
|
||||
const label = this.add.text(sprite.x, sprite.y - 70, state.name || 'CAPTAIN', {
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '10px',
|
||||
color: '#bfe6ff',
|
||||
backgroundColor: '#071018aa',
|
||||
padding: { x: 4, y: 2 },
|
||||
}).setOrigin(0.5).setDepth(12);
|
||||
|
||||
remote = {
|
||||
sprite,
|
||||
label,
|
||||
targetX: sprite.x,
|
||||
targetY: sprite.y,
|
||||
targetAngle: Number(state.angle) || 0,
|
||||
hull: Number(state.hull) || 100,
|
||||
};
|
||||
this.remotePlayers.set(state.id, remote);
|
||||
}
|
||||
|
||||
remote.targetX = clamp(Number(state.x) || 0, 0, this.world.width);
|
||||
remote.targetY = clamp(Number(state.y) || 0, 0, this.world.height);
|
||||
remote.targetAngle = normalizeDegrees(Number(state.angle) || 0);
|
||||
remote.hull = Math.max(0, Number(state.hull) || 0);
|
||||
remote.label.setText(`${state.name || 'CAPTAIN'} ${Math.round(remote.hull)}`);
|
||||
}
|
||||
|
||||
for (const [id, remote] of this.remotePlayers) {
|
||||
if (seen.has(id)) continue;
|
||||
remote.sprite?.destroy();
|
||||
remote.label?.destroy();
|
||||
this.remotePlayers.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
updateMultiplayer(deltaMs) {
|
||||
this.multiplayerSendAccumulatorMs += deltaMs;
|
||||
if (this.multiplayerSendAccumulatorMs >= 100) {
|
||||
this.multiplayerSendAccumulatorMs %= 100;
|
||||
window.airshipMultiplayer?.sendState?.({
|
||||
x: this.player?.x || 0,
|
||||
y: this.player?.y || 0,
|
||||
angle: this.player?.angle || 0,
|
||||
hull: this.playerHull,
|
||||
});
|
||||
}
|
||||
|
||||
for (const remote of this.remotePlayers.values()) {
|
||||
const sprite = remote.sprite;
|
||||
if (!sprite?.active) continue;
|
||||
sprite.x = Phaser.Math.Linear(sprite.x, remote.targetX, 0.32);
|
||||
sprite.y = Phaser.Math.Linear(sprite.y, remote.targetY, 0.32);
|
||||
sprite.angle += signedAngleDelta(remote.targetAngle, sprite.angle) * 0.32;
|
||||
remote.label.setPosition(sprite.x, sprite.y - 70);
|
||||
}
|
||||
}
|
||||
|
||||
updatePlayer(dt, deltaMs) {
|
||||
if (!this.player?.body) return;
|
||||
const stats = this.playerStats || deriveShipStats(this.progression?.loadout, this.progression?.installedConditions);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user