|
<!DOCTYPE html> |
|
<html lang="ko"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>JET FIGHT SIMULATER - FPS Mode</title> |
|
<style> |
|
body { |
|
margin: 0; |
|
overflow: hidden; |
|
background: #000; |
|
font-family: 'Courier New', monospace; |
|
} |
|
|
|
#loading { |
|
position: fixed; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
background: rgba(0,0,0,0.8); |
|
padding: 20px; |
|
border-radius: 10px; |
|
z-index: 2000; |
|
text-align: center; |
|
} |
|
|
|
.loading-spinner { |
|
width: 50px; |
|
height: 50px; |
|
border: 5px solid #0f0; |
|
border-top: 5px solid transparent; |
|
border-radius: 50%; |
|
animation: spin 1s linear infinite; |
|
margin: 0 auto 20px; |
|
} |
|
|
|
@keyframes spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
|
|
.loading-text { |
|
color: #0f0; |
|
font-size: 24px; |
|
text-align: center; |
|
} |
|
|
|
#gameContainer { |
|
position: relative; |
|
width: 100vw; |
|
height: 100vh; |
|
cursor: none; |
|
} |
|
|
|
|
|
#hudContainer { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
pointer-events: none; |
|
z-index: 1000; |
|
} |
|
|
|
|
|
#hudCrosshair { |
|
position: fixed; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 400px; |
|
height: 400px; |
|
} |
|
|
|
|
|
.hud-aiming-circle { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 150px; |
|
height: 150px; |
|
border: 2px solid rgba(0, 255, 0, 0.5); |
|
border-radius: 50%; |
|
} |
|
|
|
|
|
.hud-center-dot { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 4px; |
|
height: 4px; |
|
background: #00ff00; |
|
border-radius: 50%; |
|
} |
|
|
|
|
|
.hud-horizon-line { |
|
position: absolute; |
|
top: 50%; |
|
left: 20%; |
|
right: 20%; |
|
height: 1px; |
|
background: rgba(0, 255, 0, 0.4); |
|
} |
|
|
|
|
|
.hud-pitch-ladder { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 200px; |
|
height: 400px; |
|
} |
|
|
|
.pitch-line { |
|
position: absolute; |
|
width: 100%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.pitch-line-bar { |
|
width: 60px; |
|
height: 1px; |
|
background: rgba(0, 255, 0, 0.4); |
|
} |
|
|
|
.pitch-line-text { |
|
position: absolute; |
|
color: rgba(0, 255, 0, 0.6); |
|
font-size: 10px; |
|
left: -25px; |
|
} |
|
|
|
|
|
.hud-central-info { |
|
position: absolute; |
|
color: #00ff00; |
|
font-size: 11px; |
|
font-family: 'Courier New', monospace; |
|
text-shadow: 0 0 3px rgba(0, 0, 0, 0.8); |
|
background: rgba(0, 0, 0, 0.3); |
|
padding: 2px 5px; |
|
border-radius: 2px; |
|
} |
|
|
|
|
|
#hudSpeedCentral { |
|
left: -120px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
} |
|
|
|
|
|
#hudAltitudeCentral { |
|
right: -120px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
} |
|
|
|
|
|
#hudHeadingCentral { |
|
top: -30px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
} |
|
|
|
|
|
#hudGForceCentral { |
|
bottom: -30px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
} |
|
|
|
|
|
#hudThrottleCentral { |
|
left: -120px; |
|
top: calc(50% + 25px); |
|
} |
|
|
|
|
|
.target-marker { |
|
position: absolute; |
|
width: 30px; |
|
height: 30px; |
|
border: 2px solid transparent; |
|
transform: translate(-50%, -50%); |
|
} |
|
|
|
.target-marker.in-crosshair { |
|
border: 2px solid #ffff00; |
|
animation: target-pulse 0.5s infinite; |
|
} |
|
|
|
.target-marker.locked { |
|
border: 2px solid #ff0000; |
|
box-shadow: 0 0 10px #ff0000; |
|
} |
|
|
|
.target-marker .target-box { |
|
position: absolute; |
|
top: -5px; |
|
left: -5px; |
|
right: -5px; |
|
bottom: -5px; |
|
border: 1px solid currentColor; |
|
} |
|
|
|
@keyframes target-pulse { |
|
0%, 100% { opacity: 1; } |
|
50% { opacity: 0.5; } |
|
} |
|
|
|
.target-info { |
|
position: absolute; |
|
top: 100%; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
color: #00ff00; |
|
font-size: 10px; |
|
white-space: nowrap; |
|
margin-top: 5px; |
|
} |
|
|
|
#healthBar { |
|
position: absolute; |
|
bottom: 20px; |
|
left: 20px; |
|
width: 200px; |
|
height: 20px; |
|
background: rgba(0,20,0,0.7); |
|
border: 2px solid #0f0; |
|
z-index: 1001; |
|
border-radius: 10px; |
|
overflow: hidden; |
|
} |
|
|
|
#health { |
|
width: 100%; |
|
height: 100%; |
|
background: linear-gradient(90deg, #0f0, #00ff00); |
|
transition: width 0.3s; |
|
} |
|
|
|
#gameTitle { |
|
position: absolute; |
|
top: 60px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
color: #0f0; |
|
background: rgba(0,20,0,0.7); |
|
padding: 10px 20px; |
|
font-size: 20px; |
|
z-index: 1001; |
|
border: 1px solid #0f0; |
|
border-radius: 5px; |
|
text-transform: uppercase; |
|
letter-spacing: 2px; |
|
} |
|
|
|
#weaponDisplay { |
|
position: absolute; |
|
bottom: 20px; |
|
right: 20px; |
|
background: rgba(0,20,0,0.7); |
|
padding: 10px; |
|
z-index: 1001; |
|
border: 1px solid #0f0; |
|
border-radius: 5px; |
|
} |
|
|
|
#ammoDisplay { |
|
color: #0f0; |
|
font-size: 20px; |
|
} |
|
|
|
#radar { |
|
position: absolute; |
|
bottom: 60px; |
|
left: 20px; |
|
width: 200px; |
|
height: 200px; |
|
background: rgba(30, 30, 30, 0.9); |
|
border: 2px solid #0f0; |
|
border-radius: 50%; |
|
z-index: 1001; |
|
overflow: hidden; |
|
} |
|
|
|
|
|
.rwr-display { |
|
position: relative; |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
|
|
.rwr-center { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 15px; |
|
height: 15px; |
|
z-index: 10; |
|
} |
|
|
|
.rwr-aircraft-symbol { |
|
width: 100%; |
|
height: 100%; |
|
position: relative; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.rwr-aircraft-symbol img { |
|
width: 100%; |
|
height: 100%; |
|
object-fit: contain; |
|
filter: drop-shadow(0 0 2px #00ff00); |
|
} |
|
|
|
|
|
.rwr-range-ring { |
|
position: absolute; |
|
border: 1px solid rgba(0, 255, 0, 0.4); |
|
border-radius: 50%; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
} |
|
|
|
.rwr-ring-inner { |
|
width: 60px; |
|
height: 60px; |
|
} |
|
|
|
.rwr-ring-middle { |
|
width: 120px; |
|
height: 120px; |
|
} |
|
|
|
.rwr-ring-outer { |
|
width: 180px; |
|
height: 180px; |
|
} |
|
|
|
|
|
.rwr-center-dot { |
|
position: absolute; |
|
top: calc(50% + 4px); |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 4px; |
|
height: 4px; |
|
background: #00ff00; |
|
border-radius: 50%; |
|
z-index: 11; |
|
} |
|
|
|
|
|
.rwr-threat { |
|
position: absolute; |
|
width: 15px; |
|
height: 15px; |
|
transform: translate(-50%, -50%); |
|
text-align: center; |
|
font-size: 10px; |
|
font-weight: bold; |
|
z-index: 5; |
|
} |
|
|
|
|
|
.rwr-lock-line { |
|
position: absolute; |
|
background: #ff0000; |
|
height: 2px; |
|
transform-origin: left center; |
|
z-index: 4; |
|
animation: lock-pulse 0.5s infinite; |
|
} |
|
|
|
@keyframes lock-pulse { |
|
0%, 100% { opacity: 1; } |
|
50% { opacity: 0.3; } |
|
} |
|
|
|
|
|
.missile-warning-panel { |
|
position: fixed; |
|
top: 50%; |
|
right: 20px; |
|
transform: translateY(-50%); |
|
background: rgba(255, 0, 0, 0.2); |
|
border: 2px solid #ff0000; |
|
border-radius: 5px; |
|
padding: 10px; |
|
z-index: 1500; |
|
min-width: 200px; |
|
} |
|
|
|
.missile-warning-item { |
|
color: #ff0000; |
|
font-size: 16px; |
|
font-weight: bold; |
|
margin: 5px 0; |
|
text-shadow: 0 0 5px #ff0000; |
|
animation: warning-blink 0.3s infinite; |
|
} |
|
|
|
@keyframes warning-blink { |
|
0%, 50% { opacity: 1; } |
|
51%, 100% { opacity: 0.7; } |
|
} |
|
|
|
|
|
.lock-warning-arrow { |
|
position: fixed; |
|
width: 40px; |
|
height: 40px; |
|
z-index: 1400; |
|
pointer-events: none; |
|
} |
|
|
|
.lock-warning-arrow::before { |
|
content: 'β²'; |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
font-size: 30px; |
|
color: #ffff00; |
|
text-shadow: 0 0 10px #ffff00, 0 0 20px #ffff00; |
|
animation: arrow-blink 0.5s infinite; |
|
} |
|
|
|
@keyframes arrow-blink { |
|
0%, 50% { opacity: 1; } |
|
51%, 100% { opacity: 0.3; } |
|
} |
|
|
|
.rwr-direction-text { |
|
position: absolute; |
|
color: #0f0; |
|
font-size: 12px; |
|
font-weight: bold; |
|
transform: translate(-50%, -50%); |
|
text-shadow: 0 0 2px #0f0; |
|
} |
|
|
|
.rwr-north { |
|
top: 15px; |
|
left: 50%; |
|
} |
|
|
|
.rwr-east { |
|
top: 50%; |
|
right: 15px; |
|
left: auto; |
|
transform: translateY(-50%); |
|
} |
|
|
|
.rwr-south { |
|
bottom: 15px; |
|
left: 50%; |
|
top: auto; |
|
transform: translateX(-50%); |
|
} |
|
|
|
.rwr-west { |
|
top: 50%; |
|
left: 15px; |
|
} |
|
|
|
|
|
.rwr-threat { |
|
position: absolute; |
|
width: 15px; |
|
height: 15px; |
|
transform: translate(-50%, -50%); |
|
text-align: center; |
|
font-size: 10px; |
|
font-weight: bold; |
|
z-index: 5; |
|
} |
|
|
|
|
|
.rwr-threat.level-low { |
|
color: #ffff00; |
|
text-shadow: 0 0 3px #ffff00; |
|
} |
|
|
|
.rwr-threat.level-medium { |
|
color: #ff8800; |
|
text-shadow: 0 0 3px #ff8800; |
|
} |
|
|
|
.rwr-threat.level-high { |
|
color: #ff0000; |
|
text-shadow: 0 0 3px #ff0000; |
|
} |
|
|
|
.rwr-threat.missile-lock { |
|
animation: rwr-flash 0.3s infinite; |
|
} |
|
|
|
@keyframes rwr-flash { |
|
0%, 50% { opacity: 1; } |
|
51%, 100% { opacity: 0.3; } |
|
} |
|
|
|
#mission { |
|
position: absolute; |
|
top: 10px; |
|
left: 10px; |
|
color: #0f0; |
|
background: rgba(0,20,0,0.7); |
|
padding: 10px; |
|
font-size: 16px; |
|
z-index: 1001; |
|
border: 1px solid #0f0; |
|
border-radius: 5px; |
|
} |
|
|
|
#radarLine { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
width: 50%; |
|
height: 2px; |
|
background: #0f0; |
|
transform-origin: left center; |
|
animation: radar-sweep 4s infinite linear; |
|
} |
|
|
|
.enemy-dot { |
|
position: absolute; |
|
width: 6px; |
|
height: 6px; |
|
background: #ff0000; |
|
border-radius: 50%; |
|
transform: translate(-50%, -50%); |
|
} |
|
|
|
@keyframes radar-sweep { |
|
from { |
|
transform: rotate(0deg); |
|
} |
|
to { |
|
transform: rotate(360deg); |
|
} |
|
} |
|
|
|
#gameStats { |
|
position: absolute; |
|
top: 10px; |
|
right: 20px; |
|
color: #0f0; |
|
background: rgba(0,20,0,0.7); |
|
padding: 10px; |
|
font-size: 16px; |
|
z-index: 1001; |
|
border: 1px solid #0f0; |
|
border-radius: 5px; |
|
text-align: right; |
|
} |
|
|
|
.start-screen { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: rgba(0,0,0,0.8); |
|
display: none; |
|
justify-content: center; |
|
align-items: center; |
|
flex-direction: column; |
|
z-index: 2000; |
|
} |
|
|
|
.start-button { |
|
padding: 15px 30px; |
|
font-size: 24px; |
|
background: #0f0; |
|
color: #000; |
|
border: none; |
|
border-radius: 5px; |
|
cursor: pointer; |
|
margin-top: 20px; |
|
transition: transform 0.2s; |
|
} |
|
|
|
.start-button:hover { |
|
transform: scale(1.1); |
|
} |
|
|
|
|
|
#hudSpeed, #hudAltitude, #hudHeading, #hudPitch, #hudRoll, #hudTurnRate { |
|
display: none; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
|
|
<div id="loading"> |
|
<div class="loading-spinner"></div> |
|
<div class="loading-text">Loading Fighter Resources...</div> |
|
<div style="color: #0f0; font-size: 16px; margin-top: 10px;"> |
|
<p>Loading Aircraft Models...</p> |
|
<p>Loading Audio Assets...</p> |
|
<p>Preparing Game Environment...</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="start-screen" id="startScreen"> |
|
<h1 style="color: #0f0; font-size: 48px; margin-bottom: 20px;">JET FIGHT SIMULATER</h1> |
|
<button class="start-button" onclick="startGame()">Start Game</button> |
|
<div style="color: #0f0; margin-top: 20px; text-align: center;"> |
|
<p>Controls:</p> |
|
<p>W/S - Throttle Control</p> |
|
<p>A/D - Rudder Control</p> |
|
<p>Mouse - Aircraft Control</p> |
|
<p>Left Click - Fire</p> |
|
<p>F - Deploy Flares</p> |
|
<p>G - Escape Stall</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="gameContainer"> |
|
|
|
<div id="gameTitle" style="display: none;">JET FIGHT SIMULATER</div> |
|
<div id="mission">MISSION: DESTROY ENEMY JET</div> |
|
<div id="gameStats"> |
|
<div id="score">Score: 0</div> |
|
<div id="time">Time: 180s</div> |
|
</div> |
|
|
|
|
|
<div id="hudContainer"> |
|
|
|
<div id="hudCrosshair"> |
|
<div class="hud-aiming-circle"></div> |
|
<div class="hud-center-dot"></div> |
|
<div class="hud-horizon-line"></div> |
|
|
|
|
|
<div class="hud-central-info" id="hudSpeedCentral">SPD: 0 KT</div> |
|
<div class="hud-central-info" id="hudAltitudeCentral">ALT: 0 M</div> |
|
<div class="hud-central-info" id="hudHeadingCentral">HDG: 000Β°</div> |
|
<div class="hud-central-info" id="hudGForceCentral">G: 1.0</div> |
|
<div class="hud-central-info" id="hudThrottleCentral">THR: 60%</div> |
|
|
|
|
|
<div class="hud-pitch-ladder" id="pitchLadder"> |
|
|
|
<div class="pitch-line" style="top: calc(50% - 80px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">40</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% - 60px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">30</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% - 40px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">20</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% - 20px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">10</span> |
|
</div> |
|
|
|
<div class="pitch-line" style="top: 50%;"> |
|
<div class="pitch-line-bar" style="width: 100px; height: 2px; background: rgba(0, 255, 0, 0.8);"></div> |
|
<span class="pitch-line-text" style="color: rgba(0, 255, 0, 0.8); font-weight: bold;">0</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% + 20px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">-10</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% + 40px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">-20</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% + 60px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">-30</span> |
|
</div> |
|
<div class="pitch-line" style="top: calc(50% + 80px);"> |
|
<div class="pitch-line-bar"></div> |
|
<span class="pitch-line-text">-40</span> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="hud-roll-indicator" id="rollIndicator" style=" |
|
position: absolute; |
|
top: -90px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
width: 300px; |
|
height: 35px; |
|
"> |
|
|
|
<div style="position: relative; width: 100%; height: 100%;"> |
|
|
|
<div style=" |
|
position: absolute; |
|
top: 0; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
width: 0; |
|
height: 0; |
|
border-left: 12px solid transparent; |
|
border-right: 12px solid transparent; |
|
border-top: 18px solid #00ff00; |
|
z-index: 2; |
|
"></div> |
|
|
|
<div style=" |
|
position: absolute; |
|
bottom: 5px; |
|
left: 0; |
|
right: 0; |
|
height: 15px; |
|
background: rgba(0, 0, 0, 0.3); |
|
border: 1px solid rgba(0, 255, 0, 0.3); |
|
border-radius: 3px; |
|
"></div> |
|
|
|
<div style=" |
|
position: absolute; |
|
bottom: 5px; |
|
left: 0; |
|
width: 25%; |
|
height: 15px; |
|
background: rgba(255, 0, 0, 0.2); |
|
border-radius: 3px 0 0 3px; |
|
"></div> |
|
<div style=" |
|
position: absolute; |
|
bottom: 5px; |
|
right: 0; |
|
width: 25%; |
|
height: 15px; |
|
background: rgba(255, 0, 0, 0.2); |
|
border-radius: 0 3px 3px 0; |
|
"></div> |
|
|
|
<div style=" |
|
position: absolute; |
|
bottom: 22px; |
|
width: 100%; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: flex-end; |
|
padding: 0 10px; |
|
box-sizing: border-box; |
|
"> |
|
<div style="color: rgba(255, 0, 0, 0.7); font-size: 10px; font-weight: bold;">-60</div> |
|
<div style="position: absolute; left: 25%; transform: translateX(-50%); width: 1px; height: 10px; background: rgba(255, 255, 0, 0.6);"></div> |
|
<div style="position: absolute; left: 25%; transform: translateX(-50%); color: rgba(255, 255, 0, 0.7); font-size: 10px; top: -15px;">-30</div> |
|
<div style="position: absolute; left: 50%; transform: translateX(-50%); width: 2px; height: 12px; background: rgba(0, 255, 0, 0.8);"></div> |
|
<div style="position: absolute; left: 50%; transform: translateX(-50%); color: rgba(0, 255, 0, 1); font-size: 11px; font-weight: bold; top: -15px;">0</div> |
|
<div style="position: absolute; left: 75%; transform: translateX(-50%); width: 1px; height: 10px; background: rgba(255, 255, 0, 0.6);"></div> |
|
<div style="position: absolute; left: 75%; transform: translateX(-50%); color: rgba(255, 255, 0, 0.7); font-size: 10px; top: -15px;">30</div> |
|
<div style="color: rgba(255, 0, 0, 0.7); font-size: 10px; font-weight: bold;">60</div> |
|
</div> |
|
|
|
<div id="currentRollMarker" style=" |
|
position: absolute; |
|
bottom: 5px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
width: 3px; |
|
height: 15px; |
|
background: #00ff00; |
|
transition: left 0.1s; |
|
box-shadow: 0 0 5px #00ff00; |
|
"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="hud-info" id="hudSpeed">SPD: 0 KT</div> |
|
<div class="hud-info" id="hudAltitude">ALT: 0 M</div> |
|
<div class="hud-info" id="hudHeading">HDG: 000Β°</div> |
|
<div class="hud-info" id="hudPitch">PITCH: 0Β°</div> |
|
<div class="hud-info" id="hudRoll">ROLL: 0Β°</div> |
|
<div class="hud-info" id="hudTurnRate">TURN: 0Β°/s</div> |
|
|
|
|
|
<div id="targetMarkers"></div> |
|
</div> |
|
|
|
|
|
<div id="healthBar"> |
|
<div id="health"></div> |
|
</div> |
|
|
|
|
|
<div id="weaponDisplay"> |
|
<div style="color: #0f0; font-size: 14px; margin-bottom: 5px;">R: WEAPON CHANGE</div> |
|
<div id="ammoDisplay">20MM MG: 940</div> |
|
</div> |
|
|
|
|
|
<div id="radar"> |
|
<div class="rwr-display"> |
|
|
|
<div class="rwr-range-ring rwr-ring-inner"></div> |
|
<div class="rwr-range-ring rwr-ring-middle"></div> |
|
<div class="rwr-range-ring rwr-ring-outer"></div> |
|
|
|
|
|
<div class="rwr-direction-marks"> |
|
<div class="rwr-direction-text rwr-north">N</div> |
|
<div class="rwr-direction-text rwr-east">E</div> |
|
<div class="rwr-direction-text rwr-south">S</div> |
|
<div class="rwr-direction-text rwr-west">W</div> |
|
</div> |
|
|
|
|
|
<div class="rwr-center"> |
|
<div class="rwr-aircraft-symbol" id="rwrSymbol"> |
|
|
|
</div> |
|
</div> |
|
|
|
|
|
<div class="rwr-center-dot"></div> |
|
|
|
|
|
<div id="rwrThreats"></div> |
|
</div> |
|
|
|
|
|
<div id="radarLine" style="display: none;"></div> |
|
</div> |
|
</div> |
|
|
|
<script type="importmap"> |
|
{ |
|
"imports": { |
|
"three": "https://unpkg.com/[email protected]/build/three.module.js", |
|
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/" |
|
} |
|
} |
|
</script> |
|
|
|
|
|
<script> |
|
|
|
let gameStarted = false; |
|
|
|
|
|
window.addEventListener('gameReady', function() { |
|
console.log('Game ready - starting HUD updates'); |
|
|
|
|
|
const rwrSymbol = document.getElementById('rwrSymbol'); |
|
if (rwrSymbol) { |
|
|
|
const img = new Image(); |
|
img.src = 'effects/symbol.png'; |
|
img.style.width = '100%'; |
|
img.style.height = '100%'; |
|
img.style.objectFit = 'contain'; |
|
img.style.filter = 'drop-shadow(0 0 2px #00ff00)'; |
|
|
|
img.onload = function() { |
|
console.log('RWR symbol image loaded successfully'); |
|
rwrSymbol.innerHTML = ''; |
|
rwrSymbol.appendChild(img); |
|
}; |
|
|
|
img.onerror = function() { |
|
console.log('RWR symbol image failed to load, using fallback'); |
|
|
|
rwrSymbol.innerHTML = ` |
|
<div style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;"> |
|
<div style="width: 8px; height: 8px; background: #00ff00; border-radius: 50%; box-shadow: 0 0 4px #00ff00;"></div> |
|
</div> |
|
`; |
|
}; |
|
} |
|
|
|
|
|
setTimeout(function() { |
|
const pitchLadder = document.getElementById('pitchLadder'); |
|
if (pitchLadder) { |
|
|
|
pitchLadder.style.position = 'absolute'; |
|
pitchLadder.style.top = 'calc(50% - 200px)'; |
|
pitchLadder.style.left = '50%'; |
|
pitchLadder.style.transform = 'translate(-50%, 0)'; |
|
console.log('Pitch ladder initial position set'); |
|
} |
|
}, 100); |
|
|
|
|
|
setInterval(function() { |
|
if (window.gameInstance && window.gameInstance.fighter && window.gameInstance.fighter.isLoaded) { |
|
const fighter = window.gameInstance.fighter; |
|
|
|
|
|
const speedKnots = Math.round(fighter.speed * 1.94384); |
|
const altitudeMeters = Math.round(fighter.altitude); |
|
const throttlePercent = Math.round(fighter.throttle * 100); |
|
const gForce = fighter.gForce.toFixed(1); |
|
const headingDegrees = Math.round(fighter.getHeadingDegrees()); |
|
|
|
|
|
const hudSpeedCentral = document.getElementById('hudSpeedCentral'); |
|
const hudAltitudeCentral = document.getElementById('hudAltitudeCentral'); |
|
const hudHeadingCentral = document.getElementById('hudHeadingCentral'); |
|
const hudGForceCentral = document.getElementById('hudGForceCentral'); |
|
const hudThrottleCentral = document.getElementById('hudThrottleCentral'); |
|
|
|
if (hudSpeedCentral) hudSpeedCentral.textContent = `SPD: ${speedKnots} KT`; |
|
if (hudAltitudeCentral) hudAltitudeCentral.textContent = `ALT: ${altitudeMeters} M`; |
|
if (hudHeadingCentral) hudHeadingCentral.textContent = `HDG: ${String(headingDegrees).padStart(3, '0')}Β°`; |
|
if (hudGForceCentral) { |
|
hudGForceCentral.textContent = `G: ${gForce}`; |
|
|
|
if (fighter.overG) { |
|
hudGForceCentral.style.color = '#ff0000'; |
|
} else if (parseFloat(gForce) > 7) { |
|
hudGForceCentral.style.color = '#ffff00'; |
|
} else { |
|
hudGForceCentral.style.color = '#00ff00'; |
|
} |
|
} |
|
if (hudThrottleCentral) hudThrottleCentral.textContent = `THR: ${throttlePercent}%`; |
|
|
|
|
|
const pitchLadder = document.getElementById('pitchLadder'); |
|
if (pitchLadder) { |
|
const pitchDegrees = fighter.rotation.x * (180 / Math.PI); |
|
|
|
const pitchOffset = -200 + (-pitchDegrees * 2); |
|
pitchLadder.style.top = `calc(50% + ${pitchOffset}px)`; |
|
} |
|
|
|
|
|
const hudCrosshair = document.getElementById('hudCrosshair'); |
|
if (hudCrosshair && fighter.rotation) { |
|
const rollDegrees = fighter.rotation.z * (180 / Math.PI); |
|
hudCrosshair.style.transform = `translate(-50%, -50%) rotate(${-rollDegrees}deg)`; |
|
} |
|
|
|
|
|
const currentRollMarker = document.getElementById('currentRollMarker'); |
|
const rollIndicator = document.getElementById('rollIndicator'); |
|
if (currentRollMarker && fighter.rotation) { |
|
const rollDegrees = fighter.rotation.z * (180 / Math.PI); |
|
|
|
|
|
const normalizedRoll = (rollDegrees + 60) / 120; |
|
const markerPosition = 10 + (normalizedRoll * 280); |
|
|
|
currentRollMarker.style.left = `${markerPosition}px`; |
|
currentRollMarker.style.transform = 'translateX(-50%)'; |
|
|
|
|
|
if (Math.abs(rollDegrees) > 30) { |
|
currentRollMarker.style.background = '#ff0000'; |
|
currentRollMarker.style.boxShadow = '0 0 8px #ff0000'; |
|
currentRollMarker.style.width = '4px'; |
|
} else { |
|
currentRollMarker.style.background = '#00ff00'; |
|
currentRollMarker.style.boxShadow = '0 0 5px #00ff00'; |
|
currentRollMarker.style.width = '3px'; |
|
} |
|
} |
|
|
|
updateRWR(fighter); |
|
} |
|
}, 16); |
|
}); |
|
|
|
|
|
function updateRWR(fighter) { |
|
const rwrThreats = document.getElementById('rwrThreats'); |
|
if (!rwrThreats || !window.gameInstance) return; |
|
|
|
|
|
rwrThreats.innerHTML = ''; |
|
|
|
|
|
if (window.gameInstance.enemies) { |
|
window.gameInstance.enemies.forEach((enemy, index) => { |
|
if (!enemy.mesh || !enemy.isLoaded) return; |
|
|
|
const distance = fighter.position.distanceTo(enemy.position); |
|
|
|
|
|
if (distance <= 10000) { |
|
|
|
const relativePos = enemy.position.clone().sub(fighter.position); |
|
|
|
|
|
const angle = Math.atan2(relativePos.x, relativePos.z) - fighter.rotation.y; |
|
|
|
|
|
const maxRadius = 90; |
|
const relativeDistance = Math.min(distance / 10000, 1) * maxRadius; |
|
|
|
const x = Math.sin(angle) * relativeDistance + 100; |
|
const y = -Math.cos(angle) * relativeDistance + 100; |
|
|
|
|
|
const threat = document.createElement('div'); |
|
threat.className = 'rwr-threat'; |
|
|
|
|
|
if (distance < 2000) { |
|
threat.classList.add('level-high'); |
|
threat.classList.add('missile-lock'); |
|
threat.textContent = 'β'; |
|
} else if (distance < 5000) { |
|
threat.classList.add('level-medium'); |
|
threat.textContent = 'β'; |
|
} else { |
|
threat.classList.add('level-low'); |
|
threat.textContent = 'β'; |
|
} |
|
|
|
threat.style.left = `${x}px`; |
|
threat.style.top = `${y}px`; |
|
|
|
rwrThreats.appendChild(threat); |
|
|
|
|
|
if (enemy.isLocking && enemy.lockTarget === fighter) { |
|
const lockLine = document.createElement('div'); |
|
lockLine.className = 'rwr-lock-line'; |
|
|
|
|
|
const lineLength = Math.sqrt(Math.pow(x - 100, 2) + Math.pow(y - 100, 2)); |
|
const lineAngle = Math.atan2(y - 100, x - 100); |
|
|
|
lockLine.style.width = `${lineLength}px`; |
|
lockLine.style.left = '100px'; |
|
lockLine.style.top = '100px'; |
|
lockLine.style.transform = `rotate(${lineAngle}rad)`; |
|
|
|
rwrThreats.appendChild(lockLine); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
updateLockWarningArrows(fighter); |
|
|
|
|
|
updateMissileWarnings(fighter); |
|
} |
|
|
|
|
|
function updateLockWarningArrows(fighter) { |
|
|
|
const existingArrows = document.querySelectorAll('.lock-warning-arrow'); |
|
existingArrows.forEach(arrow => arrow.remove()); |
|
|
|
if (!fighter.beingLockedBy || fighter.beingLockedBy.length === 0) return; |
|
|
|
fighter.beingLockedBy.forEach(enemy => { |
|
if (!enemy.position) return; |
|
|
|
|
|
const screenPos = getScreenPosition(enemy.position); |
|
if (screenPos) return; |
|
|
|
|
|
const relativePos = enemy.position.clone().sub(fighter.position); |
|
const angle = Math.atan2(relativePos.x, relativePos.z) - fighter.rotation.y; |
|
|
|
const arrow = document.createElement('div'); |
|
arrow.className = 'lock-warning-arrow'; |
|
|
|
|
|
const screenCenterX = window.innerWidth / 2; |
|
const screenCenterY = window.innerHeight / 2; |
|
const edgeDistance = Math.min(screenCenterX - 100, screenCenterY - 100); |
|
|
|
const arrowX = screenCenterX + Math.sin(angle) * edgeDistance; |
|
const arrowY = screenCenterY - Math.cos(angle) * edgeDistance; |
|
|
|
arrow.style.left = `${arrowX}px`; |
|
arrow.style.top = `${arrowY}px`; |
|
|
|
|
|
const rotationAngle = angle * (180 / Math.PI); |
|
arrow.style.transform = `translate(-50%, -50%) rotate(${rotationAngle}deg)`; |
|
|
|
document.body.appendChild(arrow); |
|
}); |
|
} |
|
|
|
|
|
function updateMissileWarnings(fighter) { |
|
|
|
const existingPanel = document.querySelector('.missile-warning-panel'); |
|
if (existingPanel) existingPanel.remove(); |
|
|
|
if (!fighter.incomingMissiles || fighter.incomingMissiles.length === 0) return; |
|
|
|
const panel = document.createElement('div'); |
|
panel.className = 'missile-warning-panel'; |
|
|
|
fighter.incomingMissiles.forEach((missile, index) => { |
|
if (!missile.position) return; |
|
|
|
const distance = Math.round(fighter.position.distanceTo(missile.position)); |
|
|
|
const warningItem = document.createElement('div'); |
|
warningItem.className = 'missile-warning-item'; |
|
warningItem.textContent = `MISSILE ${index + 1}: ${distance}m`; |
|
|
|
|
|
if (distance < 500) { |
|
warningItem.style.fontSize = '20px'; |
|
warningItem.style.color = '#ff0000'; |
|
warningItem.style.textShadow = '0 0 10px #ff0000, 0 0 20px #ff0000'; |
|
} else if (distance < 1000) { |
|
warningItem.style.fontSize = '18px'; |
|
} |
|
|
|
panel.appendChild(warningItem); |
|
}); |
|
|
|
document.body.appendChild(panel); |
|
} |
|
|
|
|
|
function getScreenPosition(worldPosition) { |
|
if (!window.gameInstance || !window.gameInstance.camera) return null; |
|
|
|
const vector = worldPosition.clone(); |
|
vector.project(window.gameInstance.camera); |
|
|
|
|
|
if (vector.z > 1) return null; |
|
|
|
const x = (vector.x * 0.5 + 0.5) * window.innerWidth; |
|
const y = (-vector.y * 0.5 + 0.5) * window.innerHeight; |
|
|
|
|
|
if (x < 0 || x > window.innerWidth || y < 0 || y > window.innerHeight) { |
|
return null; |
|
} |
|
|
|
return { x, y }; |
|
} |
|
|
|
|
|
window.startGame = function() { |
|
if (!window.gameInstance || !window.gameInstance.isLoaded || !window.gameInstance.isBGMReady) { |
|
console.log('κ²μμ΄ μμ§ μ€λΉλμ§ μμμ΅λλ€...'); |
|
return; |
|
} |
|
|
|
gameStarted = true; |
|
document.getElementById('startScreen').style.display = 'none'; |
|
|
|
|
|
const gameTitle = document.getElementById('gameTitle'); |
|
if (gameTitle) { |
|
gameTitle.style.display = 'none'; |
|
} |
|
|
|
document.body.requestPointerLock(); |
|
|
|
window.gameInstance.startBGM(); |
|
window.gameInstance.startGame(); |
|
} |
|
</script> |
|
|
|
<script src="game.js" type="module"></script> |
|
</body> |
|
</html> |