🎮ArcadeLab

电机工坊模拟器

by FrozenFalcon84
169 lines8.0 KB🛠️ Three.js (3D graphics)
▶ 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>
        *{margin:0;padding:0;box-sizing:border-box;font-family:system-ui}
        body{background:#12141a;color:#fff;overflow:hidden}
        #gameCanvas{width:100vw;height:80vh;display:block;background:#1a1d26}
        .control-bar{height:20vh;background:#222733;padding:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
        .btn{padding:10px 14px;border:none;border-radius:8px;background:#2578ff;color:#fff;font-size:15px;touch-action:manipulation}
        .btn-danger{background:#ff4545}
        .btn-green{background:#28c76f}
        .info{color:#ccc;font-size:13px;width:100%}
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div class="control-bar">
        <div class="info">触控操作:滑动旋转模型|双指缩放|拖拽配件接线</div>
        <button class="btn" id="btnBrush">130有刷电机</button>
        <button class="btn" id="btnRc">RC蚊车无刷电机</button>
        <button class="btn" id="btnDrone">穿越机电机</button>
        <button class="btn" id="btnFan">涵道电机</button>
        <button class="btn btn-green" id="powerOn">通电启动</button>
        <button class="btn btn-danger" id="powerOff">断电停机</button>
        <button class="btn" id="addPaper">放置纸巾</button>
        <button class="btn" id="addSticker">粘贴旋转贴纸</button>
    </div><script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/controls/OrbitControls.js"></script>
    <script>
        const AudioCtx = new (window.AudioContext || window.webkitAudioContext)();
        function playMotorSound(speed){
            const osc = AudioCtx.createOscillator();
            const gain = AudioCtx.createGain();
            osc.type = 'sawtooth';
            osc.frequency.value = 80 + speed * 12;
            gain.gain.value = 0.12;
            osc.connect(gain);
            gain.connect(AudioCtx.destination);
            osc.start();
            return {osc,gain};
        }
        let motorAudio = null;
        let scene,camera,render,controls,motor,sticker,paper,windZone;
        let motorSpeed = 0;
        let isRun = false;
        function init3D(){
            const canvas = document.getElementById('gameCanvas');
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x1a1d26);
            camera = new THREE.PerspectiveCamera(60, canvas.clientWidth/canvas.clientHeight, 0.1, 1000);
            camera.position.set(0,4,8);
            render = new THREE.WebGLRenderer({canvas,antialias:true});
            render.setSize(canvas.clientWidth,canvas.clientHeight);
            controls = new THREE.OrbitControls(camera,canvas);
            controls.enableDamping = true;
            const light = new THREE.DirectionalLight(0xffffff,1);
            light.position.set(5,10,7);
            scene.add(light);
            scene.add(new THREE.AmbientLight(0x444444));
            const floorGeo = new THREE.BoxGeometry(12,0.3,8);
            const floorMat = new THREE.MeshStandardMaterial({color:0x333333});
            scene.add(new THREE.Mesh(floorGeo,floorMat));
            windZone = new THREE.Group();
            scene.add(windZone);
            createBrushMotor();
            loopRender();
        }function clearMotor(){
            if(motor) scene.remove(motor);
            if(sticker) scene.remove(sticker);
            if(paper) scene.remove(paper);
            motor = null; sticker = null; paper = null;
            motorSpeed = 0;
        }
        function createBrushMotor(){
            clearMotor();
            const body = new THREE.Mesh(new THREE.CylinderGeometry(0.6,0.6,2.2,16),new THREE.MeshStandardMaterial({color:0xaaaaaa}));
            const shaft = new THREE.Mesh(new THREE.CylinderGeometry(0.12,0.12,1.4,8),new THREE.MeshStandardMaterial({color:0xffd700}));
            shaft.position.y = 1.2;
            motor = new THREE.Group();
            motor.add(body,shaft);
            motor.position.y = 1.2;
            scene.add(motor);
        }
        function createRcMotor(){
            clearMotor();
            const body = new THREE.Mesh(new THREE.CylinderGeometry(0.55,0.55,1.6,20),new THREE.MeshStandardMaterial({color:0x2277dd}));
            const shaft = new THREE.Mesh(new THREE.CylinderGeometry(0.1,0.1,1,8),new THREE.MeshStandardMaterial({color:0xffd700}));
            shaft.position.y = 0.9;
            motor = new THREE.Group();
            motor.add(body,shaft);
            motor.position.y = 1.2;
            scene.add(motor);
        }
        function createDroneMotor(){
            clearMotor();
            const base = new THREE.Mesh(new THREE.CylinderGeometry(0.7,0.7,0.4,24),new THREE.MeshStandardMaterial({color:0x222222}));
            const rotor = new THREE.Mesh(new THREE.CylinderGeometry(0.08,0.08,1.2,6),new THREE.MeshStandardMaterial({color:0xcccccc}));
            rotor.position.y = 0.6;
            motor = new THREE.Group();
            motor.add(base,rotor);
            motor.position.y = 1.2;
            scene.add(motor);
        }
        function createFanMotor(){
            clearMotor();
            const shell = new THREE.Mesh(new THREE.CylinderGeometry(1,1,2.5,32),new THREE.MeshStandardMaterial({color:0x444444}));
            const blade = new THREE.Mesh(new THREE.BoxGeometry(1.8,0.05,0.2),new THREE.MeshStandardMaterial({color:0xeeeeee}));
            blade.position.y = 1;
            motor = new THREE.Group();
            motor.add(shell,blade);
            motor.position.y = 1.2;
            scene.add(motor);
        }
        function addSticker(){
            if(sticker) scene.remove(sticker);
            sticker = new THREE.Mesh(new THREE.CircleGeometry(0.4,16),new THREE.MeshStandardMaterial({color:0xff3333}));
            sticker.position.y = 2;
            motor.add(sticker);
        }
        function addPaperSheet(){
            if(paper) scene.remove(paper);
            paper = new THREE.Mesh(new THREE.PlaneGeometry(1,1.5),new THREE.MeshStandardMaterial({color:0xffffff}));
            paper.position.set(2,1.5,0);
            scene.add(paper);
        }function loopRender(){
            requestAnimationFrame(loopRender);
            controls.update();
            if(isRun && motorSpeed < 12){
                motorSpeed += 0.25;
                if(motorAudio) motorAudio.osc.frequency.value = 80 + motorSpeed *12;
            }else if(!isRun && motorSpeed>0){
                motorSpeed -=0.15;
                if(motorAudio) motorAudio.osc.frequency.value = 80 + motorSpeed *12;
            }
            if(motor) motor.rotation.y += motorSpeed * 0.008;
            if(sticker) sticker.rotation.z += motorSpeed *0.01;
            if(paper && motorSpeed>6){
                paper.position.z -= 0.06;
                paper.rotation.x += 0.03;
            }
            render.render(scene,camera);
        }
        window.onload = function(){
            init3D();
            document.getElementById('btnBrush').onclick = createBrushMotor;
            document.getElementById('btnRc').onclick = createRcMotor;
            document.getElementById('btnDrone').onclick = createDroneMotor;
            document.getElementById('btnFan').onclick = createFanMotor;
            document.getElementById('addPaper').onclick = addPaperSheet;
            document.getElementById('addSticker').onclick = addSticker;
            document.getElementById('powerOn').onclick = function(){
                isRun = true;
                if(!motorAudio) motorAudio = playMotorSound(0);
                AudioCtx.resume();
            }
            document.getElementById('powerOff').onclick = function(){
                isRun = false;
                if(motorAudio){
                    motorAudio.osc.stop();
                    motorAudio = null;
                }
            }
        }
    </script>
 </body>
 </html>

Game Source: 电机工坊模拟器

Creator: FrozenFalcon84

Libraries: three

Complexity: moderate (169 lines, 8.0 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-frozenfalcon84" to link back to the original. Then publish at arcadelab.ai/publish.