Meta Description" name="description" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Ultra Mobile Minecraft</title>
<style>
body { margin: 0; overflow: hidden; font-family: sans-serif; user-select: none; -webkit-user-select: none; background-color: #000; }
#crosshair {
position: absolute; top: 50%; left: 50%;
width: 10px; height: 10px;
transform: translate(-50%, -50%);
color: white; font-weight: bold; font-size: 20px;
pointer-events: none; z-index: 10;
}
/* Touch UI Layout */
#joystick-zone {
position: absolute; bottom: 30px; left: 30px;
width: 120px; height: 120px;
background: rgba(255,255,255,0.15); border: 2px solid rgba(255,255,255,0.3);
border-radius: 50%; display: flex; align-items: center; justify-content: center; z-index: 20;
}
#joystick-knob { width: 50px; height: 50px; background: white; border-radius: 50%; opacity: 0.8; }
.action-btn {
position: absolute; right: 40px; width: 65px; height: 65px;
background: rgba(255,255,255,0.2); border: 2px solid white; border-radius: 50%;
color: white; display: flex; align-items: center; justify-content: center;
font-weight: bold; z-index: 20; font-size: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
#jump-btn { bottom: 120px; }
#fly-btn { bottom: 40px; background: rgba(0, 150, 255, 0.4); }
#fly-btn.active { background: rgba(0, 255, 100, 0.7); box-shadow: 0 0 15px #00ff64; }
#hotbar {
position: absolute; top: 15px; left: 50%;
transform: translateX(-50%);
display: flex; background: rgba(0,0,0,0.7);
padding: 6px; border-radius: 8px; gap: 5px; z-index: 20;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
.slot {
width: 45px; height: 45px; border: 2px solid #444;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 8px; font-weight: bold; text-align: center;
border-radius: 6px;
}
.slot.active { border-color: #00ff64; background-color: rgba(255,255,255,0.2); }
</style>
</head>
<body>
<div id="crosshair">+</div>
<div id="joystick-zone"><div id="joystick-knob"></div></div>
<div id="jump-btn" class="action-btn">JUMP</div>
<div id="fly-btn" class="action-btn">FLY: OFF</div>
<div id="hotbar">
<div class="slot active" id="slot1" style="background-color: #4a7023;">Grass</div>
<div class="slot" id="slot2" style="background-color: #616161;">Stone</div>
<div class="slot" id="slot3" style="background-color: #1a5ec4; opacity: 0.8;">Water</div>
<div class="slot" id="slot4" style="background-color: #b53c0d;">Lava</div>
<div class="slot" id="slot5" style="background-color: #242528;">Nether</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// 1. Ultra Graphic Scene Setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xa3d5ff); // Realistic atmosphere sky
scene.fog = new THREE.FogExp2(0xa3d5ff, 0.025);
const camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: "high-performance" });
renderer.setSize(window.innerWidth, window.innerHeight);
// Ultra Shadows & Lighting setup
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;
document.body.appendChild(renderer.domElement);
// Advanced Cinematic Lights
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight(0xfffaed, 1.2); // Warm sun tint
sunLight.position.set(30, 60, 30);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 1024; // High-res shadows
sunLight.shadow.mapSize.height = 1024;
sunLight.shadow.camera.near = 0.5;
sunLight.shadow.camera.far = 150;
const d = 30;
sunLight.shadow.camera.left = -d; sunLight.shadow.camera.right = d;
sunLight.shadow.camera.top = d; sunLight.shadow.camera.bottom = -d;
sunLight.shadow.bias = -0.0005;
scene.add(sunLight);
// 2. High-Fidelity Materials Grid Setup
const geometry = new THREE.BoxGeometry(1, 1, 1);
const createMat = (color, roughness, metalness) =>
new THREE.MeshStandardMaterial({ color: color, roughness: roughness, metalness: metalness });
const materials = {
1: createMat(0x5c8a32, 0.9, 0.0), // Grass
2: createMat(0x737373, 0.8, 0.1), // Stone
3: new THREE.MeshStandardMaterial({ color: 0x0066cc, roughness: 0.1, metalness: 0.1, transparent: true, opacity: 0.6 }), // Crystal Transparent Water
4: new THREE.MeshStandardMaterial({ color: 0xcc3300, emissive: 0x4a0a00, roughness: 0.4 }), // Glowing Lava
5: createMat(0x212224, 0.4, 0.7) // Polished Netherite
};
const blocks = [];
const worldSize = 24;
const seaLevel = 3;
let spawnY = 6;
// 3. Terrain Generation Engine
function generateHeight(x, z) {
let height = Math.sin(x * 0.15) * 2.5 + Math.cos(z * 0.15) * 2.5;
height += Math.sin(x * 0.04) * Math.cos(z * 0.04) * 6; // Beautiful rolling peaks
return Math.floor(height) + 4;
}
// Generate Chunk Terrain + Water Levels
for (let x = 0; x < worldSize; x++) {
for (let z = 0; z < worldSize; z++) {
const terrainY = generateHeight(x, z);
if (x === Math.floor(worldSize/2) && z === Math.floor(worldSize/2)) {
spawnY = Math.max(terrainY, seaLevel) + 2;
}
// Fill Solid Ground
for (let y = 0; y <= terrainY; y++) {
const mat = (y === terrainY) ? materials[1] : materials[2];
const block = new THREE.Mesh(geometry, mat);
block.position.set(x, y, z);
block.castShadow = true;
block.receiveShadow = true;
scene.add(block);
blocks.push(block);
}
// Procedural Water: Fill empty spaces up to sea level if land is low
if (terrainY < seaLevel) {
for (let y = terrainY + 1; y <= seaLevel; y++) {
const waterBlock = new THREE.Mesh(geometry, materials[3]);
waterBlock.position.set(x, y, z);
scene.add(waterBlock);
blocks.push(waterBlock); // Allows player to stand or interact with it
}
}
}
}
// 4. Hotbar Selector Setup
let activeSlot = 1;
document.querySelectorAll('.slot').forEach((slot, index) => {
slot.addEventListener('touchstart', (e) => {
e.stopPropagation();
document.getElementById(`slot${activeSlot}`).classList.remove('active');
activeSlot = index + 1;
slot.classList.add('active');
});
});
// 5. Look Mechanics & Camera Setup
let lon = 0, lat = 0, phi = 0, theta = 0;
let touchStartLookX = 0, touchStartLookY = 0, touchStartTime = 0;
const target = new THREE.Vector3();
camera.position.set(worldSize / 2, spawnY, worldSize / 2);
// 6. Flight & Physics States
let isFlying = false;
let moveX = 0, moveZ = 0;
let playerVelocity = new THREE.Vector3();
let canJump = false;
// Toggle Flight UI Binding
const flyBtn = document.getElementById('fly-btn');
flyBtn.addEventListener('touchstart', (e) => {
e.preventDefault(); e.stopPropagation();
isFlying = !isFlying;
if (isFlying) {
flyBtn.classList.add('active');
flyBtn.innerText = "FLY: ON";
playerVelocity.set(0,0,0); // Stop mid-air instantly
} else {
flyBtn.classList.remove('active');
flyBtn.innerText = "FLY: OFF";
}
});
// 7. Touch Gesture Raycasting Parser
const raycaster = new THREE.Raycaster();
const centerMouse = new THREE.Vector2(0, 0);
window.addEventListener('touchstart', (e) => {
const touch = e.touches[0];
if (e.target.closest('#joystick-zone') || e.target.closest('.action-btn') || e.target.closest('#hotbar')) return;
touchStartLookX = touch.clientX; touchStartLookY = touch.clientY;
touchStartTime = Date.now();
});
window.addEventListener('touchmove', (e) => {
const touch = e.touches[0];
if (e.target.closest('#joystick-zone') || e.target.closest('.action-btn') || e.target.closest('#hotbar')) return;
lon += (touch.clientX - touchStartLookX) * 0.25;
lat -= (touch.clientY - touchStartLookY) * 0.25;
lat = Math.max(-85, Math.min(85, lat));
touchStartLookX = touch.clientX; touchStartLookY = touch.clientY;
});
window.addEventListener('touchend', (e) => {
if (e.target.closest('#joystick-zone') || e.target.closest('.action-btn') || e.target.closest('#hotbar')) return;
if (Date.now() - touchStartTime > 220) {
// Long Hold: PLACE
raycaster.setFromCamera(centerMouse, camera);
const intersects = raycaster.intersectObjects(blocks);
if (intersects.length > 0 && intersects[0].distance < 7) {
const intersect = intersects[0];
const spawnPos = intersect.object.position.clone().add(intersect.face.normal);
const newBlock = new THREE.Mesh(geometry, materials[activeSlot]);
newBlock.position.copy(spawnPos);
newBlock.castShadow = true; newBlock.receiveShadow = true;
scene.add(newBlock); blocks.push(newBlock);
}
} else {
// Quick Tap: DESTROY
raycaster.setFromCamera(centerMouse, camera);
const intersects = raycaster.intersectObjects(blocks);
if (intersects.length > 0 && intersects[0].distance < 7) {
const intersect = intersects[0];
scene.remove(intersect.object);
blocks.splice(blocks.indexOf(intersect.object), 1);
}
}
});
// Joystick Event Binding
const joystickZone = document.getElementById('joystick-zone');
const joystickKnob = document.getElementById('joystick-knob');
let joystickActive = false;
joystickZone.addEventListener('touchstart', () => { joystickActive = true; });
joystickZone.addEventListener('touchmove', (e) => {
if (!joystickActive) return;
const touch = e.touches[0];
const rect = joystickZone.getBoundingClientRect();
let dx = touch.clientX - (rect.left + rect.width / 2);
let dy = touch.clientY - (rect.top + rect.height / 2);
const dist = Math.sqrt(dx*dx + dy*dy);
if (dist > 50) { dx = (dx / dist) * 50; dy = (dy / dist) * 50; }
joystickKnob.style.transform = `translate(${dx}px, ${dy}px)`;
moveX = dx / 50; moveZ = dy / 50;
});
joystickZone.addEventListener('touchend', () => {
joystickActive = false; joystickKnob.style.transform = `translate(0px, 0px)`;
moveX = 0; moveZ = 0;
});
// Jump button event mapping
document.getElementById('jump-btn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (isFlying) {
camera.position.y += 1.0; // Fly Upwards
} else if (canJump) {
playerVelocity.y += 6.5; canJump = false;
}
});
// 8. Game Dynamics Loop Execution
const clock = new THREE.Clock();
const gravity = 16;
function animate() {
requestAnimationFrame(animate);
const delta = Math.min(clock.getDelta(), 0.1);
// Turn Camera Matrix
phi = THREE.MathUtils.degToRad(90 - lat);
theta = THREE.MathUtils.degToRad(lon);
target.setFromSphericalCoords(1, phi, theta).add(camera.position);
camera.lookAt(target);
// Calculated Vector Angles
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
if (!isFlying) forward.y = 0; // lock lateral movement on ground
forward.normalize();
const right = new THREE.Vector3(1, 0, 0).applyQuaternion(camera.quaternion);
right.y = 0; right.normalize();
// Apply Lateral Joystick Inputs
camera.position.addScaledVector(forward, -moveZ * (isFlying ? 10 : 5) * delta);
camera.position.addScaledVector(right, moveX * (isFlying ? 10 : 5) * delta);
const px = Math.floor(camera.position.x);
const pz = Math.floor(camera.position.z);
let groundHeight = 0;
if (px >= 0 && px < worldSize && pz >= 0 && pz < worldSize) {
groundHeight = Math.max(generateHeight(px, pz), (seaLevel)); // factor in water bed surface
}
if (isFlying) {
// Fly Downwards if pulling back on Joystick while looking low, or keep hovering safely
if (camera.position.y < groundHeight + 1.8) camera.position.y = groundHeight + 1.8;
} else {
// Standard Gravity Physics
playerVelocity.y -= gravity * delta;
camera.position.y += playerVelocity.y * delta;
if (camera.position.y < groundHeight + 1.8) {
playerVelocity.y = 0;
camera.position.y = groundHeight + 1.8;
canJump = true;
}
}
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
2
2
134KB
605KB
6,404.0ms
224.0ms
6,404.0ms