Add: Off-screen indicators

This commit is contained in:
Wizzard 2025-03-17 18:09:06 -04:00
parent a17146fee9
commit 2df1b5a560
2 changed files with 183 additions and 68 deletions

@ -43,6 +43,10 @@
<input type="checkbox" onclick="toggleHealth()" id="healthCheck" name="health" checked /> <input type="checkbox" onclick="toggleHealth()" id="healthCheck" name="health" checked />
<label for="healthCheck">Display Health</label> <label for="healthCheck">Display Health</label>
</div> </div>
<div>
<input type="checkbox" onclick="toggleOffscreenIndicators()" id="offscreenCheck" name="offscreen" checked />
<label for="offscreenCheck">Off-screen Indicators</label>
</div>
<div> <div>
<input type="checkbox" onclick="toggleRotate()" id="rotateCheck" name="rotate" checked /> <input type="checkbox" onclick="toggleRotate()" id="rotateCheck" name="rotate" checked />
<label for="rotateCheck">Rotate Map</label> <label for="rotateCheck">Rotate Map</label>

@ -5,13 +5,17 @@ const enemyColor = "#ec040b"
const bombColor = "#eda338" const bombColor = "#eda338"
const textColor = "#d1d1d1" const textColor = "#d1d1d1"
const DEFAULT_TEXT_SIZE = 1.2;
const DEFAULT_ENTITY_SIZE = 1.5;
const DEFAULT_ZOOM_LEVEL = 1.3;
// Settings // Settings
let shouldZoom = false; let shouldZoom = false;
let rotateMap = true; let rotateMap = true;
let playerCentered = true; let playerCentered = true;
let showOffscreenIndicators = true;
let drawHealth = true; let drawHealth = true;
let drawStats = true; let drawStats = true;
let drawNames = true; let drawNames = true;
let drawGuns = true; let drawGuns = true;
@ -22,10 +26,7 @@ let minTextSize = 16;
let minEntitySize = 10; let minEntitySize = 10;
let textSizeMultiplier = 1.0; let textSizeMultiplier = 1.0;
let entitySizeMultiplier = 1.0; let entitySizeMultiplier = 1.0;
let playerCenteredZoom = 1.0;
const DEFAULT_TEXT_SIZE = 0.4;
const DEFAULT_ENTITY_SIZE = 1.2;
const DEFAULT_ZOOM_LEVEL = 2.4;
const NETWORK_SETTINGS = { const NETWORK_SETTINGS = {
useInterpolation: true, useInterpolation: true,
@ -53,6 +54,7 @@ let lastKnownPositions = {};
let entityInterpolationData = {}; let entityInterpolationData = {};
let lastUpdateTime = 0; let lastUpdateTime = 0;
let networkLatencyHistory = []; let networkLatencyHistory = [];
let lastPingSent = 0;
let focusedPlayerYaw = 0; let focusedPlayerYaw = 0;
let focusedPlayerName = "YOU"; let focusedPlayerName = "YOU";
@ -534,6 +536,11 @@ function updateZoomSliderVisibility() {
} }
} }
function toggleOffscreenIndicators() {
showOffscreenIndicators = !showOffscreenIndicators;
localStorage.setItem('showOffscreenIndicators', showOffscreenIndicators ? 'true' : 'false');
}
function drawPlayerHealth(pos, playerType, health, hasBomb) { function drawPlayerHealth(pos, playerType, health, hasBomb) {
if (!map) return; if (!map) return;
@ -589,6 +596,8 @@ function drawEntities() {
height: canvas.height + 100 height: canvas.height + 100
}; };
const offscreenEnemies = [];
entityData.forEach((entity, index) => { entityData.forEach((entity, index) => {
const entityId = `entity_${index}`; const entityId = `entity_${index}`;
let interpolatedEntity = null; let interpolatedEntity = null;
@ -620,80 +629,178 @@ function drawEntities() {
mapPos.y >= clipRect.y && mapPos.y >= clipRect.y &&
mapPos.y <= clipRect.y + clipRect.height; mapPos.y <= clipRect.y + clipRect.height;
if (!isVisible) return; if (!isVisible && renderEntity.Player &&
renderEntity.Player.playerType === "Enemy" &&
playerCentered && showOffscreenIndicators) {
if (renderEntity.Bomb) { offscreenEnemies.push({
drawBomb(renderEntity.Bomb.pos, renderEntity.Bomb.isPlanted); pos: mapPos,
} else if (renderEntity.Player) { originalPos: pos,
const player = renderEntity.Player; player: renderEntity.Player
let fillStyle = localColor; });
}
switch (player.playerType) { if (isVisible) {
case "Team": fillStyle = teamColor; break; if (renderEntity.Bomb) {
case "Enemy": fillStyle = enemyColor; break; drawBomb(renderEntity.Bomb.pos, renderEntity.Bomb.isPlanted);
} } else if (renderEntity.Player) {
const player = renderEntity.Player;
let fillStyle = localColor;
drawEntity( switch (player.playerType) {
player.pos, case "Team": fillStyle = teamColor; break;
fillStyle, case "Enemy": fillStyle = enemyColor; break;
player.isDormant,
player.hasBomb,
player.yaw,
player.hasAwp,
player.playerType,
player.isScoped,
player.playerName,
false,
player.weaponId
);
if (!player.isDormant) {
if (drawNames) {
drawPlayerName(
player.pos,
player.playerName,
player.playerType,
player.hasAwp,
player.hasBomb,
player.isScoped
);
} }
if (drawGuns) { drawEntity(
drawPlayerWeapon( player.pos,
player.pos, fillStyle,
player.playerType, player.isDormant,
player.weaponId player.hasBomb,
); player.yaw,
} player.hasAwp,
player.playerType,
player.isScoped,
player.playerName,
false,
player.weaponId
);
if (player.hasBomb) { if (!player.isDormant) {
drawPlayerBomb( if (drawNames) {
player.pos, drawPlayerName(
player.playerType player.pos,
); player.playerName,
} player.playerType,
player.hasAwp,
player.hasBomb,
player.isScoped
);
}
if (drawMoney && typeof player.money === 'number') { if (drawGuns) {
drawPlayerMoney( drawPlayerWeapon(
player.pos, player.pos,
player.playerType, player.playerType,
player.money, player.weaponId
player.hasBomb );
); }
}
if (drawHealth && typeof player.health === 'number') { if (player.hasBomb) {
drawPlayerHealth( drawPlayerBomb(
player.pos, player.pos,
player.playerType, player.playerType
player.health, );
player.hasBomb }
);
if (drawMoney && typeof player.money === 'number') {
drawPlayerMoney(
player.pos,
player.playerType,
player.money,
player.hasBomb
);
}
if (drawHealth && typeof player.health === 'number') {
drawPlayerHealth(
player.pos,
player.playerType,
player.health,
player.hasBomb
);
}
} }
} }
} }
}); });
if (playerCentered && showOffscreenIndicators) {
drawOffscreenIndicators(offscreenEnemies);
}
}
function drawOffscreenIndicators(offscreenEnemies) {
if (!offscreenEnemies.length) return;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const padding = 40;
offscreenEnemies.forEach(enemy => {
const dx = enemy.pos.x - centerX;
const dy = enemy.pos.y - centerY;
let angle = Math.atan2(dy, dx);
const indicatorRadius = Math.min(canvas.width, canvas.height) / 2 - padding;
let indicatorX = centerX + Math.cos(angle) * indicatorRadius;
let indicatorY = centerY + Math.sin(angle) * indicatorRadius;
const distance = Math.sqrt(dx * dx + dy * dy);
const maxDistance = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height);
const opacity = 0.4 + (1 - Math.min(distance / maxDistance, 1)) * 0.6;
drawOffscreenIndicator(
indicatorX,
indicatorY,
angle,
enemyColor,
opacity,
enemy.player
);
});
}
function drawOffscreenIndicator(x, y, angle, color, opacity, player) {
const size = 14 * entitySizeMultiplier;
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(size, 0);
ctx.lineTo(-size / 2, -size / 2);
ctx.lineTo(-size / 2, size / 2);
ctx.closePath();
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${opacity})`;
ctx.fill();
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
if (player.hasAwp) {
ctx.beginPath();
ctx.arc(-size / 2, 0, size / 4, 0, Math.PI * 2);
ctx.fillStyle = 'orange';
ctx.fill();
ctx.stroke();
}
if (drawHealth && typeof player.health === 'number') {
let healthColor;
if (player.health > 70) {
healthColor = "#32CD32";
} else if (player.health > 30) {
healthColor = "#FFFF00";
} else {
healthColor = "#FF0000";
}
ctx.beginPath();
ctx.arc(-size / 2, -size / 2, size / 4, 0, Math.PI * 2);
ctx.fillStyle = healthColor;
ctx.fill();
ctx.stroke();
}
ctx.restore();
} }
function drawBombTimer() { function drawBombTimer() {
@ -1367,6 +1474,9 @@ addEventListener("DOMContentLoaded", () => {
const savedEntitySize = localStorage.getItem('entitySizeMultiplier'); const savedEntitySize = localStorage.getItem('entitySizeMultiplier');
entitySizeMultiplier = savedEntitySize !== null ? parseFloat(savedEntitySize) : DEFAULT_ENTITY_SIZE; entitySizeMultiplier = savedEntitySize !== null ? parseFloat(savedEntitySize) : DEFAULT_ENTITY_SIZE;
const savedOffscreenIndicators = localStorage.getItem('showOffscreenIndicators');
showOffscreenIndicators = savedOffscreenIndicators !== null ? savedOffscreenIndicators === 'true' : true;
const checkboxes = { const checkboxes = {
"zoomCheck": false, "zoomCheck": false,
"statsCheck": true, "statsCheck": true,
@ -1376,7 +1486,8 @@ addEventListener("DOMContentLoaded", () => {
"moneyReveal": false, "moneyReveal": false,
"rotateCheck": true, "rotateCheck": true,
"centerCheck": true, "centerCheck": true,
"healthCheck": drawHealth "healthCheck": drawHealth,
"offscreenCheck": showOffscreenIndicators
}; };
Object.entries(checkboxes).forEach(([id, state]) => { Object.entries(checkboxes).forEach(([id, state]) => {