未命名 55a0cjedit icon

创建者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>国家大战模拟器 - 终极版</title>
    <style>
        :root {
            --bg-color: #f0f2f5;
            --panel-bg: rgba(255, 255, 255, 0.9);
            --text-color: #333;
            --accent-color: #007bff;
            --border-radius: 12px;
            --shadow: 0 4px 12px rgba(0,0,0,0.15);
        }

        /* 主题定义 */
        body.theme-cyber {
            --bg-color: #0d1117;
            --panel-bg: rgba(22, 27, 34, 0.85);
            --text-color: #58a6ff;
            --accent-color: #2ea043;
            --shadow: 0 0 15px rgba(88, 166, 255, 0.2);
        }

        body.theme-retro {
            --bg-color: #e6dcc3;
            --panel-bg: rgba(230, 220, 195, 0.9);
            --text-color: #5c4b37;
            --accent-color: #8b4513;
            --shadow: 2px 2px 0px rgba(92, 75, 55, 0.2);
        }

        * { margin: 0; padding: 0; box-sizing: border-box; user-select: none; -webkit-tap-highlight-color: transparent; }
        
        body {
            font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
            background-color: var(--bg-color);
            color: var(--text-color);
            overflow: hidden;
            transition: background-color 0.5s, color 0.5s;
            height: 100vh;
            width: 100vw;
        }

        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }

        /* UI 控制面板 */
        #ui-layer {
            position: absolute;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            gap: 15px;
            padding: 15px 25px;
            background: var(--panel-bg);
            backdrop-filter: blur(10px);
            border-radius: var(--border-radius);
            box-shadow: var(--shadow);
            z-index: 100;
            transition: all 0.3s ease;
            border: 1px solid rgba(128,128,128,0.1);
        }

        .control-group {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        label { font-size: 14px; font-weight: 600; }

        select, button {
            padding: 8px 12px;
            border-radius: 6px;
            border: 1px solid rgba(128,128,128,0.3);
            background: rgba(255,255,255,0.1);
            color: var(--text-color);
            cursor: pointer;
            font-size: 14px;
            outline: none;
            transition: 0.2s;
        }

        button:hover { filter: brightness(1.1); }
        button:active { transform: scale(0.95); }

        .btn-primary { background: var(--accent-color); color: white; border: none; font-weight: bold; }

        /* 状态信息 */
        #stats-bar {
            position: absolute;
            bottom: 20px;
            left: 20px;
            background: var(--panel-bg);
            padding: 10px 20px;
            border-radius: var(--border-radius);
            font-size: 14px;
            pointer-events: none;
            box-shadow: var(--shadow);
        }

        /* 移动端适配 */
        @media (max-width: 768px) {
            #ui-layer {
                top: auto;
                bottom: 20px;
                left: 50%;
                transform: translateX(-50%);
                width: 90%;
                justify-content: space-between;
                flex-wrap: wrap;
                padding: 10px;
            }
            
            .control-group { flex-direction: column; align-items: flex-start; gap: 5px; }
            select, button { width: 100%; text-align: center; }
            
            #stats-bar {
                bottom: 100px; /* 让出按钮空间 */
                left: 50%;
                transform: translateX(-50%);
                width: 90%;
                text-align: center;
            }
        }
    </style>
</head>
<body>

    <canvas id="simCanvas"></canvas>

    <div id="ui-layer">
        <div class="control-group">
            <label>主题:</label>
            <select id="themeSelect">
                <option value="modern">现代简约</option>
                <option value="cyber">赛博朋克</option>
                <option value="retro">复古羊皮</option>
            </select>
        </div>
        <div class="control-group">
            <button id="restartBtn" class="btn-primary">重置模拟</button>
        </div>
        <div class="control-group">
            <button id="pauseBtn">暂停/继续</button>
        </div>
    </div>

    <div id="stats-bar">
        存活国家:<span id="nationCount">0</span> | 当前帧率:<span id="fpsCount">0</span>
    </div>

<script>
/**
 * 国家大战模拟器核心逻辑
 */
const canvas = document.getElementById('simCanvas');
const ctx = canvas.getContext('2d');

