fix: radar compass always heading-up with rotating N/E/S/W labels, fix reopen bug
- Compass is now always heading-up: player facing direction is fixed pointing up, N/E/S/W labels rotate around the edge as player turns - Fix: reopening a closed radar window now resends start_radar command so streaming resumes without needing a full page refresh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3852cf205e
commit
502467e075
1 changed files with 39 additions and 37 deletions
|
|
@ -3608,7 +3608,14 @@ function showRadarWindow(name) {
|
|||
}
|
||||
);
|
||||
|
||||
if (!isNew) return;
|
||||
if (!isNew) {
|
||||
// Window was hidden, not destroyed — re-register and restart streaming
|
||||
radarWindows[name] = win;
|
||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify({ player_name: name, command: 'start_radar' }));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
radarWindows[name] = win;
|
||||
win.dataset.character = name;
|
||||
|
|
@ -3636,14 +3643,7 @@ function showRadarWindow(name) {
|
|||
rangeLabel.appendChild(rangeSelect);
|
||||
controls.appendChild(rangeLabel);
|
||||
|
||||
const headingToggle = document.createElement('label');
|
||||
headingToggle.className = 'radar-heading-toggle';
|
||||
const headingCheck = document.createElement('input');
|
||||
headingCheck.type = 'checkbox';
|
||||
headingCheck.checked = false;
|
||||
headingToggle.appendChild(headingCheck);
|
||||
headingToggle.appendChild(document.createTextNode(' Heading-up'));
|
||||
controls.appendChild(headingToggle);
|
||||
// Compass is always heading-up (player facing direction = up)
|
||||
|
||||
content.appendChild(controls);
|
||||
|
||||
|
|
@ -3672,7 +3672,6 @@ function showRadarWindow(name) {
|
|||
win._radarCanvas = canvas;
|
||||
win._radarListBody = listBody;
|
||||
win._radarRangeSelect = rangeSelect;
|
||||
win._radarHeadingCheck = headingCheck;
|
||||
|
||||
// Send start_radar command
|
||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||
|
|
@ -3688,7 +3687,6 @@ function updateRadarWindow(msg) {
|
|||
const canvas = win._radarCanvas;
|
||||
const listBody = win._radarListBody;
|
||||
const range = parseFloat(win._radarRangeSelect.value) || RADAR_DEFAULT_RANGE;
|
||||
const headingUp = win._radarHeadingCheck.checked;
|
||||
const objects = msg.objects || [];
|
||||
|
||||
const playerEW = msg.player_ew;
|
||||
|
|
@ -3726,44 +3724,48 @@ function updateRadarWindow(msg) {
|
|||
ctx.moveTo(0, cy); ctx.lineTo(size, cy);
|
||||
ctx.stroke();
|
||||
|
||||
// Heading line (north indicator or player heading)
|
||||
const headingRad = headingUp ? 0 : (-playerHeading * Math.PI / 180);
|
||||
// Always heading-up: player facing direction = up on canvas.
|
||||
// Compass labels rotate around the edge based on player heading.
|
||||
const headingRad = playerHeading * Math.PI / 180;
|
||||
const compassLabels = [
|
||||
{ label: 'N', angle: 0 },
|
||||
{ label: 'E', angle: Math.PI / 2 },
|
||||
{ label: 'S', angle: Math.PI },
|
||||
{ label: 'W', angle: -Math.PI / 2 },
|
||||
];
|
||||
ctx.font = 'bold 12px monospace';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
compassLabels.forEach(({ label, angle }) => {
|
||||
// Rotate compass direction by negative heading so labels move as player turns
|
||||
const a = angle - headingRad;
|
||||
const lx = cx + Math.sin(a) * (cx - 12);
|
||||
const ly = cy - Math.cos(a) * (cx - 12);
|
||||
ctx.fillStyle = label === 'N' ? '#cc4444' : '#888';
|
||||
ctx.fillText(label, lx, ly);
|
||||
});
|
||||
|
||||
// Facing direction indicator (always points up from center)
|
||||
ctx.strokeStyle = '#666';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
const nhx = cx + Math.sin(headingRad) * cx * 0.9;
|
||||
const nhy = cy - Math.cos(headingRad) * cx * 0.9;
|
||||
ctx.moveTo(cx, cy);
|
||||
ctx.lineTo(nhx, nhy);
|
||||
ctx.lineTo(cx, cy - cx * 0.85);
|
||||
ctx.stroke();
|
||||
|
||||
// N label
|
||||
ctx.fillStyle = '#888';
|
||||
ctx.font = '10px monospace';
|
||||
ctx.textAlign = 'center';
|
||||
const nlx = cx + Math.sin(headingRad) * (cx - 10);
|
||||
const nly = cy - Math.cos(headingRad) * (cx - 10);
|
||||
ctx.fillText('N', nlx, nly + 3);
|
||||
|
||||
// Rotation angle for heading-up mode (negate to counter-rotate world)
|
||||
const rotAngle = headingUp ? (-playerHeading * Math.PI / 180) : 0;
|
||||
// Rotation angle: negate heading to counter-rotate world so facing = up
|
||||
const rotAngle = -headingRad;
|
||||
|
||||
// Draw objects
|
||||
objects.forEach(obj => {
|
||||
const dEW = obj.ew - playerEW;
|
||||
const dNS = obj.ns - playerNS;
|
||||
|
||||
// Rotate if heading-up
|
||||
let dx, dy;
|
||||
if (rotAngle !== 0) {
|
||||
const cosA = Math.cos(rotAngle);
|
||||
const sinA = Math.sin(rotAngle);
|
||||
dx = dEW * cosA - dNS * sinA;
|
||||
dy = -(dEW * sinA + dNS * cosA);
|
||||
} else {
|
||||
dx = dEW;
|
||||
dy = -dNS; // NS increases north, canvas Y increases down
|
||||
}
|
||||
// Rotate world by negative heading so player facing = up
|
||||
const cosA = Math.cos(rotAngle);
|
||||
const sinA = Math.sin(rotAngle);
|
||||
const dx = dEW * cosA - dNS * sinA;
|
||||
const dy = -(dEW * sinA + dNS * cosA);
|
||||
|
||||
const px = cx + dx * scale;
|
||||
const py = cy + dy * scale;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue