电机工坊模拟器
by FrozenFalcon84169 lines8.0 KB🛠️ Three.js (3D graphics)
<!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.