// 配置参数
const CONFIG = {
    baseNationCount: 15, // 基础国家数量
    growthRate: 0.05,    // 基础生长速度
    attackRange: 40,     // 攻击距离
    colors: [
        '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', 
        '#F7DC6F', '#BB8FCE', '#F1948A', '#82E0AA', '#85C1E9'
    ]
};

// 全局状态
let nations = [];
let isPaused = false;
let animationId;
let lastTime = 0;
let frameCount = 0;
let lastFpsTime = 0;

// 主题配置映射
const THEMES = {
    modern: { bg: '#f0f2f5', grid: '#e1e4e8', text: '#333' },
    cyber: { bg: '#0d1117', grid: '#21262d', text: '#58a6ff' },
    retro: { bg: '#e6dcc3', grid: '#d4c5a3', text: '#5c4b37' }
};
let currentTheme = 'modern';

// 国家类
class Nation {
    constructor(id, x, y, radius, color, powerMultiplier) {
        this.id = id;
        this.x = x;
        this.y = y;
        this.baseRadius = radius; // 初始大小代表领土潜力
        this.radius = radius;
        this.color = color;
        this.power = 100 * powerMultiplier; // 战力 (兵力)
        this.maxPower = 1000 * powerMultiplier;
        this.alive = true;
        this.name = `国-${id}`;
        
        // 差异化属性
        this.growthSpeed = (Math.random() * 0.5 + 0.5) * powerMultiplier; // 恢复速度
        this.aggression = Math.random(); // 侵略性
    }

    update(dt) {
        if (!this.alive) return;

        // 兵力自然恢复
        if (this.power < this.maxPower) {
            this.power += this.growthSpeed * dt;
        }

        // 领土随兵力微调 (视觉反馈)
        const targetRadius = this.baseRadius + (this.power / this.maxPower) * 10;
        this.radius += (targetRadius - this.radius) * 0.1;
    }

    draw(ctx) {
        if (!this.alive) return;

        // 绘制领土
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
        
        // 边框
        ctx.lineWidth = 2;
        ctx.strokeStyle = 'rgba(0,0,0,0.2)';
        ctx.stroke();

        // 绘制兵力条
        const barWidth = this.radius * 1.5;
        const barHeight = 6;
        const barX = this.x - barWidth / 2;
        const barY = this.y - this.radius - 15;

        // 背景条
        ctx.fillStyle = 'rgba(0,0,0,0.3)';
        ctx.fillRect(barX, barY, barWidth, barHeight);
        
        // 前景条
        const pct = Math.min(1, this.power / this.maxPower);
        ctx.fillStyle = '#fff';
        ctx.fillRect(barX, barY, barWidth * pct, barHeight);

        // 文字
        ctx.fillStyle = THEMES[currentTheme].text;
        ctx.font = 'bold 12px Arial';
        ctx.textAlign = 'center';
        ctx.fillText(Math.floor(this.power), this.x, this.y + 4);
    }
}

// 初始化画布尺寸
function resize() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();

// 初始化游戏
function initGame() {
    nations = [];
    const w = canvas.width;
    const h = canvas.height;
    
    // 根据屏幕大小动态调整国家数量
    const area = w * h;
    const count = Math.floor(CONFIG.baseNationCount * (area / (800*600)));

    for (let i = 0; i < count; i++) {
        // 随机位置 (留出边距)
        const margin = 50;
        const x = Math.random() * (w - margin * 2) + margin;
        const y = Math.random() * (h - margin * 2) + margin;
        
        // 随机属性:领土大小和战力倍率
        // 有些国家天生就是大国 (半径大,兵力多)
        const isBigPower = Math.random() > 0.8; 
        const sizeMult = isBigPower ? (Math.random() * 0.5 + 1.2) : (Math.random() * 0.5 + 0.6);
        const powerMult = isBigPower ? (Math.random() * 0.5 + 1.5) : (Math.random() * 0.5 + 0.8);
        
        const radius = 25 * sizeMult;
        const color = CONFIG.colors[i % CONFIG.colors.length];
        
        nations.push(new Nation(i, x, y, radius, color, powerMult));
    }
    
    updateStats();
}

