1203 lines
45 KiB
HTML
1203 lines
45 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||
<title>飞机大战 - 移动端高可用版</title>
|
||
<meta name="theme-color" content="#0f1419">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||
|
||
<style>
|
||
:root {
|
||
/* 深空科技主题色彩系统 */
|
||
--primary-color: #6366f1;
|
||
--primary-light: #8b5cf6;
|
||
--primary-dark: #4f46e5;
|
||
--secondary-color: #10b981;
|
||
--secondary-light: #34d399;
|
||
--accent-color: #f59e0b;
|
||
--accent-light: #fbbf24;
|
||
--danger-color: #ef4444;
|
||
|
||
/* 移动端优化背景色系 */
|
||
--bg-primary: #0f1419;
|
||
--bg-secondary: #1a1d29;
|
||
--bg-tertiary: #252837;
|
||
--bg-elevated: #2d3142;
|
||
|
||
/* 高对比度边框色系 */
|
||
--border-primary: #3d4159;
|
||
--border-secondary: #4a5073;
|
||
--border-highlight: #6366f1;
|
||
|
||
/* 文字色系 */
|
||
--text-primary: #ffffff;
|
||
--text-secondary: #b4b7c9;
|
||
--text-tertiary: #9ca3af;
|
||
--text-disabled: #6b7280;
|
||
|
||
/* 移动端触摸区域尺寸 */
|
||
--touch-target-min: 44px;
|
||
--safe-area-padding: 20px;
|
||
}
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html, body {
|
||
height: 100%;
|
||
overflow-x: hidden;
|
||
-webkit-text-size-adjust: 100%;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Microsoft YaHei UI", sans-serif;
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
touch-action: manipulation;
|
||
}
|
||
|
||
/* PWA 支持的安全区域适配 */
|
||
.safe-area {
|
||
padding-left: env(safe-area-inset-left);
|
||
padding-right: env(safe-area-inset-right);
|
||
padding-top: env(safe-area-inset-top);
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
}
|
||
|
||
/* 动态背景星空效果 */
|
||
.background-constellation {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
z-index: -1;
|
||
}
|
||
|
||
.star {
|
||
position: absolute;
|
||
width: 2px;
|
||
height: 2px;
|
||
background: var(--primary-color);
|
||
border-radius: 50%;
|
||
opacity: 0.6;
|
||
animation: twinkle 3s infinite ease-in-out;
|
||
}
|
||
|
||
.star:nth-child(2n) {
|
||
background: var(--accent-color);
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
.star:nth-child(3n) {
|
||
background: var(--secondary-color);
|
||
animation-delay: 2s;
|
||
}
|
||
|
||
@keyframes twinkle {
|
||
0%, 100% { opacity: 0.3; transform: scale(0.8); }
|
||
50% { opacity: 1; transform: scale(1.2); }
|
||
}
|
||
|
||
/* 主容器 - 全屏布局 */
|
||
.app-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 100vh;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* 状态栏 */
|
||
.status-bar {
|
||
background: rgba(26, 29, 41, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
padding: 8px var(--safe-area-padding);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
color: var(--text-tertiary);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.network-status {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.connection-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: var(--secondary-color);
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; transform: scale(1); }
|
||
50% { opacity: 0.4; transform: scale(1.3); }
|
||
}
|
||
|
||
/* 主内容区域 */
|
||
.main-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: var(--safe-area-padding);
|
||
justify-content: center;
|
||
align-items: center;
|
||
text-align: center;
|
||
position: relative;
|
||
}
|
||
|
||
/* 游戏Logo区域 */
|
||
.game-header {
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.game-logo {
|
||
font-size: clamp(28px, 8vw, 36px);
|
||
font-weight: 800;
|
||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 50%, var(--accent-color) 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
margin-bottom: 12px;
|
||
letter-spacing: 2px;
|
||
animation: logoGlow 4s ease-in-out infinite alternate;
|
||
}
|
||
|
||
@keyframes logoGlow {
|
||
0% { filter: drop-shadow(0 0 5px rgba(99, 102, 241, 0.3)); }
|
||
100% { filter: drop-shadow(0 0 25px rgba(139, 92, 246, 0.6)); }
|
||
}
|
||
|
||
.game-subtitle {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
/* 游戏特色展示 */
|
||
.game-preview {
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border-primary);
|
||
border-radius: 16px;
|
||
padding: 24px;
|
||
margin: 30px 0;
|
||
max-width: 340px;
|
||
width: 100%;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.game-preview::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: -100%;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
|
||
animation: shimmer 3s infinite;
|
||
}
|
||
|
||
@keyframes shimmer {
|
||
0% { left: -100%; }
|
||
100% { left: 100%; }
|
||
}
|
||
|
||
.preview-title {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: var(--text-primary);
|
||
margin-bottom: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.plane-icon {
|
||
font-size: 18px;
|
||
color: var(--accent-color);
|
||
}
|
||
|
||
/* 十字形飞机演示 */
|
||
.cross-plane-display {
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 12px;
|
||
line-height: 1.1;
|
||
background: var(--bg-primary);
|
||
border: 1px solid var(--border-secondary);
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
margin: 16px 0;
|
||
position: relative;
|
||
}
|
||
|
||
.plane-structure {
|
||
color: var(--text-primary);
|
||
text-align: center;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.plane-head { color: var(--accent-color); }
|
||
.plane-wing { color: var(--primary-light); }
|
||
.plane-body { color: var(--primary-color); }
|
||
.plane-tail { color: var(--text-tertiary); }
|
||
|
||
.structure-legend {
|
||
font-size: 10px;
|
||
color: var(--text-tertiary);
|
||
margin-top: 12px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
/* 游戏规则简介 */
|
||
.game-rules-brief {
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.5;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.highlight-text {
|
||
color: var(--accent-light);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* 主操作按钮组 */
|
||
.action-buttons {
|
||
width: 100%;
|
||
max-width: 300px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
margin: 30px 0 20px 0;
|
||
}
|
||
|
||
.btn {
|
||
min-height: var(--touch-target-min);
|
||
border: none;
|
||
border-radius: 12px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
text-decoration: none;
|
||
user-select: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
/* 按钮触摸反馈效果 */
|
||
.btn::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 0;
|
||
height: 0;
|
||
background: rgba(255, 255, 255, 0.3);
|
||
border-radius: 50%;
|
||
transform: translate(-50%, -50%);
|
||
transition: width 0.3s, height 0.3s;
|
||
}
|
||
|
||
.btn:active::before {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
|
||
color: #ffffff;
|
||
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
|
||
}
|
||
|
||
.btn-primary:hover, .btn-primary:focus {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);
|
||
}
|
||
|
||
.btn-primary:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.btn-success {
|
||
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-light));
|
||
color: #ffffff;
|
||
box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
|
||
}
|
||
|
||
.btn-success:hover, .btn-success:focus {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 25px rgba(16, 185, 129, 0.4);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: rgba(99, 102, 241, 0.15);
|
||
color: var(--primary-color);
|
||
border: 1px solid var(--primary-color);
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.btn-secondary:hover, .btn-secondary:focus {
|
||
background: rgba(99, 102, 241, 0.25);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
/* 快速操作区域 */
|
||
.quick-actions {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 12px;
|
||
width: 100%;
|
||
max-width: 300px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.quick-btn {
|
||
min-height: 40px;
|
||
background: var(--bg-tertiary);
|
||
border: 1px solid var(--border-primary);
|
||
border-radius: 10px;
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.quick-btn:hover, .quick-btn:focus {
|
||
background: var(--bg-elevated);
|
||
border-color: var(--border-highlight);
|
||
color: var(--text-primary);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
/* 底部信息栏 */
|
||
.bottom-info {
|
||
background: rgba(26, 29, 41, 0.8);
|
||
backdrop-filter: blur(20px);
|
||
padding: 16px var(--safe-area-padding);
|
||
border-top: 1px solid var(--border-primary);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
.offline-indicator {
|
||
display: none;
|
||
color: var(--danger-color);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.offline .offline-indicator {
|
||
display: block;
|
||
}
|
||
|
||
.offline .connection-dot {
|
||
background: var(--danger-color);
|
||
animation: none;
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.loading-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(15, 20, 25, 0.95);
|
||
backdrop-filter: blur(10px);
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 40px;
|
||
height: 40px;
|
||
border: 3px solid rgba(99, 102, 241, 0.3);
|
||
border-top: 3px solid var(--primary-color);
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
.loading-text {
|
||
margin-top: 16px;
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 响应式设计增强 */
|
||
@media (max-width: 375px) {
|
||
.game-preview {
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.action-buttons {
|
||
max-width: 280px;
|
||
gap: 14px;
|
||
}
|
||
|
||
.btn {
|
||
font-size: 15px;
|
||
min-height: 42px;
|
||
}
|
||
}
|
||
|
||
@media (max-height: 640px) {
|
||
.main-content {
|
||
justify-content: flex-start;
|
||
padding-top: 20px;
|
||
}
|
||
|
||
.game-header {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.game-preview {
|
||
margin: 20px 0;
|
||
padding: 20px;
|
||
}
|
||
}
|
||
|
||
/* 高对比度支持 */
|
||
@media (prefers-contrast: high) {
|
||
:root {
|
||
--text-primary: #ffffff;
|
||
--text-secondary: #e5e5e5;
|
||
--border-primary: #ffffff;
|
||
--bg-secondary: #000000;
|
||
}
|
||
}
|
||
|
||
/* 减少动画偏好 */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
|
||
/* 暗色模式强制支持 */
|
||
@media (prefers-color-scheme: dark) {
|
||
body {
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="safe-area">
|
||
<!-- 动态星空背景 -->
|
||
<div class="background-constellation" id="starField"></div>
|
||
|
||
<!-- 加载遮罩 -->
|
||
<div class="loading-overlay" id="loadingOverlay">
|
||
<div>
|
||
<div class="loading-spinner"></div>
|
||
<div class="loading-text">正在启动游戏...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="app-container">
|
||
<!-- 状态栏 -->
|
||
<header class="status-bar">
|
||
<div class="network-status">
|
||
<div class="connection-dot"></div>
|
||
<span id="networkStatus">在线</span>
|
||
<span class="offline-indicator">离线模式</span>
|
||
</div>
|
||
<div class="app-version">v2.0.0</div>
|
||
</header>
|
||
|
||
<!-- 主内容 -->
|
||
<main class="main-content">
|
||
<header class="game-header">
|
||
<h1 class="game-logo">飞机大战</h1>
|
||
<p class="game-subtitle">十字飞机 • 战略博弈</p>
|
||
</header>
|
||
|
||
<section class="game-preview">
|
||
<h2 class="preview-title">
|
||
<span class="plane-icon">✈</span>
|
||
游戏特色
|
||
</h2>
|
||
|
||
<div class="cross-plane-display">
|
||
<div class="plane-structure">
|
||
十字形飞机结构 (11格):<br><br>
|
||
<span class="plane-head"> ● </span><br>
|
||
<span class="plane-wing"> ◆</span><span class="plane-body">■</span><span class="plane-wing">◆ </span><br>
|
||
<span class="plane-body"> ■ </span><br>
|
||
<span class="plane-wing"> ◆</span><span class="plane-body">■</span><span class="plane-wing">◆ </span><br>
|
||
<span class="plane-tail"> ▲ </span><br>
|
||
<span class="plane-tail"> ▲ </span>
|
||
</div>
|
||
<div class="structure-legend">
|
||
● 机头 (击中摧毁) | ■ 机身 | ◆ 机翼 | ▲ 机尾
|
||
</div>
|
||
</div>
|
||
|
||
<div class="game-rules-brief">
|
||
在 <span class="highlight-text">10×10 网格</span> 中布置 <span class="highlight-text">3架飞机</span><br>
|
||
轮流攻击寻找敌机,<span class="highlight-text">击中机头</span> 即可摧毁整架飞机
|
||
</div>
|
||
</section>
|
||
|
||
<div class="action-buttons">
|
||
<button class="btn btn-primary" id="startGameBtn">
|
||
<span>🎮</span>
|
||
开始游戏
|
||
</button>
|
||
|
||
<button class="btn btn-success" id="quickMatchBtn">
|
||
<span>⚡</span>
|
||
快速匹配
|
||
</button>
|
||
|
||
<button class="btn btn-secondary" id="tutorialBtn">
|
||
<span>📖</span>
|
||
游戏教程
|
||
</button>
|
||
</div>
|
||
|
||
<div class="quick-actions">
|
||
<a href="#" class="quick-btn" id="rankingBtn">
|
||
<span>🏆</span>
|
||
排行榜
|
||
</a>
|
||
<a href="#" class="quick-btn" id="settingsBtn">
|
||
<span>⚙️</span>
|
||
设置
|
||
</a>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- 底部信息栏 -->
|
||
<footer class="bottom-info">
|
||
<div class="game-info">移动端优化版 | 支持离线游戏</div>
|
||
<div class="build-info">Build 2025.03</div>
|
||
</footer>
|
||
</div>
|
||
|
||
<script>
|
||
// 应用状态管理
|
||
class MobileGameApp {
|
||
constructor() {
|
||
this.isOnline = navigator.onLine;
|
||
this.isLoading = false;
|
||
this.touchStartTime = 0;
|
||
|
||
this.initializeApp();
|
||
this.bindEvents();
|
||
this.createStarField();
|
||
this.checkNetworkStatus();
|
||
}
|
||
|
||
initializeApp() {
|
||
// 防止双击缩放
|
||
document.addEventListener('touchstart', this.handleTouchStart.bind(this), {passive: false});
|
||
document.addEventListener('touchend', this.handleTouchEnd.bind(this), {passive: false});
|
||
|
||
// PWA 支持检测
|
||
if ('serviceWorker' in navigator) {
|
||
this.registerServiceWorker();
|
||
}
|
||
|
||
// 页面可见性变化处理
|
||
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
||
|
||
console.log('🎮 移动端飞机大战应用已启动');
|
||
}
|
||
|
||
bindEvents() {
|
||
// 主要按钮事件
|
||
document.getElementById('startGameBtn').addEventListener('click', this.startGame.bind(this));
|
||
document.getElementById('quickMatchBtn').addEventListener('click', this.quickMatch.bind(this));
|
||
document.getElementById('tutorialBtn').addEventListener('click', this.showTutorial.bind(this));
|
||
document.getElementById('rankingBtn').addEventListener('click', this.showRanking.bind(this));
|
||
document.getElementById('settingsBtn').addEventListener('click', this.showSettings.bind(this));
|
||
|
||
// 网络状态监听
|
||
window.addEventListener('online', this.handleOnline.bind(this));
|
||
window.addEventListener('offline', this.handleOffline.bind(this));
|
||
|
||
// 内存警告处理
|
||
if ('memory' in performance) {
|
||
this.monitorMemoryUsage();
|
||
}
|
||
}
|
||
|
||
// 触摸事件处理 - 防止意外操作
|
||
handleTouchStart(e) {
|
||
this.touchStartTime = Date.now();
|
||
|
||
// 防止多点触控导致的缩放
|
||
if (e.touches.length > 1) {
|
||
e.preventDefault();
|
||
}
|
||
}
|
||
|
||
handleTouchEnd(e) {
|
||
const touchDuration = Date.now() - this.touchStartTime;
|
||
|
||
// 处理长按事件
|
||
if (touchDuration > 500) {
|
||
this.handleLongPress(e);
|
||
}
|
||
}
|
||
|
||
handleLongPress(e) {
|
||
// 长按反馈
|
||
if (e.target.classList.contains('btn')) {
|
||
this.showContextMenu(e.target);
|
||
}
|
||
}
|
||
|
||
// 游戏功能实现
|
||
async startGame() {
|
||
this.showLoading('正在准备游戏...');
|
||
|
||
try {
|
||
// 模拟游戏加载过程
|
||
await this.delay(1200);
|
||
|
||
// 检查设备性能
|
||
const deviceInfo = this.getDeviceInfo();
|
||
console.log('设备信息:', deviceInfo);
|
||
|
||
// 跳转到飞机放置界面
|
||
this.navigateToPlacement();
|
||
|
||
} catch (error) {
|
||
this.handleError('游戏启动失败', error);
|
||
} finally {
|
||
this.hideLoading();
|
||
}
|
||
}
|
||
|
||
async quickMatch() {
|
||
if (!this.isOnline) {
|
||
this.showToast('需要网络连接才能进行快速匹配', 'warning');
|
||
return;
|
||
}
|
||
|
||
this.showLoading('正在匹配对手...');
|
||
|
||
try {
|
||
// 模拟匹配过程
|
||
await this.delay(2000);
|
||
|
||
// 模拟匹配成功
|
||
this.showToast('匹配成功!即将开始对战', 'success');
|
||
await this.delay(800);
|
||
|
||
this.navigateToPlacement();
|
||
|
||
} catch (error) {
|
||
this.handleError('匹配失败', error);
|
||
} finally {
|
||
this.hideLoading();
|
||
}
|
||
}
|
||
|
||
showTutorial() {
|
||
// 创建教程弹窗
|
||
const tutorialHTML = `
|
||
<div class="modal-overlay" id="tutorialModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h3>🎯 游戏教程</h3>
|
||
<button class="modal-close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="tutorial-step">
|
||
<h4>📋 基本规则</h4>
|
||
<ul>
|
||
<li>游戏使用10×10网格</li>
|
||
<li>每位玩家放置3架十字形飞机</li>
|
||
<li>每架飞机占据11个格子</li>
|
||
<li>飞机可以朝4个方向放置</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="tutorial-step">
|
||
<h4>✈️ 飞机结构</h4>
|
||
<div class="plane-demo">
|
||
<div style="font-family: monospace; text-align: center; font-size: 12px; line-height: 1.2;">
|
||
<span style="color: #f59e0b;"> ●</span> ← 机头(关键目标)<br>
|
||
<span style="color: #8b5cf6;">◆■◆</span> ← 机翼+机身<br>
|
||
<span style="color: #6366f1;"> ■</span> ← 机身<br>
|
||
<span style="color: #8b5cf6;">◆■◆</span> ← 机翼+机身<br>
|
||
<span style="color: #6b7280;"> ▲</span> ← 机尾<br>
|
||
<span style="color: #6b7280;"> ▲</span> ← 机尾
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tutorial-step">
|
||
<h4>🎮 游戏流程</h4>
|
||
<ol>
|
||
<li><strong>布置阶段:</strong> 拖拽放置3架飞机</li>
|
||
<li><strong>战斗阶段:</strong> 轮流点击攻击目标</li>
|
||
<li><strong>胜利条件:</strong> 摧毁敌方3架飞机</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<div class="tutorial-step">
|
||
<h4>💡 策略提示</h4>
|
||
<ul>
|
||
<li>机头是唯一的致命弱点</li>
|
||
<li>通过命中信息推断飞机位置</li>
|
||
<li>合理布局避免飞机被发现</li>
|
||
<li>优先攻击可能的机头位置</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-primary" onclick="this.closest('.modal-overlay').remove()">
|
||
开始游戏
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
this.showModal(tutorialHTML);
|
||
}
|
||
|
||
showRanking() {
|
||
window.location.href = 'mobile_leaderboard_1.html';
|
||
}
|
||
|
||
showSettings() {
|
||
const settingsHTML = `
|
||
<div class="modal-overlay" id="settingsModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h3>⚙️ 游戏设置</h3>
|
||
<button class="modal-close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="setting-group">
|
||
<h4>🎨 界面设置</h4>
|
||
<div class="setting-item">
|
||
<label>
|
||
<input type="checkbox" checked> 显示网格坐标
|
||
</label>
|
||
</div>
|
||
<div class="setting-item">
|
||
<label>
|
||
<input type="checkbox" checked> 启用触摸振动
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="setting-group">
|
||
<h4>🎮 游戏设置</h4>
|
||
<div class="setting-item">
|
||
<label>
|
||
<select>
|
||
<option>30秒</option>
|
||
<option selected>60秒</option>
|
||
<option>90秒</option>
|
||
</select>
|
||
回合时间限制
|
||
</label>
|
||
</div>
|
||
<div class="setting-item">
|
||
<label>
|
||
<input type="checkbox" checked> 启用攻击动画
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="setting-group">
|
||
<h4>💾 数据管理</h4>
|
||
<div class="setting-item">
|
||
<button class="btn btn-secondary" style="width: 100%; margin-top: 8px;">清除游戏记录</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-primary" onclick="this.closest('.modal-overlay').remove()">
|
||
保存设置
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
this.showModal(settingsHTML);
|
||
}
|
||
|
||
// 工具方法
|
||
navigateToPlacement() {
|
||
// 这里应该导航到飞机放置界面
|
||
window.location.href = 'mobile_plane_placement_1.html';
|
||
}
|
||
|
||
showLoading(message = '加载中...') {
|
||
this.isLoading = true;
|
||
const overlay = document.getElementById('loadingOverlay');
|
||
const text = overlay.querySelector('.loading-text');
|
||
text.textContent = message;
|
||
overlay.style.display = 'flex';
|
||
}
|
||
|
||
hideLoading() {
|
||
this.isLoading = false;
|
||
const overlay = document.getElementById('loadingOverlay');
|
||
overlay.style.display = 'none';
|
||
}
|
||
|
||
showToast(message, type = 'info') {
|
||
const toast = document.createElement('div');
|
||
toast.className = `toast toast-${type}`;
|
||
toast.textContent = message;
|
||
|
||
// 添加toast样式到文档
|
||
if (!document.querySelector('#toastStyles')) {
|
||
const style = document.createElement('style');
|
||
style.id = 'toastStyles';
|
||
style.textContent = `
|
||
.toast {
|
||
position: fixed;
|
||
top: 80px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: var(--bg-elevated);
|
||
color: var(--text-primary);
|
||
padding: 12px 20px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--border-primary);
|
||
z-index: 1001;
|
||
animation: toastSlide 0.3s ease-out;
|
||
max-width: 300px;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
}
|
||
.toast-success { border-color: var(--secondary-color); }
|
||
.toast-warning { border-color: var(--accent-color); }
|
||
.toast-error { border-color: var(--danger-color); }
|
||
@keyframes toastSlide {
|
||
0% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
|
||
100% { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}
|
||
|
||
document.body.appendChild(toast);
|
||
|
||
setTimeout(() => {
|
||
toast.remove();
|
||
}, 3000);
|
||
}
|
||
|
||
showModal(htmlContent) {
|
||
// 添加模态框样式
|
||
if (!document.querySelector('#modalStyles')) {
|
||
const style = document.createElement('style');
|
||
style.id = 'modalStyles';
|
||
style.textContent = `
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.8);
|
||
backdrop-filter: blur(10px);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
padding: 20px;
|
||
animation: modalFadeIn 0.3s ease-out;
|
||
}
|
||
.modal-content {
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border-primary);
|
||
border-radius: 16px;
|
||
max-width: 400px;
|
||
width: 100%;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
animation: modalSlideIn 0.3s ease-out;
|
||
}
|
||
.modal-header {
|
||
padding: 20px 20px 0;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.modal-header h3 {
|
||
color: var(--text-primary);
|
||
font-size: 18px;
|
||
margin: 0;
|
||
}
|
||
.modal-close {
|
||
background: none;
|
||
border: none;
|
||
color: var(--text-secondary);
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
width: 30px;
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.modal-body {
|
||
padding: 20px;
|
||
}
|
||
.modal-footer {
|
||
padding: 0 20px 20px;
|
||
}
|
||
.tutorial-step {
|
||
margin-bottom: 24px;
|
||
}
|
||
.tutorial-step h4 {
|
||
color: var(--primary-color);
|
||
margin-bottom: 12px;
|
||
font-size: 16px;
|
||
}
|
||
.tutorial-step ul, .tutorial-step ol {
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
padding-left: 20px;
|
||
}
|
||
.tutorial-step li {
|
||
margin-bottom: 6px;
|
||
}
|
||
.plane-demo {
|
||
background: var(--bg-primary);
|
||
border: 1px solid var(--border-secondary);
|
||
border-radius: 8px;
|
||
padding: 12px;
|
||
margin: 12px 0;
|
||
}
|
||
.setting-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
.setting-group h4 {
|
||
color: var(--primary-color);
|
||
margin-bottom: 12px;
|
||
font-size: 16px;
|
||
}
|
||
.setting-item {
|
||
margin-bottom: 12px;
|
||
}
|
||
.setting-item label {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
.setting-item select {
|
||
background: var(--bg-tertiary);
|
||
border: 1px solid var(--border-primary);
|
||
border-radius: 6px;
|
||
color: var(--text-primary);
|
||
padding: 4px 8px;
|
||
font-size: 14px;
|
||
}
|
||
@keyframes modalFadeIn {
|
||
0% { opacity: 0; }
|
||
100% { opacity: 1; }
|
||
}
|
||
@keyframes modalSlideIn {
|
||
0% { transform: translateY(30px) scale(0.9); opacity: 0; }
|
||
100% { transform: translateY(0) scale(1); opacity: 1; }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}
|
||
|
||
const modalContainer = document.createElement('div');
|
||
modalContainer.innerHTML = htmlContent;
|
||
document.body.appendChild(modalContainer.firstElementChild);
|
||
|
||
// 绑定关闭事件
|
||
const modal = document.querySelector('.modal-overlay:last-child');
|
||
const closeBtn = modal.querySelector('.modal-close');
|
||
|
||
closeBtn.addEventListener('click', () => modal.remove());
|
||
modal.addEventListener('click', (e) => {
|
||
if (e.target === modal) modal.remove();
|
||
});
|
||
}
|
||
|
||
showContextMenu(element) {
|
||
// 长按上下文菜单功能(预留)
|
||
if (navigator.vibrate) {
|
||
navigator.vibrate(50);
|
||
}
|
||
}
|
||
|
||
createStarField() {
|
||
const starField = document.getElementById('starField');
|
||
const starCount = Math.floor(Math.random() * 50) + 30;
|
||
|
||
for (let i = 0; i < starCount; i++) {
|
||
const star = document.createElement('div');
|
||
star.className = 'star';
|
||
star.style.left = Math.random() * 100 + '%';
|
||
star.style.top = Math.random() * 100 + '%';
|
||
star.style.animationDelay = Math.random() * 3 + 's';
|
||
starField.appendChild(star);
|
||
}
|
||
}
|
||
|
||
checkNetworkStatus() {
|
||
const updateStatus = () => {
|
||
this.isOnline = navigator.onLine;
|
||
const statusText = document.getElementById('networkStatus');
|
||
const body = document.body;
|
||
|
||
if (this.isOnline) {
|
||
statusText.textContent = '在线';
|
||
body.classList.remove('offline');
|
||
} else {
|
||
statusText.textContent = '离线';
|
||
body.classList.add('offline');
|
||
}
|
||
};
|
||
|
||
updateStatus();
|
||
setInterval(updateStatus, 5000);
|
||
}
|
||
|
||
handleOnline() {
|
||
this.isOnline = true;
|
||
this.showToast('网络连接已恢复', 'success');
|
||
this.checkNetworkStatus();
|
||
}
|
||
|
||
handleOffline() {
|
||
this.isOnline = false;
|
||
this.showToast('网络连接已断开,切换到离线模式', 'warning');
|
||
this.checkNetworkStatus();
|
||
}
|
||
|
||
handleVisibilityChange() {
|
||
if (document.hidden) {
|
||
// 应用进入后台
|
||
console.log('应用进入后台');
|
||
} else {
|
||
// 应用回到前台
|
||
console.log('应用回到前台');
|
||
this.checkNetworkStatus();
|
||
}
|
||
}
|
||
|
||
getDeviceInfo() {
|
||
return {
|
||
userAgent: navigator.userAgent,
|
||
platform: navigator.platform,
|
||
memory: navigator.deviceMemory || 'unknown',
|
||
cores: navigator.hardwareConcurrency || 'unknown',
|
||
connection: navigator.connection?.effectiveType || 'unknown',
|
||
viewport: {
|
||
width: window.innerWidth,
|
||
height: window.innerHeight
|
||
}
|
||
};
|
||
}
|
||
|
||
monitorMemoryUsage() {
|
||
if ('memory' in performance) {
|
||
setInterval(() => {
|
||
const memory = performance.memory;
|
||
if (memory.usedJSHeapSize / memory.jsHeapSizeLimit > 0.9) {
|
||
console.warn('内存使用率过高:', (memory.usedJSHeapSize / memory.jsHeapSizeLimit * 100).toFixed(1) + '%');
|
||
}
|
||
}, 10000);
|
||
}
|
||
}
|
||
|
||
async registerServiceWorker() {
|
||
try {
|
||
// 这里可以注册Service Worker实现离线功能
|
||
console.log('Service Worker 支持可用');
|
||
} catch (error) {
|
||
console.warn('Service Worker 注册失败:', error);
|
||
}
|
||
}
|
||
|
||
handleError(message, error) {
|
||
console.error(message, error);
|
||
this.showToast(message, 'error');
|
||
}
|
||
|
||
delay(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
}
|
||
|
||
// 应用启动
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
new MobileGameApp();
|
||
});
|
||
|
||
// 页面加载完成动画
|
||
window.addEventListener('load', () => {
|
||
const appContainer = document.querySelector('.app-container');
|
||
appContainer.style.opacity = '0';
|
||
appContainer.style.transform = 'translateY(20px)';
|
||
appContainer.style.transition = 'all 0.8s cubic-bezier(0.4, 0, 0.2, 1)';
|
||
|
||
setTimeout(() => {
|
||
appContainer.style.opacity = '1';
|
||
appContainer.style.transform = 'translateY(0)';
|
||
}, 100);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |