Files
DFJ/01_文档/原型设计/05_对战页面.html
2025-09-11 13:34:29 +08:00

1182 lines
47 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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">
<!-- 引入通用样式 -->
<link rel="stylesheet" href="common-styles.css">
<style>
/* 页面特定CSS变量 */
:root {
--cell-size: min(8.5vw, 36px);
}
body {
background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 30%, #16213e 70%, #0f3460 100%);
}
/* 顶部状态栏 */
.status-header {
padding: 8px var(--safe-area-padding);
background: rgba(26, 29, 41, 0.95);
backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border-primary);
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
}
.network-status {
display: flex;
align-items: center;
gap: 6px;
color: var(--text-tertiary);
}
.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); }
}
.turn-indicator {
padding: 6px 16px;
border-radius: 16px;
font-size: 14px;
font-weight: 600;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.turn-indicator.my-turn {
background: linear-gradient(135deg, var(--secondary-color) 0%, var(--secondary-light) 100%);
color: #1a1a2e;
box-shadow: 0 4px 20px rgba(64, 224, 208, 0.4);
}
.turn-indicator.opponent-turn {
background: linear-gradient(135deg, rgba(255, 71, 87, 0.9) 0%, rgba(255, 56, 56, 0.9) 100%);
color: white;
border: 1px solid rgba(255, 71, 87, 0.6);
box-shadow: 0 4px 20px rgba(255, 71, 87, 0.3);
}
/* 主内容区域 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
padding: var(--safe-area-padding);
overflow: hidden;
}
/* 棋盘区域 */
.board-container {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px;
}
.board-wrapper {
position: relative;
}
.game-board {
display: grid;
grid-template-columns: repeat(10, var(--cell-size));
grid-template-rows: repeat(10, var(--cell-size));
gap: 1px;
background: rgba(64, 224, 208, 0.1);
border: 2px solid rgba(64, 224, 208, 0.5);
border-radius: 12px;
padding: 6px;
backdrop-filter: blur(8px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.board-cell {
background: rgba(15, 52, 96, 0.8);
border: 1px solid rgba(64, 224, 208, 0.15);
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
color: rgba(255, 255, 255, 0.4);
transition: all 0.2s ease;
position: relative;
cursor: pointer;
user-select: none;
font-weight: 600;
}
.board-cell:active {
background: rgba(64, 224, 208, 0.4);
transform: scale(0.95);
border-color: var(--secondary-color);
}
/* 攻击结果状态 */
.board-cell.hit {
background: linear-gradient(135deg, var(--danger-color) 0%, var(--danger-light) 100%);
color: white;
animation: hitFlash 0.6s ease-out;
box-shadow: 0 0 15px var(--danger-color);
}
.board-cell.miss {
background: rgba(108, 117, 125, 0.6);
color: var(--text-tertiary);
}
.board-cell.destroy {
background: linear-gradient(135deg, var(--accent-color) 0%, var(--accent-light) 100%);
color: white;
animation: destroyFlash 1s ease-out;
box-shadow: 0 0 20px var(--accent-color);
}
/* 我方飞机状态 */
.board-cell.my-plane {
background: var(--primary-color);
color: white;
}
.board-cell.my-plane-head {
background: var(--accent-color);
}
.board-cell.my-plane-destroyed {
background: rgba(108, 117, 125, 0.8);
color: var(--text-tertiary);
position: relative;
}
.board-cell.my-plane-destroyed::after {
content: '💥';
position: absolute;
font-size: 16px;
}
/* 模拟飞机样式 */
.board-cell.simulated-plane {
background: rgba(99, 102, 241, 0.3);
border: 2px dashed var(--primary-color);
color: var(--primary-color);
}
/* 目标选择状态 */
.board-cell.selected-target {
background: rgba(245, 158, 11, 0.6);
border: 2px solid var(--accent-color);
animation: targetPulse 1s infinite;
}
/* 对手瞄准状态 */
.board-cell.opponent-targeting {
background: rgba(255, 71, 87, 0.4);
border: 2px solid var(--danger-color);
animation: dangerPulse 0.5s infinite;
}
@keyframes hitFlash {
0% { transform: scale(1); box-shadow: 0 0 10px var(--danger-color); }
50% { transform: scale(1.1); box-shadow: 0 0 20px var(--danger-color); }
100% { transform: scale(1); box-shadow: 0 0 5px var(--danger-color); }
}
@keyframes destroyFlash {
0%, 100% { transform: scale(1); }
25% { transform: scale(1.2); }
50% { transform: scale(0.9); }
75% { transform: scale(1.1); }
}
@keyframes targetPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
@keyframes dangerPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* 坐标轴标识 */
.col-label, .row-label {
position: absolute;
font-size: 10px;
color: var(--text-tertiary);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
}
.col-label {
top: -20px;
height: 15px;
width: var(--cell-size);
}
.row-label {
left: -20px;
width: 15px;
height: var(--cell-size);
}
/* 控制面板 */
.control-panel {
background: rgba(22, 33, 62, 0.8);
border: 1px solid rgba(64, 224, 208, 0.3);
border-radius: 16px;
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
overflow: hidden;
height: 320px;
display: flex;
flex-direction: column;
}
/* 页签头部 */
.tab-header {
display: flex;
background: var(--bg-tertiary);
border-bottom: 1px solid var(--border-primary);
}
.tab-item {
flex: 1;
padding: 12px;
text-align: center;
font-size: 14px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
min-height: var(--touch-target-min);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
}
.tab-item.active {
color: var(--primary-color);
background: var(--bg-secondary);
border-bottom: 2px solid var(--primary-color);
}
.tab-item:active {
background: rgba(99, 102, 241, 0.1);
}
/* 页签内容 */
.tab-content {
padding: 16px;
flex: 1;
overflow-y: auto;
}
.tab-pane {
display: none;
height: 100%;
}
.tab-pane.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* 飞机模拟控制 */
.simulate-controls {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 16px;
margin-bottom: 16px;
flex: 1;
}
.plane-selection {
display: flex;
flex-direction: column;
gap: 8px;
}
.direction-control {
display: grid;
grid-template-columns: repeat(3, 44px);
grid-template-rows: repeat(3, 44px);
gap: 4px;
}
/* 页面特定按钮样式覆盖 */
.plane-btn.placed {
background: linear-gradient(135deg, var(--primary-color), var(--primary-light)) !important;
color: white !important;
border-color: var(--primary-light) !important;
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
}
.plane-btn.selected {
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-light)) !important;
color: #1a1a2e !important;
border-color: var(--secondary-color) !important;
box-shadow: 0 4px 16px rgba(64, 224, 208, 0.3);
}
/* 攻击控制区域 */
.attack-controls {
text-align: center;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.attack-target-info {
background: rgba(15, 52, 96, 0.4);
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
color: var(--text-secondary);
font-size: 14px;
}
.attack-buttons {
display: flex;
gap: 12px;
justify-content: center;
margin-top: 16px;
}
/* 历史记录 */
.history-container {
flex: 1;
overflow-y: auto;
margin-bottom: 16px;
}
.history-item {
font-size: 13px;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 8px;
padding: 8px;
background: rgba(64, 224, 208, 0.1);
border-radius: 8px;
border-left: 3px solid var(--secondary-color);
transition: all 0.3s ease;
}
.history-item.hit {
border-left-color: var(--danger-color);
background: rgba(255, 71, 87, 0.1);
}
.history-item.miss {
border-left-color: var(--text-tertiary);
background: rgba(108, 117, 125, 0.1);
}
.history-item.destroy {
border-left-color: var(--accent-color);
background: rgba(245, 158, 11, 0.2);
font-weight: 600;
}
/* 状态信息区域 */
.status-info {
text-align: center;
padding: 12px;
background: rgba(15, 52, 96, 0.4);
border-radius: 8px;
margin-top: auto;
color: var(--text-secondary);
font-size: 14px;
}
/* 响应式设计 */
@media (max-width: 375px) {
:root {
--cell-size: min(8vw, 32px);
}
.btn {
font-size: 13px;
min-height: 40px;
padding: 8px 12px;
}
.tab-item {
font-size: 13px;
padding: 10px;
}
}
@media (max-height: 640px) {
.main-content {
padding: 12px;
}
.tab-content {
padding: 12px;
}
}
@media (orientation: landscape) and (max-height: 500px) {
.app-container {
flex-direction: row;
}
.main-content {
flex-direction: row;
gap: 16px;
}
.board-container {
flex: 1;
margin-bottom: 0;
}
.control-panel {
width: 300px;
max-height: 100%;
}
}
</style>
</head>
<body>
<div class="app-container">
<!-- 顶部状态栏 -->
<header class="status-header">
<div class="network-status">
<div class="connection-dot"></div>
<span>在线</span>
</div>
<div class="turn-indicator my-turn" id="turnIndicator">我的回合</div>
<div style="width: 60px;"></div>
</header>
<!-- 主内容区域 -->
<main class="main-content">
<!-- 棋盘容器 -->
<div class="board-container">
<div class="board-wrapper" id="boardWrapper">
<div class="game-board" id="gameBoard"></div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<div class="tab-header">
<div class="tab-item active" data-tab="simulate">🎯 模拟</div>
<div class="tab-item" data-tab="attack">⚡ 攻击</div>
<div class="tab-item" data-tab="history">📋 历史</div>
</div>
<div class="tab-content">
<!-- 飞机模拟页签 -->
<div class="tab-pane active" id="simulate">
<div class="simulate-controls">
<div class="plane-selection">
<button class="btn btn-secondary plane-btn" id="simulatePlane1" data-plane-id="1">飞机1</button>
<button class="btn btn-secondary plane-btn" id="simulatePlane2" data-plane-id="2">飞机2</button>
<button class="btn btn-secondary plane-btn" id="simulatePlane3" data-plane-id="3">飞机3</button>
</div>
<div class="direction-control">
<div></div>
<button class="btn btn-secondary" id="moveUp"></button>
<button class="btn btn-danger" id="deletePlane">🗑️</button>
<button class="btn btn-secondary" id="moveLeft"></button>
<button class="btn btn-secondary" id="rotatePlane"></button>
<button class="btn btn-secondary" id="moveRight"></button>
<div></div>
<button class="btn btn-secondary" id="moveDown"></button>
<button class="btn btn-secondary" id="clearSimulation">🔄</button>
</div>
</div>
<div class="status-info" id="simulateStatus">点击棋盘放置模拟飞机</div>
</div>
<!-- 攻击页签 -->
<div class="tab-pane" id="attack">
<div class="attack-controls">
<div class="attack-target-info" id="attackTargetInfo">
选择攻击目标
</div>
<div class="attack-buttons">
<button class="btn btn-success" id="attackBtn" disabled>🚀 打击</button>
<button class="btn btn-secondary" id="switchToDefenseBtn">👁️ 观察我方</button>
</div>
</div>
<div class="status-info" id="attackStatus">点击敌方棋盘选择攻击目标</div>
</div>
<!-- 历史记录页签 -->
<div class="tab-pane" id="history">
<div class="history-container" id="historyContainer">
<div class="history-item hit">A5 - 命中敌机!</div>
<div class="history-item miss">B3 - 攻击落空</div>
<div class="history-item destroy">C7 - 摧毁敌机头部!</div>
<div class="history-item miss">D2 - 攻击落空</div>
</div>
<div class="status-info">攻击历史记录</div>
</div>
</div>
</div>
</main>
</div>
<script>
class BattlePage {
constructor() {
this.BOARD_SIZE = 10;
this.currentGameState = 'my_turn'; // 'my_turn' | 'opponent_turn'
this.currentMode = 'attack'; // 'attack' | 'simulate' | 'observe'
this.selectedTarget = null;
this.simulatedPlanes = [];
this.selectedSimulatePlane = null;
this.attackHistory = [];
// 棋盘状态
this.attackBoard = Array(this.BOARD_SIZE).fill(null).map(() => Array(this.BOARD_SIZE).fill(0));
this.myBoard = Array(this.BOARD_SIZE).fill(null).map(() => Array(this.BOARD_SIZE).fill(0));
this.dom = {
board: document.getElementById('gameBoard'),
boardWrapper: document.getElementById('boardWrapper'),
turnIndicator: document.getElementById('turnIndicator'),
tabItems: document.querySelectorAll('.tab-item'),
tabPanes: document.querySelectorAll('.tab-pane'),
// 模拟控件
simulatePlane1: document.getElementById('simulatePlane1'),
simulatePlane2: document.getElementById('simulatePlane2'),
simulatePlane3: document.getElementById('simulatePlane3'),
moveUp: document.getElementById('moveUp'),
moveDown: document.getElementById('moveDown'),
moveLeft: document.getElementById('moveLeft'),
moveRight: document.getElementById('moveRight'),
rotatePlane: document.getElementById('rotatePlane'),
deletePlane: document.getElementById('deletePlane'),
clearSimulation: document.getElementById('clearSimulation'),
simulateStatus: document.getElementById('simulateStatus'),
// 攻击控件
attackBtn: document.getElementById('attackBtn'),
switchToDefenseBtn: document.getElementById('switchToDefenseBtn'),
attackTargetInfo: document.getElementById('attackTargetInfo'),
attackStatus: document.getElementById('attackStatus'),
// 历史记录
historyContainer: document.getElementById('historyContainer')
};
this.init();
}
init() {
this.createBoard();
this.bindEvents();
this.loadMyPlanes(); // 从localStorage加载我方飞机布局
this.updateUI();
console.log("对战页面已初始化");
}
createBoard() {
this.dom.board.innerHTML = '';
// 创建网格单元格
for (let r = 0; r < this.BOARD_SIZE; r++) {
for (let c = 0; c < this.BOARD_SIZE; c++) {
const cell = document.createElement('div');
cell.className = 'board-cell';
cell.dataset.row = r;
cell.dataset.col = c;
this.dom.board.appendChild(cell);
}
}
// 添加坐标轴标签
for (let i = 0; i < this.BOARD_SIZE; i++) {
const colLabel = document.createElement('div');
colLabel.className = 'col-label';
colLabel.textContent = String.fromCharCode(65 + i);
colLabel.style.left = `calc(${i} * var(--cell-size) + ${i + 1}px + 6px)`;
this.dom.boardWrapper.appendChild(colLabel);
const rowLabel = document.createElement('div');
rowLabel.className = 'row-label';
rowLabel.textContent = i + 1;
rowLabel.style.top = `calc(${i} * var(--cell-size) + ${i + 1}px + 6px)`;
this.dom.boardWrapper.appendChild(rowLabel);
}
}
bindEvents() {
// 棋盘点击事件
this.dom.board.addEventListener('click', this.handleBoardClick.bind(this));
// 页签切换事件
this.dom.tabItems.forEach(tab => {
tab.addEventListener('click', this.handleTabClick.bind(this));
});
// 模拟控件事件
[this.dom.simulatePlane1, this.dom.simulatePlane2, this.dom.simulatePlane3].forEach(btn => {
btn.addEventListener('click', this.handleSimulatePlaneClick.bind(this));
});
this.dom.moveUp.addEventListener('click', () => this.moveSimulatePlane(0, -1));
this.dom.moveDown.addEventListener('click', () => this.moveSimulatePlane(0, 1));
this.dom.moveLeft.addEventListener('click', () => this.moveSimulatePlane(-1, 0));
this.dom.moveRight.addEventListener('click', () => this.moveSimulatePlane(1, 0));
this.dom.rotatePlane.addEventListener('click', this.rotateSimulatePlane.bind(this));
this.dom.deletePlane.addEventListener('click', this.deleteSimulatePlane.bind(this));
this.dom.clearSimulation.addEventListener('click', this.clearAllSimulation.bind(this));
// 攻击控件事件
this.dom.attackBtn.addEventListener('click', this.executeAttack.bind(this));
this.dom.switchToDefenseBtn.addEventListener('click', this.switchToDefenseView.bind(this));
// 触觉反馈
document.querySelectorAll('.btn, .board-cell, .tab-item').forEach(element => {
element.addEventListener('click', () => {
if ('vibrate' in navigator) {
navigator.vibrate(10);
}
});
});
}
handleBoardClick(e) {
const cell = e.target.closest('.board-cell');
if (!cell) return;
const row = parseInt(cell.dataset.row);
const col = parseInt(cell.dataset.col);
const activeTab = document.querySelector('.tab-item.active').dataset.tab;
if (activeTab === 'simulate') {
this.handleSimulateBoardClick(row, col);
} else if (activeTab === 'attack') {
this.handleAttackBoardClick(row, col);
}
}
handleSimulateBoardClick(row, col) {
if (this.selectedSimulatePlane) {
// 放置选中的模拟飞机
this.tryPlaceSimulatePlane(this.selectedSimulatePlane, {x: col, y: row});
} else {
// 点击已有模拟飞机进行选择
const plane = this.simulatedPlanes.find(p =>
p.positions.some(pos => pos.x === col && pos.y === row)
);
if (plane) {
this.selectedSimulatePlane = plane.id;
this.updateSimulateStatus(`已选择模拟飞机 ${plane.id}`);
} else {
this.updateSimulateStatus("请先选择要放置的飞机");
}
}
this.updateUI();
}
handleAttackBoardClick(row, col) {
if (this.currentGameState !== 'my_turn') return;
// 检查是否已经攻击过这个位置
if (this.attackBoard[row][col] !== 0) {
this.updateAttackStatus("该位置已经攻击过了");
return;
}
// 设置攻击目标
this.selectedTarget = {x: col, y: row};
const coordinate = String.fromCharCode(65 + col) + (row + 1);
this.updateAttackTargetInfo(`目标: ${coordinate}`);
this.updateAttackStatus(`已选择目标 ${coordinate},点击打击按钮发起攻击`);
this.dom.attackBtn.disabled = false;
this.updateUI();
}
handleTabClick(e) {
const tabId = e.target.dataset.tab;
if (!tabId) return;
// 更新页签状态
this.dom.tabItems.forEach(tab => tab.classList.remove('active'));
e.target.classList.add('active');
this.dom.tabPanes.forEach(pane => pane.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
// 根据页签切换模式
if (tabId === 'simulate') {
this.currentMode = 'simulate';
} else if (tabId === 'attack') {
this.currentMode = 'attack';
}
this.updateUI();
}
handleSimulatePlaneClick(e) {
const planeId = parseInt(e.target.dataset.planeId);
this.selectedSimulatePlane = (this.selectedSimulatePlane === planeId) ? null : planeId;
this.updateSimulateStatus(
this.selectedSimulatePlane ? `已选择飞机 ${planeId},点击棋盘放置` : "请选择要操作的飞机"
);
this.updateUI();
}
tryPlaceSimulatePlane(planeId, center) {
const directions = ['up', 'right', 'down', 'left'];
let placed = false;
// 移除该飞机的旧位置
this.simulatedPlanes = this.simulatedPlanes.filter(p => p.id !== planeId);
// 尝试各个方向
for (const direction of directions) {
const positions = this.getPlanePositions(center, direction);
if (this.isSimulatePlacementValid(positions)) {
this.simulatedPlanes.push({
id: planeId,
center: center,
direction: direction,
positions: positions
});
placed = true;
this.updateSimulateStatus(`飞机 ${planeId} 已放置在 ${String.fromCharCode(65 + center.x)}${center.y + 1}`);
break;
}
}
if (!placed) {
this.updateSimulateStatus(`无法在该位置放置飞机 ${planeId}`);
}
}
moveSimulatePlane(dx, dy) {
if (!this.selectedSimulatePlane) return;
const plane = this.simulatedPlanes.find(p => p.id === this.selectedSimulatePlane);
if (!plane) return;
const newCenter = {
x: plane.center.x + dx,
y: plane.center.y + dy
};
this.tryPlaceSimulatePlane(this.selectedSimulatePlane, newCenter);
this.updateUI();
}
rotateSimulatePlane() {
if (!this.selectedSimulatePlane) return;
const plane = this.simulatedPlanes.find(p => p.id === this.selectedSimulatePlane);
if (!plane) return;
const directions = ['up', 'right', 'down', 'left'];
const currentIndex = directions.indexOf(plane.direction);
const nextDirection = directions[(currentIndex + 1) % 4];
// 移除旧飞机
this.simulatedPlanes = this.simulatedPlanes.filter(p => p.id !== this.selectedSimulatePlane);
// 尝试新方向
const positions = this.getPlanePositions(plane.center, nextDirection);
if (this.isSimulatePlacementValid(positions)) {
this.simulatedPlanes.push({
id: this.selectedSimulatePlane,
center: plane.center,
direction: nextDirection,
positions: positions
});
this.updateSimulateStatus(`飞机 ${this.selectedSimulatePlane} 已旋转`);
} else {
// 恢复原飞机
this.simulatedPlanes.push(plane);
this.updateSimulateStatus(`无法旋转飞机 ${this.selectedSimulatePlane}`);
}
this.updateUI();
}
deleteSimulatePlane() {
if (!this.selectedSimulatePlane) return;
this.simulatedPlanes = this.simulatedPlanes.filter(p => p.id !== this.selectedSimulatePlane);
this.updateSimulateStatus(`已删除模拟飞机 ${this.selectedSimulatePlane}`);
this.selectedSimulatePlane = null;
this.updateUI();
}
clearAllSimulation() {
this.simulatedPlanes = [];
this.selectedSimulatePlane = null;
this.updateSimulateStatus("已清除所有模拟飞机");
this.updateUI();
}
executeAttack() {
if (!this.selectedTarget || this.currentGameState !== 'my_turn') return;
const {x, y} = this.selectedTarget;
const coordinate = String.fromCharCode(65 + x) + (y + 1);
// 模拟攻击结果实际应用中通过WebSocket获取
const result = this.simulateAttackResult(x, y);
// 更新攻击棋盘
this.attackBoard[y][x] = result.type;
// 添加到历史记录
this.attackHistory.unshift({
coordinate: coordinate,
result: result.type,
message: result.message,
timestamp: Date.now()
});
// 清除模拟飞机(攻击后自动清除)
this.simulatedPlanes = [];
this.selectedSimulatePlane = null;
// 重置攻击目标
this.selectedTarget = null;
this.dom.attackBtn.disabled = true;
this.updateAttackTargetInfo("选择攻击目标");
this.updateAttackStatus(`${coordinate} ${result.message}`);
// 更新历史记录显示
this.updateHistoryDisplay();
// 模拟切换到对手回合
setTimeout(() => {
this.switchToOpponentTurn();
}, 2000);
this.updateUI();
}
simulateAttackResult(x, y) {
// 简单的随机攻击结果模拟
const random = Math.random();
if (random < 0.3) {
return { type: 'hit', message: '命中敌机!' };
} else if (random < 0.4) {
return { type: 'destroy', message: '摧毁敌机头部!' };
} else {
return { type: 'miss', message: '攻击落空' };
}
}
switchToDefenseView() {
this.switchToOpponentTurn();
}
switchToOpponentTurn() {
this.currentGameState = 'opponent_turn';
this.currentMode = 'observe';
// 切换页签到攻击页面,但显示为观察模式
this.dom.tabItems.forEach(tab => tab.classList.remove('active'));
this.dom.tabItems[1].classList.add('active'); // 攻击页签
this.dom.tabPanes.forEach(pane => pane.classList.remove('active'));
document.getElementById('attack').classList.add('active');
this.dom.turnIndicator.textContent = '对手回合';
this.dom.turnIndicator.className = 'turn-indicator opponent-turn';
this.updateAttackTargetInfo("观察对手动向");
this.updateAttackStatus("对手正在思考...");
// 模拟对手瞄准
this.simulateOpponentTargeting();
// 模拟5秒后切换回我的回合
setTimeout(() => {
this.switchToMyTurn();
}, 5000);
this.updateUI();
}
switchToMyTurn() {
this.currentGameState = 'my_turn';
this.currentMode = 'attack';
this.dom.turnIndicator.textContent = '我的回合';
this.dom.turnIndicator.className = 'turn-indicator my-turn';
this.updateAttackTargetInfo("选择攻击目标");
this.updateAttackStatus("点击敌方棋盘选择攻击目标");
this.updateUI();
}
simulateOpponentTargeting() {
// 模拟对手瞄准过程
let targetCount = 0;
const maxTargets = 3;
const targetInterval = setInterval(() => {
if (targetCount >= maxTargets || this.currentGameState === 'my_turn') {
clearInterval(targetInterval);
return;
}
// 随机选择一个未被攻击的位置
const availablePositions = [];
for (let r = 0; r < this.BOARD_SIZE; r++) {
for (let c = 0; c < this.BOARD_SIZE; c++) {
if (this.myBoard[r][c] === 0) {
availablePositions.push({x: c, y: r});
}
}
}
if (availablePositions.length > 0) {
const randomPos = availablePositions[Math.floor(Math.random() * availablePositions.length)];
this.simulateOpponentTarget(randomPos);
}
targetCount++;
}, 1500);
}
simulateOpponentTarget(position) {
// 清除之前的瞄准状态
const cells = this.dom.board.querySelectorAll('.board-cell');
cells.forEach(cell => cell.classList.remove('opponent-targeting'));
// 设置新的瞄准状态
const cell = cells[position.y * this.BOARD_SIZE + position.x];
cell.classList.add('opponent-targeting');
const coordinate = String.fromCharCode(65 + position.x) + (position.y + 1);
this.updateAttackStatus(`对手正在瞄准 ${coordinate}...`);
}
getPlanePositions(center, direction) {
const geometry = {
up: [
{ x: 0, y: -2, type: 'head' },
{ x: -2, y: -1, type: 'wing' }, { x: -1, y: -1, type: 'wing' },
{ x: 0, y: -1, type: 'wing' }, { x: 1, y: -1, type: 'wing' }, { x: 2, y: -1, type: 'wing' },
{ x: 0, y: 0, type: 'body' }, { x: 0, y: 1, type: 'body' },
{ x: -1, y: 2, type: 'tail' }, { x: 0, y: 2, type: 'tail' }, { x: 1, y: 2, type: 'tail' }
],
down: [
{ x: 0, y: 2, type: 'head' },
{ x: -2, y: 1, type: 'wing' }, { x: -1, y: 1, type: 'wing' },
{ x: 0, y: 1, type: 'wing' }, { x: 1, y: 1, type: 'wing' }, { x: 2, y: 1, type: 'wing' },
{ x: 0, y: 0, type: 'body' }, { x: 0, y: -1, type: 'body' },
{ x: -1, y: -2, type: 'tail' }, { x: 0, y: -2, type: 'tail' }, { x: 1, y: -2, type: 'tail' }
],
left: [
{ x: -2, y: 0, type: 'head' },
{ x: -1, y: -2, type: 'wing' }, { x: -1, y: -1, type: 'wing' },
{ x: -1, y: 0, type: 'wing' }, { x: -1, y: 1, type: 'wing' }, { x: -1, y: 2, type: 'wing' },
{ x: 0, y: 0, type: 'body' }, { x: 1, y: 0, type: 'body' },
{ x: 2, y: -1, type: 'tail' }, { x: 2, y: 0, type: 'tail' }, { x: 2, y: 1, type: 'tail' }
],
right: [
{ x: 2, y: 0, type: 'head' },
{ x: 1, y: -2, type: 'wing' }, { x: 1, y: -1, type: 'wing' },
{ x: 1, y: 0, type: 'wing' }, { x: 1, y: 1, type: 'wing' }, { x: 1, y: 2, type: 'wing' },
{ x: 0, y: 0, type: 'body' }, { x: -1, y: 0, type: 'body' },
{ x: -2, y: -1, type: 'tail' }, { x: -2, y: 0, type: 'tail' }, { x: -2, y: 1, type: 'tail' }
]
};
const offsets = geometry[direction];
if (!offsets) return [];
return offsets.map(o => ({
x: center.x + o.x,
y: center.y + o.y,
type: o.type
}));
}
isSimulatePlacementValid(positions) {
for (const pos of positions) {
if (pos.x < 0 || pos.x >= this.BOARD_SIZE || pos.y < 0 || pos.y >= this.BOARD_SIZE) {
return false; // 越界
}
}
return true;
}
loadMyPlanes() {
// 从localStorage加载我方飞机布局从准备页面
try {
const savedPlanes = localStorage.getItem('playerPlanes');
if (savedPlanes) {
const planes = JSON.parse(savedPlanes);
planes.forEach(plane => {
if (plane.isPlaced && plane.center) {
const positions = this.getPlanePositions(plane.center, plane.direction);
positions.forEach(pos => {
if (pos.x >= 0 && pos.x < this.BOARD_SIZE && pos.y >= 0 && pos.y < this.BOARD_SIZE) {
this.myBoard[pos.y][pos.x] = plane.id;
}
});
}
});
}
} catch (e) {
console.warn('无法加载飞机布局:', e);
}
}
updateHistoryDisplay() {
this.dom.historyContainer.innerHTML = '';
this.attackHistory.forEach(item => {
const div = document.createElement('div');
div.className = `history-item ${item.result}`;
div.textContent = `${item.coordinate} - ${item.message}`;
this.dom.historyContainer.appendChild(div);
});
}
updateUI() {
this.updateBoardDisplay();
this.updateControlsState();
}
updateBoardDisplay() {
const cells = this.dom.board.querySelectorAll('.board-cell');
cells.forEach((cell, index) => {
const row = Math.floor(index / this.BOARD_SIZE);
const col = index % this.BOARD_SIZE;
// 重置单元格类名
cell.className = 'board-cell';
cell.textContent = '';
if (this.currentGameState === 'my_turn' && this.currentMode !== 'observe') {
// 我的回合 - 显示攻击棋盘
const attackState = this.attackBoard[row][col];
if (attackState === 'hit') {
cell.classList.add('hit');
cell.textContent = '🔥';
} else if (attackState === 'miss') {
cell.classList.add('miss');
cell.textContent = '×';
} else if (attackState === 'destroy') {
cell.classList.add('destroy');
cell.textContent = '💥';
}
// 显示模拟飞机
const simulatedPlane = this.simulatedPlanes.find(plane =>
plane.positions.some(pos => pos.x === col && pos.y === row)
);
if (simulatedPlane) {
cell.classList.add('simulated-plane');
if (simulatedPlane.id === this.selectedSimulatePlane) {
//cell.style.borderColor = 'var(--success-color)';
}
}
// 显示选中的攻击目标
if (this.selectedTarget && this.selectedTarget.x === col && this.selectedTarget.y === row) {
cell.classList.add('selected-target');
}
} else {
// 对手回合 - 显示我方棋盘
const myPlaneId = this.myBoard[row][col];
if (myPlaneId > 0) {
cell.classList.add('my-plane');
// 可以根据部位类型添加不同样式
}
}
});
}
updateControlsState() {
// 更新模拟飞机按钮状态
[this.dom.simulatePlane1, this.dom.simulatePlane2, this.dom.simulatePlane3].forEach(btn => {
const planeId = parseInt(btn.dataset.planeId);
btn.classList.remove('placed', 'selected');
if (this.simulatedPlanes.find(p => p.id === planeId)) {
btn.classList.add('placed');
}
if (planeId === this.selectedSimulatePlane) {
btn.classList.add('selected');
}
});
// 更新方向控制按钮状态
const hasSelectedPlane = this.selectedSimulatePlane !== null;
this.dom.moveUp.disabled = !hasSelectedPlane;
this.dom.moveDown.disabled = !hasSelectedPlane;
this.dom.moveLeft.disabled = !hasSelectedPlane;
this.dom.moveRight.disabled = !hasSelectedPlane;
this.dom.rotatePlane.disabled = !hasSelectedPlane;
this.dom.deletePlane.disabled = !hasSelectedPlane;
// 更新攻击按钮状态
const canAttack = this.selectedTarget && this.currentGameState === 'my_turn';
this.dom.attackBtn.disabled = !canAttack;
// 更新切换按钮文本
if (this.currentGameState === 'my_turn') {
this.dom.switchToDefenseBtn.textContent = '👁️ 观察我方';
} else {
this.dom.switchToDefenseBtn.textContent = '⚡ 返回攻击';
this.dom.switchToDefenseBtn.onclick = () => this.switchToMyTurn();
}
}
updateSimulateStatus(message) {
this.dom.simulateStatus.textContent = message;
}
updateAttackStatus(message) {
this.dom.attackStatus.textContent = message;
}
updateAttackTargetInfo(message) {
this.dom.attackTargetInfo.textContent = message;
}
}
// 初始化对战页面
document.addEventListener('DOMContentLoaded', () => {
new BattlePage();
});
</script>
</body>
</html>