// 碰撞与战斗逻辑
function checkCollisions() {
    for (let i = 0; i < nations.length; i++) {
        let n1 = nations[i];
        if (!n1.alive) continue;

        for (let j = i + 1; j < nations.length; j++) {
            let n2 = nations[j];
            if (!n2.alive) continue;

            const dx = n1.x - n2.x;
            const dy = n1.y - n2.y;
            const dist = Math.sqrt(dx*dx + dy*dy);
            const minDist = n1.radius + n2.radius;

            // 如果领土接触
            if (dist < minDist) {
                // 计算重叠程度作为战斗强度
                const overlap = minDist - dist;
                
                // 简单的战斗公式:兵力多的一方侵蚀兵力少的一方
                // 引入随机波动,避免绝对 deterministic
                const powerDiff = n1.power - n2.power;
                
                if (powerDiff > 0) {
                    // n1 攻击 n2
                    const damage = overlap * 0.5 * (n1.power / 100);
                    n2.power -= damage;
                    // n1 也会消耗一点兵力
                    n1.power -= damage * 0.2; 
                } else {
                    // n2 攻击 n1
                    const damage = overlap * 0.5 * (n2.power / 100);
                    n1.power -= damage;
                    n2.power -= damage * 0.2;
                }

                // 死亡判定
                if (n1.power <= 0) killNation(n1);
                if (n2.power <= 0) killNation(n2);
            }
        }
    }
}

function killNation(nation) {
    nation.alive = false;
    nation.power = 0;
    nation.radius = 0; // 视觉上消失
    
    // 可选:将领土分给附近的赢家,这里简化为直接消失产生真空地带
    // 或者让击败者瞬间获得大量领土
    // 这里我们让击败者稍微变大一点作为奖励
    // (需要在循环外处理,简化起见暂略)
}

// 渲染循环
function loop(timestamp) {
    if (!isPaused) {
        const dt = timestamp - lastTime;
        lastTime = timestamp;

        // FPS 计算
        frameCount++;
        if (timestamp - lastFpsTime >= 1000) {
            document.getElementById('fpsCount').innerText = frameCount;
            frameCount = 0;
            lastFpsTime = timestamp;
        }

        // 清屏
        ctx.fillStyle = THEMES[currentTheme].bg;
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // 绘制网格背景 (装饰)
        drawGrid();

        // 更新和绘制国家
        // 先排序,让兵力少的先画,兵力多的在上面 (可选)
        nations.sort((a, b) => a.power - b.power);

        nations.forEach(n => {
            n.update(dt);
            n.draw(ctx);
        });

        checkCollisions();
        updateStats();
    }
    
    animationId = requestAnimationFrame(loop);
}

function drawGrid() {
    ctx.strokeStyle = THEMES[currentTheme].grid;
    ctx.lineWidth = 1;
    ctx.beginPath();
    const gridSize = 50;
    for (let x = 0; x < canvas.width; x += gridSize) {
        ctx.moveTo(x, 0);
        ctx.lineTo(x, canvas.height);
    }
    for (let y = 0; y < canvas.height; y += gridSize) {
        ctx.moveTo(0, y);
        ctx.lineTo(canvas.width, y);
    }
    ctx.stroke();
}

function updateStats() {
    const aliveCount = nations.filter(n => n.alive).length;
    document.getElementById('nationCount').innerText = aliveCount;
    
    if (aliveCount <= 1 && nations.length > 1 && !isPaused) {
        // 游戏结束提示 (可选)
        // console.log("统一天下!");
    }
}

// UI 事件绑定
document.getElementById('restartBtn').addEventListener('click', () => {
    initGame();
});

document.getElementById('pauseBtn').addEventListener('click', () => {
    isPaused = !isPaused;
    if (!isPaused) {
        lastTime = performance.now();
        loop(lastTime);
    }
});

document.getElementById('themeSelect').addEventListener('change', (e) => {
    currentTheme = e.target.value;
    document.body.className = `theme-${currentTheme}`;
});

// 启动
initGame();
lastTime = performance.now();
loop(lastTime);

</script>
</body>
</html>
        
编辑器加载中
预览
控制台