官网ds(可能是v4)、glm5.1、gemini3.1pro网页版生成极简版mc测试
- 内容介绍
- 文章标签
- 相关推荐
提示词:用three.js实现一个类似于mc的小游戏,玩家可以通过wasd走动、视野里只需要随机加载普通泥土块、玩家能够放置摧毁方块,把完整代码给我,我希望复制到html文件中就能够运行
ds官网官网专家模式:能够上下左右移动跳跃,放置摧毁方块,但是方向键是反的,体积碰撞什么的没问题
image1920×964 288 KB
glm5.1(trae cn版 上使用的):没有大问题,完全遵循了指令,只是画面帧率不高,有点卡顿
image3792×1896 259 KB
gemini网页版(flash和pro都试了,效果差不多):移动和放置方块没问题,但是移动一定距离后就会穿模并回到原点,试了三次都是一样的问题
image1920×949 135 KB
在这个任务上,个人感觉glm5.1 > ds官网 => gemini官网。
以下是对话:
- ds:https://chat.deepseek.com/share/8fpzg5lwrfstmdk2mb
- gemini:https://gemini.google.com/share/21440ed2c0a1
- glm5:
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Mini MC</title>
<style>
* { margin: 0; padding: 0; }
body { overflow: hidden; background: #000; }
canvas { display: block; }
#crosshair {
position: fixed; top: 50%; left: 50%;
transform: translate(-50%, -50%);
color: #fff; font-size: 24px; pointer-events: none;
text-shadow: 0 0 2px #000;
font-family: monospace;
z-index: 10;
}
#info {
position: fixed; top: 10px; left: 10px;
color: #fff; font-family: monospace; font-size: 14px;
background: rgba(0,0,0,0.5); padding: 10px; border-radius: 5px;
z-index: 10; pointer-events: none;
}
#startScreen {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8); display: flex; flex-direction: column;
align-items: center; justify-content: center; z-index: 100;
color: #fff; font-family: monospace;
}
#startScreen h1 { font-size: 48px; margin-bottom: 20px; color: #8B6914; }
#startScreen p { font-size: 16px; margin: 5px 0; }
#startScreen button {
margin-top: 30px; padding: 15px 40px; font-size: 20px;
font-family: monospace; cursor: pointer; background: #8B6914;
color: #fff; border: 3px solid #5a4510; border-radius: 5px;
}
#startScreen button:hover { background: #a07818; }
</style>
</head>
<body>
<div id="crosshair">+</div>
<div id="info">
WASD - 移动 | 空格 - 跳跃 | 鼠标 - 视角<br>
左键 - 摧毁方块 | 右键 - 放置方块 | ESC - 释放鼠标
</div>
<div id="startScreen">
<h1>Mini MC</h1>
<p>WASD - 移动</p>
<p>空格 - 跳跃</p>
<p>鼠标 - 视角</p>
<p>左键 - 摧毁方块</p>
<p>右键 - 放置方块</p>
<button id="startBtn">开始游戏</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
const CHUNK_SIZE = 16;
const WORLD_HEIGHT = 32;
const RENDER_DIST = 3;
const BLOCK_SIZE = 1;
const GRAVITY = -25;
const JUMP_FORCE = 9;
const MOVE_SPEED = 6;
const MOUSE_SENS = 0.002;
const PLAYER_HEIGHT = 1.7;
const PLAYER_RADIUS = 0.3;
const blocks = new Map();
const blockMeshes = new Map();
let scene, camera, renderer;
let yaw = 0, pitch = 0;
let velocity = new THREE.Vector3();
let onGround = false;
let isLocked = false;
const keys = {};
const raycaster = new THREE.Raycaster();
raycaster.far = 8;
const highlightMesh = new THREE.Mesh(
new THREE.BoxGeometry(1.005, 1.005, 1.005),
new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, transparent: true, opacity: 0.5 })
);
highlightMesh.visible = false;
const dirtColors = [
new THREE.Color(0x8B6914),
new THREE.Color(0x7a5c12),
new THREE.Color(0x9c7416),
new THREE.Color(0x6b4e0e),
new THREE.Color(0x846218),
];
const grassTopColor = new THREE.Color(0x4a8c2a);
const grassSideColor = new THREE.Color(0x6b8c3a);
const blockGeometry = new THREE.BoxGeometry(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
const dirtMaterials = dirtColors.map(c => new THREE.MeshLambertMaterial({ color: c }));
function blockKey(x, y, z) { return `${x},${y},${z}`; }
function chunkKey(cx, cz) { return `${cx},${cz}`; }
function getBlock(x, y, z) { return blocks.get(blockKey(x, y, z)) || 0; }
function setBlock(x, y, z, type) {
const key = blockKey(x, y, z);
if (type === 0) {
blocks.delete(key);
removeBlockMesh(x, y, z);
} else {
blocks.set(key, type);
addBlockMesh(x, y, z, type);
}
}
function createBlockMaterial(type) {
if (type === 1) {
return new THREE.MeshLambertMaterial({ color: dirtColors[Math.floor(Math.random() * dirtColors.length)] });
} else if (type === 2) {
return [
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassTopColor }),
new THREE.MeshLambertMaterial({ color: dirtColors[0] }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
];
}
return dirtMaterials[0];
}
function addBlockMesh(x, y, z, type) {
const key = blockKey(x, y, z);
if (blockMeshes.has(key)) {
scene.remove(blockMeshes.get(key));
}
const mat = createBlockMaterial(type);
const mesh = new THREE.Mesh(blockGeometry, mat);
mesh.position.set(x + 0.5, y + 0.5, z + 0.5);
mesh.userData = { blockX: x, blockY: y, blockZ: z };
scene.add(mesh);
blockMeshes.set(key, mesh);
}
function removeBlockMesh(x, y, z) {
const key = blockKey(x, y, z);
const mesh = blockMeshes.get(key);
if (mesh) {
scene.remove(mesh);
if (Array.isArray(mesh.material)) {
mesh.material.forEach(m => m.dispose());
} else {
mesh.material.dispose();
}
blockMeshes.delete(key);
}
}
function simpleNoise(x, z) {
const n = Math.sin(x * 0.1 + z * 0.15) * 0.5 +
Math.sin(x * 0.05 - z * 0.08) * 0.3 +
Math.sin(x * 0.2 + z * 0.1) * 0.2;
return n;
}
function getTerrainHeight(x, z) {
return Math.floor(simpleNoise(x, z) * 4 + 8);
}
function generateChunk(cx, cz) {
const startX = cx * CHUNK_SIZE;
const startZ = cz * CHUNK_SIZE;
for (let x = startX; x < startX + CHUNK_SIZE; x++) {
for (let z = startZ; z < startZ + CHUNK_SIZE; z++) {
const h = getTerrainHeight(x, z);
setBlock(x, h, z, 2);
for (let y = h - 1; y >= h - 3 && y >= 0; y--) {
setBlock(x, y, z, 1);
}
}
}
}
function removeChunk(cx, cz) {
const startX = cx * CHUNK_SIZE;
const startZ = cz * CHUNK_SIZE;
for (let x = startX; x < startX + CHUNK_SIZE; x++) {
for (let z = startZ; z < startZ + CHUNK_SIZE; z++) {
for (let y = 0; y < WORLD_HEIGHT; y++) {
const key = blockKey(x, y, z);
if (blocks.has(key)) {
blocks.delete(key);
removeBlockMesh(x, y, z);
}
}
}
}
}
const loadedChunks = new Set();
function updateChunks() {
const cx = Math.floor(camera.position.x / CHUNK_SIZE);
const cz = Math.floor(camera.position.z / CHUNK_SIZE);
const needed = new Set();
for (let dx = -RENDER_DIST; dx <= RENDER_DIST; dx++) {
for (let dz = -RENDER_DIST; dz <= RENDER_DIST; dz++) {
const key = chunkKey(cx + dx, cz + dz);
needed.add(key);
if (!loadedChunks.has(key)) {
generateChunk(cx + dx, cz + dz);
loadedChunks.add(key);
}
}
}
for (const key of loadedChunks) {
if (!needed.has(key)) {
const [ox, oz] = key.split(',').map(Number);
removeChunk(ox, oz);
loadedChunks.delete(key);
}
}
}
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.Fog(0x87CEEB, 30, 60);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
renderer = new THREE.WebGLRenderer({ antialias: false });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const ambientLight = new THREE.AmbientLight(0x808080);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(50, 80, 30);
scene.add(dirLight);
scene.add(highlightMesh);
const spawnX = 0, spawnZ = 0;
const spawnH = getTerrainHeight(spawnX, spawnZ);
camera.position.set(spawnX + 0.5, spawnH + 2 + PLAYER_HEIGHT, spawnZ + 0.5);
updateChunks();
document.addEventListener('keydown', e => { keys[e.code] = true; });
document.addEventListener('keyup', e => { keys[e.code] = false; });
document.addEventListener('mousemove', e => {
if (!isLocked) return;
yaw -= e.movementX * MOUSE_SENS;
pitch -= e.movementY * MOUSE_SENS;
pitch = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, pitch));
});
document.addEventListener('mousedown', e => {
if (!isLocked) return;
if (e.button === 0) destroyBlock();
else if (e.button === 2) placeBlock();
});
document.addEventListener('contextmenu', e => e.preventDefault());
document.addEventListener('pointerlockchange', () => {
isLocked = document.pointerLockElement === renderer.domElement;
document.getElementById('startScreen').style.display = isLocked ? 'none' : 'flex';
});
document.getElementById('startBtn').addEventListener('click', () => {
renderer.domElement.requestPointerLock();
});
renderer.domElement.addEventListener('click', () => {
if (!isLocked) renderer.domElement.requestPointerLock();
});
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
}
function getForward() {
return new THREE.Vector3(-Math.sin(yaw), 0, -Math.cos(yaw)).normalize();
}
function getRight() {
return new THREE.Vector3(Math.cos(yaw), 0, -Math.sin(yaw)).normalize();
}
function collidesWithBlock(px, py, pz) {
const minX = Math.floor(px - PLAYER_RADIUS);
const maxX = Math.floor(px + PLAYER_RADIUS);
const minY = Math.floor(py);
const maxY = Math.floor(py + PLAYER_HEIGHT);
const minZ = Math.floor(pz - PLAYER_RADIUS);
const maxZ = Math.floor(pz + PLAYER_RADIUS);
for (let x = minX; x <= maxX; x++) {
for (let y = minY; y <= maxY; y++) {
for (let z = minZ; z <= maxZ; z++) {
if (getBlock(x, y, z) !== 0) {
const bx = x, by = y, bz = z;
if (px + PLAYER_RADIUS > bx && px - PLAYER_RADIUS < bx + 1 &&
py + PLAYER_HEIGHT > by && py < by + 1 &&
pz + PLAYER_RADIUS > bz && pz - PLAYER_RADIUS < bz + 1) {
return true;
}
}
}
}
}
return false;
}
let lastTime = performance.now();
function update() {
const now = performance.now();
const dt = Math.min((now - lastTime) / 1000, 0.05);
lastTime = now;
if (!isLocked) return;
const forward = getForward();
const right = getRight();
const moveDir = new THREE.Vector3(0, 0, 0);
if (keys['KeyW']) moveDir.add(forward);
if (keys['KeyS']) moveDir.sub(forward);
if (keys['KeyD']) moveDir.add(right);
if (keys['KeyA']) moveDir.sub(right);
if (moveDir.length() > 0) moveDir.normalize();
velocity.x = moveDir.x * MOVE_SPEED;
velocity.z = moveDir.z * MOVE_SPEED;
velocity.y += GRAVITY * dt;
if (keys['Space'] && onGround) {
velocity.y = JUMP_FORCE;
onGround = false;
}
const pos = camera.position;
const newX = pos.x + velocity.x * dt;
if (!collidesWithBlock(newX, pos.y - PLAYER_HEIGHT, pos.z)) {
pos.x = newX;
} else {
velocity.x = 0;
}
const newZ = pos.z + velocity.z * dt;
if (!collidesWithBlock(pos.x, pos.y - PLAYER_HEIGHT, newZ)) {
pos.z = newZ;
} else {
velocity.z = 0;
}
const newY = pos.y + velocity.y * dt;
if (!collidesWithBlock(pos.x, newY - PLAYER_HEIGHT, pos.z)) {
pos.y = newY;
onGround = false;
} else {
if (velocity.y < 0) onGround = true;
velocity.y = 0;
}
if (pos.y < -20) {
const h = getTerrainHeight(Math.floor(pos.x), Math.floor(pos.z));
pos.y = h + 2 + PLAYER_HEIGHT;
velocity.set(0, 0, 0);
}
camera.rotation.order = 'YXZ';
camera.rotation.y = yaw;
camera.rotation.x = pitch;
updateHighlight();
updateChunks();
}
function getTargetBlock() {
raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
const meshArray = Array.from(blockMeshes.values());
const intersects = raycaster.intersectObjects(meshArray);
if (intersects.length > 0) {
return intersects[0];
}
return null;
}
function updateHighlight() {
const hit = getTargetBlock();
if (hit) {
const ud = hit.object.userData;
highlightMesh.position.set(ud.blockX + 0.5, ud.blockY + 0.5, ud.blockZ + 0.5);
highlightMesh.visible = true;
} else {
highlightMesh.visible = false;
}
}
function destroyBlock() {
const hit = getTargetBlock();
if (hit) {
const ud = hit.object.userData;
setBlock(ud.blockX, ud.blockY, ud.blockZ, 0);
}
}
function placeBlock() {
const hit = getTargetBlock();
if (hit) {
const normal = hit.face.normal;
const ud = hit.object.userData;
const nx = ud.blockX + Math.round(normal.x);
const ny = ud.blockY + Math.round(normal.y);
const nz = ud.blockZ + Math.round(normal.z);
if (ny >= 0 && ny < WORLD_HEIGHT) {
const px = camera.position.x;
const py = camera.position.y - PLAYER_HEIGHT;
const pz = camera.position.z;
if (!(px + PLAYER_RADIUS > nx && px - PLAYER_RADIUS < nx + 1 &&
py + PLAYER_HEIGHT > ny && py < ny + 1 &&
pz + PLAYER_RADIUS > nz && pz - PLAYER_RADIUS < nz + 1)) {
setBlock(nx, ny, nz, 1);
}
}
}
}
function animate() {
requestAnimationFrame(animate);
update();
renderer.render(scene, camera);
}
init();
animate();
</script>
</body>
</html>```
网友解答:
--【壹】--: sagiri:
gemini网页版
网页版的Gemini降智到一定程度了
这是我的提示词
image711×309 43 KB
这是vertex渠道的Gemini 3.1 pro high thinking effort的表现
JS-Craft
image1908×877 209 KB
deepseek网页版专家模式的代码写的还可以,可玩性几乎为0,把我的小破笔记本卡死了
⛏️ VoxelCraft — Minecraft Clone
image1899×886 375 KB
--【贰】--:
这个速度和效果,是可用状态了,起码不想M2.7胡说八道的
--【叁】--:
不知道目前官网上的是不是真v4,但是比官方api的v3.2强,v3.2写的代码完全不能用
提示词:用three.js实现一个类似于mc的小游戏,玩家可以通过wasd走动、视野里只需要随机加载普通泥土块、玩家能够放置摧毁方块,把完整代码给我,我希望复制到html文件中就能够运行
ds官网官网专家模式:能够上下左右移动跳跃,放置摧毁方块,但是方向键是反的,体积碰撞什么的没问题
image1920×964 288 KB
glm5.1(trae cn版 上使用的):没有大问题,完全遵循了指令,只是画面帧率不高,有点卡顿
image3792×1896 259 KB
gemini网页版(flash和pro都试了,效果差不多):移动和放置方块没问题,但是移动一定距离后就会穿模并回到原点,试了三次都是一样的问题
image1920×949 135 KB
在这个任务上,个人感觉glm5.1 > ds官网 => gemini官网。
以下是对话:
- ds:https://chat.deepseek.com/share/8fpzg5lwrfstmdk2mb
- gemini:https://gemini.google.com/share/21440ed2c0a1
- glm5:
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Mini MC</title>
<style>
* { margin: 0; padding: 0; }
body { overflow: hidden; background: #000; }
canvas { display: block; }
#crosshair {
position: fixed; top: 50%; left: 50%;
transform: translate(-50%, -50%);
color: #fff; font-size: 24px; pointer-events: none;
text-shadow: 0 0 2px #000;
font-family: monospace;
z-index: 10;
}
#info {
position: fixed; top: 10px; left: 10px;
color: #fff; font-family: monospace; font-size: 14px;
background: rgba(0,0,0,0.5); padding: 10px; border-radius: 5px;
z-index: 10; pointer-events: none;
}
#startScreen {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8); display: flex; flex-direction: column;
align-items: center; justify-content: center; z-index: 100;
color: #fff; font-family: monospace;
}
#startScreen h1 { font-size: 48px; margin-bottom: 20px; color: #8B6914; }
#startScreen p { font-size: 16px; margin: 5px 0; }
#startScreen button {
margin-top: 30px; padding: 15px 40px; font-size: 20px;
font-family: monospace; cursor: pointer; background: #8B6914;
color: #fff; border: 3px solid #5a4510; border-radius: 5px;
}
#startScreen button:hover { background: #a07818; }
</style>
</head>
<body>
<div id="crosshair">+</div>
<div id="info">
WASD - 移动 | 空格 - 跳跃 | 鼠标 - 视角<br>
左键 - 摧毁方块 | 右键 - 放置方块 | ESC - 释放鼠标
</div>
<div id="startScreen">
<h1>Mini MC</h1>
<p>WASD - 移动</p>
<p>空格 - 跳跃</p>
<p>鼠标 - 视角</p>
<p>左键 - 摧毁方块</p>
<p>右键 - 放置方块</p>
<button id="startBtn">开始游戏</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
const CHUNK_SIZE = 16;
const WORLD_HEIGHT = 32;
const RENDER_DIST = 3;
const BLOCK_SIZE = 1;
const GRAVITY = -25;
const JUMP_FORCE = 9;
const MOVE_SPEED = 6;
const MOUSE_SENS = 0.002;
const PLAYER_HEIGHT = 1.7;
const PLAYER_RADIUS = 0.3;
const blocks = new Map();
const blockMeshes = new Map();
let scene, camera, renderer;
let yaw = 0, pitch = 0;
let velocity = new THREE.Vector3();
let onGround = false;
let isLocked = false;
const keys = {};
const raycaster = new THREE.Raycaster();
raycaster.far = 8;
const highlightMesh = new THREE.Mesh(
new THREE.BoxGeometry(1.005, 1.005, 1.005),
new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, transparent: true, opacity: 0.5 })
);
highlightMesh.visible = false;
const dirtColors = [
new THREE.Color(0x8B6914),
new THREE.Color(0x7a5c12),
new THREE.Color(0x9c7416),
new THREE.Color(0x6b4e0e),
new THREE.Color(0x846218),
];
const grassTopColor = new THREE.Color(0x4a8c2a);
const grassSideColor = new THREE.Color(0x6b8c3a);
const blockGeometry = new THREE.BoxGeometry(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
const dirtMaterials = dirtColors.map(c => new THREE.MeshLambertMaterial({ color: c }));
function blockKey(x, y, z) { return `${x},${y},${z}`; }
function chunkKey(cx, cz) { return `${cx},${cz}`; }
function getBlock(x, y, z) { return blocks.get(blockKey(x, y, z)) || 0; }
function setBlock(x, y, z, type) {
const key = blockKey(x, y, z);
if (type === 0) {
blocks.delete(key);
removeBlockMesh(x, y, z);
} else {
blocks.set(key, type);
addBlockMesh(x, y, z, type);
}
}
function createBlockMaterial(type) {
if (type === 1) {
return new THREE.MeshLambertMaterial({ color: dirtColors[Math.floor(Math.random() * dirtColors.length)] });
} else if (type === 2) {
return [
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassTopColor }),
new THREE.MeshLambertMaterial({ color: dirtColors[0] }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
new THREE.MeshLambertMaterial({ color: grassSideColor }),
];
}
return dirtMaterials[0];
}
function addBlockMesh(x, y, z, type) {
const key = blockKey(x, y, z);
if (blockMeshes.has(key)) {
scene.remove(blockMeshes.get(key));
}
const mat = createBlockMaterial(type);
const mesh = new THREE.Mesh(blockGeometry, mat);
mesh.position.set(x + 0.5, y + 0.5, z + 0.5);
mesh.userData = { blockX: x, blockY: y, blockZ: z };
scene.add(mesh);
blockMeshes.set(key, mesh);
}
function removeBlockMesh(x, y, z) {
const key = blockKey(x, y, z);
const mesh = blockMeshes.get(key);
if (mesh) {
scene.remove(mesh);
if (Array.isArray(mesh.material)) {
mesh.material.forEach(m => m.dispose());
} else {
mesh.material.dispose();
}
blockMeshes.delete(key);
}
}
function simpleNoise(x, z) {
const n = Math.sin(x * 0.1 + z * 0.15) * 0.5 +
Math.sin(x * 0.05 - z * 0.08) * 0.3 +
Math.sin(x * 0.2 + z * 0.1) * 0.2;
return n;
}
function getTerrainHeight(x, z) {
return Math.floor(simpleNoise(x, z) * 4 + 8);
}
function generateChunk(cx, cz) {
const startX = cx * CHUNK_SIZE;
const startZ = cz * CHUNK_SIZE;
for (let x = startX; x < startX + CHUNK_SIZE; x++) {
for (let z = startZ; z < startZ + CHUNK_SIZE; z++) {
const h = getTerrainHeight(x, z);
setBlock(x, h, z, 2);
for (let y = h - 1; y >= h - 3 && y >= 0; y--) {
setBlock(x, y, z, 1);
}
}
}
}
function removeChunk(cx, cz) {
const startX = cx * CHUNK_SIZE;
const startZ = cz * CHUNK_SIZE;
for (let x = startX; x < startX + CHUNK_SIZE; x++) {
for (let z = startZ; z < startZ + CHUNK_SIZE; z++) {
for (let y = 0; y < WORLD_HEIGHT; y++) {
const key = blockKey(x, y, z);
if (blocks.has(key)) {
blocks.delete(key);
removeBlockMesh(x, y, z);
}
}
}
}
}
const loadedChunks = new Set();
function updateChunks() {
const cx = Math.floor(camera.position.x / CHUNK_SIZE);
const cz = Math.floor(camera.position.z / CHUNK_SIZE);
const needed = new Set();
for (let dx = -RENDER_DIST; dx <= RENDER_DIST; dx++) {
for (let dz = -RENDER_DIST; dz <= RENDER_DIST; dz++) {
const key = chunkKey(cx + dx, cz + dz);
needed.add(key);
if (!loadedChunks.has(key)) {
generateChunk(cx + dx, cz + dz);
loadedChunks.add(key);
}
}
}
for (const key of loadedChunks) {
if (!needed.has(key)) {
const [ox, oz] = key.split(',').map(Number);
removeChunk(ox, oz);
loadedChunks.delete(key);
}
}
}
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.Fog(0x87CEEB, 30, 60);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
renderer = new THREE.WebGLRenderer({ antialias: false });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const ambientLight = new THREE.AmbientLight(0x808080);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(50, 80, 30);
scene.add(dirLight);
scene.add(highlightMesh);
const spawnX = 0, spawnZ = 0;
const spawnH = getTerrainHeight(spawnX, spawnZ);
camera.position.set(spawnX + 0.5, spawnH + 2 + PLAYER_HEIGHT, spawnZ + 0.5);
updateChunks();
document.addEventListener('keydown', e => { keys[e.code] = true; });
document.addEventListener('keyup', e => { keys[e.code] = false; });
document.addEventListener('mousemove', e => {
if (!isLocked) return;
yaw -= e.movementX * MOUSE_SENS;
pitch -= e.movementY * MOUSE_SENS;
pitch = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, pitch));
});
document.addEventListener('mousedown', e => {
if (!isLocked) return;
if (e.button === 0) destroyBlock();
else if (e.button === 2) placeBlock();
});
document.addEventListener('contextmenu', e => e.preventDefault());
document.addEventListener('pointerlockchange', () => {
isLocked = document.pointerLockElement === renderer.domElement;
document.getElementById('startScreen').style.display = isLocked ? 'none' : 'flex';
});
document.getElementById('startBtn').addEventListener('click', () => {
renderer.domElement.requestPointerLock();
});
renderer.domElement.addEventListener('click', () => {
if (!isLocked) renderer.domElement.requestPointerLock();
});
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
}
function getForward() {
return new THREE.Vector3(-Math.sin(yaw), 0, -Math.cos(yaw)).normalize();
}
function getRight() {
return new THREE.Vector3(Math.cos(yaw), 0, -Math.sin(yaw)).normalize();
}
function collidesWithBlock(px, py, pz) {
const minX = Math.floor(px - PLAYER_RADIUS);
const maxX = Math.floor(px + PLAYER_RADIUS);
const minY = Math.floor(py);
const maxY = Math.floor(py + PLAYER_HEIGHT);
const minZ = Math.floor(pz - PLAYER_RADIUS);
const maxZ = Math.floor(pz + PLAYER_RADIUS);
for (let x = minX; x <= maxX; x++) {
for (let y = minY; y <= maxY; y++) {
for (let z = minZ; z <= maxZ; z++) {
if (getBlock(x, y, z) !== 0) {
const bx = x, by = y, bz = z;
if (px + PLAYER_RADIUS > bx && px - PLAYER_RADIUS < bx + 1 &&
py + PLAYER_HEIGHT > by && py < by + 1 &&
pz + PLAYER_RADIUS > bz && pz - PLAYER_RADIUS < bz + 1) {
return true;
}
}
}
}
}
return false;
}
let lastTime = performance.now();
function update() {
const now = performance.now();
const dt = Math.min((now - lastTime) / 1000, 0.05);
lastTime = now;
if (!isLocked) return;
const forward = getForward();
const right = getRight();
const moveDir = new THREE.Vector3(0, 0, 0);
if (keys['KeyW']) moveDir.add(forward);
if (keys['KeyS']) moveDir.sub(forward);
if (keys['KeyD']) moveDir.add(right);
if (keys['KeyA']) moveDir.sub(right);
if (moveDir.length() > 0) moveDir.normalize();
velocity.x = moveDir.x * MOVE_SPEED;
velocity.z = moveDir.z * MOVE_SPEED;
velocity.y += GRAVITY * dt;
if (keys['Space'] && onGround) {
velocity.y = JUMP_FORCE;
onGround = false;
}
const pos = camera.position;
const newX = pos.x + velocity.x * dt;
if (!collidesWithBlock(newX, pos.y - PLAYER_HEIGHT, pos.z)) {
pos.x = newX;
} else {
velocity.x = 0;
}
const newZ = pos.z + velocity.z * dt;
if (!collidesWithBlock(pos.x, pos.y - PLAYER_HEIGHT, newZ)) {
pos.z = newZ;
} else {
velocity.z = 0;
}
const newY = pos.y + velocity.y * dt;
if (!collidesWithBlock(pos.x, newY - PLAYER_HEIGHT, pos.z)) {
pos.y = newY;
onGround = false;
} else {
if (velocity.y < 0) onGround = true;
velocity.y = 0;
}
if (pos.y < -20) {
const h = getTerrainHeight(Math.floor(pos.x), Math.floor(pos.z));
pos.y = h + 2 + PLAYER_HEIGHT;
velocity.set(0, 0, 0);
}
camera.rotation.order = 'YXZ';
camera.rotation.y = yaw;
camera.rotation.x = pitch;
updateHighlight();
updateChunks();
}
function getTargetBlock() {
raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
const meshArray = Array.from(blockMeshes.values());
const intersects = raycaster.intersectObjects(meshArray);
if (intersects.length > 0) {
return intersects[0];
}
return null;
}
function updateHighlight() {
const hit = getTargetBlock();
if (hit) {
const ud = hit.object.userData;
highlightMesh.position.set(ud.blockX + 0.5, ud.blockY + 0.5, ud.blockZ + 0.5);
highlightMesh.visible = true;
} else {
highlightMesh.visible = false;
}
}
function destroyBlock() {
const hit = getTargetBlock();
if (hit) {
const ud = hit.object.userData;
setBlock(ud.blockX, ud.blockY, ud.blockZ, 0);
}
}
function placeBlock() {
const hit = getTargetBlock();
if (hit) {
const normal = hit.face.normal;
const ud = hit.object.userData;
const nx = ud.blockX + Math.round(normal.x);
const ny = ud.blockY + Math.round(normal.y);
const nz = ud.blockZ + Math.round(normal.z);
if (ny >= 0 && ny < WORLD_HEIGHT) {
const px = camera.position.x;
const py = camera.position.y - PLAYER_HEIGHT;
const pz = camera.position.z;
if (!(px + PLAYER_RADIUS > nx && px - PLAYER_RADIUS < nx + 1 &&
py + PLAYER_HEIGHT > ny && py < ny + 1 &&
pz + PLAYER_RADIUS > nz && pz - PLAYER_RADIUS < nz + 1)) {
setBlock(nx, ny, nz, 1);
}
}
}
}
function animate() {
requestAnimationFrame(animate);
update();
renderer.render(scene, camera);
}
init();
animate();
</script>
</body>
</html>```
网友解答:
--【壹】--: sagiri:
gemini网页版
网页版的Gemini降智到一定程度了
这是我的提示词
image711×309 43 KB
这是vertex渠道的Gemini 3.1 pro high thinking effort的表现
JS-Craft
image1908×877 209 KB
deepseek网页版专家模式的代码写的还可以,可玩性几乎为0,把我的小破笔记本卡死了
⛏️ VoxelCraft — Minecraft Clone
image1899×886 375 KB
--【贰】--:
这个速度和效果,是可用状态了,起码不想M2.7胡说八道的
--【叁】--:
不知道目前官网上的是不是真v4,但是比官方api的v3.2强,v3.2写的代码完全不能用

