🎮ArcadeLab

铁轮工会 · 第八代 · 营地原型

by EpicCoder88
338 lines15.4 KB
▶ Play
<!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>
        * { box-sizing: border-box; user-select: none; -webkit-user-select: none; }
        body { margin: 0; overflow: hidden; background-color: #1a252c; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; touch-action: none; }
        canvas { display: block; }
        #ui {
            position: absolute; top: 10px; left: 10px; right: 10px; bottom: 10px;
            pointer-events: none; display: flex; flex-direction: column; justify-content: space-between;
        }
        .top-panel {
            display: flex; justify-content: space-between; gap: 8px;
        }
        .card {
            background: rgba(20, 30, 40, 0.85); color: #ecf0f1; padding: 8px 12px; border-radius: 8px;
            font-size: 13px; border: 1px solid #34495e; backdrop-filter: blur(4px); flex: 1;
        }
        .card b { color: #f1c40f; }
        .log-box {
            background: rgba(20, 30, 40, 0.9); color: #bdc3c7; padding: 10px; border-radius: 8px;
            font-size: 12px; line-height: 1.6; border: 1px solid #34495e; height: 130px; overflow-y: auto;
            display: flex; flex-direction: column; justify-content: flex-end;
        }
        .log-box p { margin: 0; padding: 2px 0; }
        .log-box .sys { color: #3498db; }
        .log-box .warn { color: #e74c3c; font-weight: bold; }
        .log-box .good { color: #2ecc71; }
        #hint {
            position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.6); color: #fff; padding: 10px 20px; border-radius: 20px;
            font-size: 14px; pointer-events: none; opacity: 0; transition: opacity 0.5s;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div id="hint"></div>

    <div id="ui">
        <div class="top-panel">
            <div class="card">
                身份: <b id="role">守法老公民</b><br>
                状态: <b id="status">和平</b>
            </div>
            <div class="card" style="text-align: right;">
                行动力: <b id="energy">100</b> / 100<br>
                位置: <b id="location">中央营地</b>
            </div>
        </div>
        <div class="log-box" id="logBox">
            <p class="sys">[系统] 欢迎来到铁轮工会中央营地。</p>
            <p class="sys">[系统] 点击屏幕移动。去捕猎,或去会议台看看。</p>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        let cw, ch;

        function resize() {
            cw = window.innerWidth;
            ch = window.innerHeight;
            canvas.width = cw;
            canvas.height = ch;
            initMap(); // 重新计算地图坐标
        }

        // ================== 游戏核心数据 ==================
        let state = {
            role: "守法老公民",
            status: "和平",
            energy: 100,
            location: "中央营地",
            logs: []
        };

        let player = { x: cw/2, y: ch/2, radius: 12, speed: 4, targetX: cw/2, targetY: ch/2 };

        // 越轨者、防卫队、猎物等实体
        let entities = [];
        // 地图区域(根据你的手绘图设定)
        let zones = [];

        function initMap() {
            // 重置地图数据(防止屏幕旋转后错位)
            entities = [
                { type: 'prey', x: cw * 0.15, y: ch * 0.2, size: 12, color: '#8B4513', label: '猎物' },
                { type: 'prey', x: cw * 0.85, y: ch * 0.3, size: 12, color: '#8B4513', label: '猎物' },
                { type: 'prey', x: cw * 0.7, y: ch * 0.8, size: 12, color: '#8B4513', label: '猎物' },
                { type: 'guard', x: cw * 0.8, y: ch * 0.7, size: 15, color: '#e74c3c', label: '防卫队' },
                { type: 'guard', x: cw * 0.2, y: ch * 0.8, size: 15, color: '#e74c3c', label: '防卫队' },
                { type: 'poacher', x: cw * 0.2, y: ch * 0.5, size: 16, color: '#9b59b6', label: '越轨者' }
            ];

            zones = [
                // 顶部:外客接待区
                { name: '外客接待区', x: cw/2, y: ch * 0.12, w: 100, h: 40, color: '#95a5a6' },
                // 中部左侧:学徒巢穴、工友巢穴
                { name: '学徒巢穴', x: cw * 0.2, y: ch * 0.35, w: 80, h: 50, color: '#e67e22' },
                { name: '工友巢穴', x: cw * 0.2, y: ch * 0.5, w: 80, h: 50, color: '#d35400' },
                // 底部左侧:育婴室
                { name: '育婴室', x: cw * 0.25, y: ch * 0.75, w: 80, h: 60, color: '#f39c12' },
                // 中部右侧:治疗区、长老巢穴
                { name: '治疗区', x: cw * 0.8, y: ch * 0.35, w: 80, h: 50, color: '#1abc9c' },
                { name: '长老巢穴', x: cw * 0.8, y: ch * 0.5, w: 80, h: 50, color: '#16a085' },
                // 中心:会议台
                { name: '会议台', x: cw * 0.5, y: ch * 0.55, w: 80, h: 60, color: '#8e44ad' },
                // 底部:训练场
                { name: '训练场', x: cw * 0.7, y: ch * 0.75, w: 100, h: 60, color: '#2980b9' },
                // 营地入口(标识)
                { name: '营地入口2', x: cw * 0.08, y: ch * 0.4, w: 40, h: 30, color: '#c0392b' },
                { name: '营地入口1', x: cw * 0.92, y: ch * 0.5, w: 40, h: 30, color: '#c0392b' },
                { name: '秘密通道', x: cw * 0.5, y: ch * 0.95, w: 50, h: 30, color: '#2c3e50' }
            ];
        }

        // ================== 日志系统 ==================
        function addLog(msg, type = 'sys') {
            state.logs.push({ text: msg, type: type });
            if (state.logs.length > 8) state.logs.shift();
            const box = document.getElementById('logBox');
            box.innerHTML = state.logs.map(log => `<p class="${log.type}">${log.text}</p>`).join('');
            box.scrollTop = box.scrollHeight;
        }

        function showHint(text) {
            const hint = document.getElementById('hint');
            hint.textContent = text;
            hint.style.opacity = 1;
            setTimeout(() => { hint.style.opacity = 0; }, 1500);
        }

        // ================== 触摸控制 ==================
        canvas.addEventListener('touchstart', (e) => {
            e.preventDefault();
            const rect = canvas.getBoundingClientRect();
            const touch = e.touches[0];
            if (touch) {
                player.targetX = touch.clientX - rect.left;
                player.targetY = touch.clientY - rect.top;
            }
        }, { passive: false });

        canvas.addEventListener('mousedown', (e) => {
            player.targetX = e.clientX;
            player.targetY = e.clientY;
        });

        // ================== 碰撞与交互逻辑 ==================
        function checkCollisions() {
            // 1. 与动态实体的交互
            entities.forEach(ent => {
                const dist = Math.hypot(player.x - ent.x, player.y - ent.y);
                if (dist < player.radius + ent.size) {
                    if (ent.type === 'prey') {
                        state.energy = Math.min(100, state.energy + 15);
                        addLog("你捕获了猎物。行动力 +15", "good");
                        ent.x = Math.random() * (cw - 100) + 50;
                        ent.y = Math.random() * (ch - 200) + 100;
                    } else if (ent.type === 'guard') {
                        if (state.role === '守法老公民') {
                            addLog("防卫队: 朋友,领地安全。", "sys");
                        } else {
                            addLog("防卫队: 警告!你已被通缉!准备战斗!", "warn");
                            state.status = "被追捕";
                            state.energy -= 10; // 被攻击
                            // 弹开
                            const angle = Math.atan2(player.y - ent.y, player.x - ent.x);
                            player.targetX = player.x + Math.cos(angle) * 80;
                            player.targetY = player.y + Math.sin(angle) * 80;
                        }
                    } else if (ent.type === 'poacher') {
                        if (state.role === '守法老公民') {
                            addLog("你遇到了越轨者!你决定拔出爪子。【超雄模式】激活!", "warn");
                            state.role = "超雄玩家 (大镖客)";
                            state.status = "战斗";
                            showHint("你已切换为超雄玩家!");
                        } else {
                            state.energy -= 5;
                            addLog("你与越轨者发生了冲突。", "warn");
                        }
                        ent.x = Math.random() * (cw - 100) + 50;
                        ent.y = Math.random() * (ch - 200) + 100;
                    }
                }
            });

            // 2. 与地图区域的交互
            let inZone = false;
            zones.forEach(zone => {
                const dx = Math.abs(player.x - zone.x);
                const dy = Math.abs(player.y - zone.y);
                if (dx < zone.w/2 && dy < zone.h/2) {
                    inZone = true;
                    if (state.location !== zone.name) {
                        state.location = zone.name;
                        addLog(`你进入了【${zone.name}】`);
                        // 特定区域效果
                        if (zone.name === '会议台') {
                            addLog("会议台:玳羽会长曾在此发表演讲。公会投票在此进行。", "sys");
                            if (state.role === '超雄玩家 (大镖客)') {
                                addLog("由于你处于通缉状态,你不敢久留。", "warn");
                            }
                        } else if (zone.name === '育婴室') {
                            addLog("育婴室:幼崽的庇护所。任何伤害幼崽的行为都是重罪。", "good");
                            if (state.role === '超雄玩家 (大镖客)') {
                                addLog("防卫队: 离育婴室远点!", "warn");
                                state.energy -= 10;
                            }
                        } else if (zone.name === '训练场') {
                            addLog("训练场:你可以在此提升战斗技巧。", "sys");
                        } else if (zone.name === '秘密通道') {
                            addLog("秘密通道:这是避开防卫队的绝佳路线。", "sys");
                        } else if (zone.name === '治疗区') {
                            addLog("治疗区:治愈伤口,学习医学知识。", "good");
                        }
                    }
                }
            });
            if (!inZone) state.location = "中央营地外围";

            // 边界限制
            player.x = Math.max(player.radius, Math.min(cw - player.radius, player.x));
            player.y = Math.max(player.radius, Math.min(ch - player.radius, player.y));
        }

        // ================== 主循环 ==================
        function update() {
            const dx = player.targetX - player.x;
            const dy = player.targetY - player.y;
            const distance = Math.hypot(dx, dy);

            // 移动逻辑
            if (distance > 5) {
                player.x += (dx / distance) * player.speed;
                player.y += (dy / distance) * player.speed;
                
                // 消耗行动力(跑动越久越累)
                if (state.energy > 0) {
                    state.energy -= 0.08;
                } else {
                    addLog("你太累了,跑不动了。去找点吃的吧。", "warn");
                    player.targetX = player.x;
                    player.targetY = player.y;
                }
            }

            // 碰撞检测
            checkCollisions();

            // 实时更新UI
            document.getElementById('role').textContent = state.role;
            document.getElementById('status').textContent = state.status;
            document.getElementById('energy').textContent = Math.floor(state.energy);
            document.getElementById('location').textContent = state.location;

            // ================== 渲染画面 ==================
            // 1. 绘制草地(暗绿色,符合野外营地风格)
            ctx.fillStyle = '#2c3e50';
            ctx.fillRect(0, 0, cw, ch);
            ctx.fillStyle = '#273746';
            ctx.fillRect(20, 20, cw - 40, ch - 40); // 内部场地

            // 2. 绘制地图区域(带标签的矩形)
            zones.forEach(zone => {
                ctx.fillStyle = zone.color + '88'; // 半透明
                ctx.fillRect(zone.x - zone.w/2, zone.y - zone.h/2, zone.w, zone.h);
                ctx.strokeStyle = zone.color;
                ctx.lineWidth = 2;
                ctx.strokeRect(zone.x - zone.w/2, zone.y - zone.h/2, zone.w, zone.h);
                
                // 区域标签
                ctx.fillStyle = '#ecf0f1';
                ctx.font = 'bold 12px sans-serif';
                ctx.textAlign = 'center';
                ctx.fillText(zone.name, zone.x, zone.y + 5);
            });

            // 3. 绘制实体(猎物、防卫队、越轨者)
            entities.forEach(ent => {
                ctx.beginPath();
                if (ent.type === 'prey') {
                    ctx.rect(ent.x - ent.size/2, ent.y - ent.size/2, ent.size, ent.size);
                    ctx.fillStyle = ent.color;
                } else if (ent.type === 'guard') {
                    ctx.moveTo(ent.x, ent.y - ent.size);
                    ctx.lineTo(ent.x + ent.size, ent.y + ent.size);
                    ctx.lineTo(ent.x - ent.size, ent.y + ent.size);
                    ctx.fillStyle = ent.color;
                } else {
                    ctx.arc(ent.x, ent.y, ent.size, 0, Math.PI * 2);
                    ctx.fillStyle = ent.color;
                }
                ctx.fill();
                
                // 实体标签
                ctx.fillStyle = '#bdc3c7';
                ctx.font = '10px sans-serif';
                ctx.textAlign = 'center';
                ctx.fillText(ent.label, ent.x, ent.y - ent.size - 5);
            });

            // 4. 绘制玩家(蓝圈,带眼睛的猫脸感)
            ctx.beginPath();
            ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
            ctx.fillStyle = '#3498db';
            ctx.fill();
            ctx.strokeStyle = '#ecf0f1';
            ctx.lineWidth = 2;
            ctx.stroke();

            // 画两只小耳朵
            ctx.beginPath();
            ctx.moveTo(player.x - 6, player.y - 10);
            ctx.lineTo(player.x - 2, player.y - 18);
            ctx.lineTo(player.x + 2, player.y - 10);
            ctx.fillStyle = '#ecf0f1';
            ctx.fill();
            ctx.beginPath();
            ctx.moveTo(player.x + 2, player.y - 10);
            ctx.lineTo(player.x + 6, player.y - 18);
            ctx.lineTo(player.x + 10, player.y - 10);
            ctx.fill();

            requestAnimationFrame(update);
        }

        // 初始化
        resize();
        update();
    </script>
</body>
</html>

Game Source: 铁轮工会 · 第八代 · 营地原型

Creator: EpicCoder88

Libraries: none

Complexity: complex (338 lines, 15.4 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-epiccoder88-muqnrujx" to link back to the original. Then publish at arcadelab.ai/publish.