Worms_game / index.html
Andro0s's picture
Update index.html
93b8415 verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Worms 3D</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #222;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
/* CONTENEDOR GENERAL */
#game-container {
width: 90vw;
height: 70vh;
background: #000;
border: 3px solid #00ff88;
margin-top: 10px;
position: relative;
}
/* BOTONES */
#ui-bar {
margin-top: 12px;
display: flex;
gap: 12px;
}
button {
padding: 14px 26px;
font-size: 18px;
font-weight: bold;
border-radius: 8px;
border: none;
background: #00ff99;
color: #000;
cursor: pointer;
}
button:hover {
background: #00d97e;
}
</style>
<!-- THREE.JS + LIBRERÍAS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/examples/js/loaders/OBJLoader.js"></script>
</head>
<body>
<!-- BOTONES VISIBLES -->
<div id="ui-bar">
<button onclick="cameraFollow = true">Seguir Gusano</button>
<button onclick="cameraFollow = false">Control Libre</button>
</div>
<!-- CONTENEDOR DEL JUEGO (AGRANDADO) -->
<div id="game-container"></div>
<script>
// =======================================================
// === Three.js 3D Initialization ===
// =======================================================
let scene, camera, renderer, terrain, controls;
let wormMesh;
const keys = {};
let cameraFollow = true; // Activar o desactivar seguimiento automático
const container = document.getElementById("game-container");
const textureLoader = new THREE.TextureLoader();
const movementSpeed = 0.5;
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87ceeb);
camera = new THREE.PerspectiveCamera(
75,
container.clientWidth / container.clientHeight,
0.1,
1000
);
camera.position.set(0, 50, 70);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(container.clientWidth, container.clientHeight);
container.appendChild(renderer.domElement);
const ambientLight = new THREE.AmbientLight(0x404040, 3);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
directionalLight.position.set(100, 100, 50);
scene.add(directionalLight);
createTerrain();
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 20;
controls.maxDistance = 150;
loadWormModel();
window.addEventListener("keydown", (e) => keys[e.key.toLowerCase()] = true);
window.addEventListener("keyup", (e) => keys[e.key.toLowerCase()] = false);
window.addEventListener("resize", onWindowResize);
}
// =======================================================
// === Terreno Procedural ===
// =======================================================
function createTerrain() {
const texture = textureLoader.load("grass_texture.jpg");
const size = 150, segments = 64;
const geometry = new THREE.PlaneGeometry(size, size, segments, segments);
geometry.rotateX(-Math.PI / 2);
const material = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide
});
terrain = new THREE.Mesh(geometry, material);
const verts = geometry.attributes.position.array;
const maxH = 15;
for (let i = 0; i < verts.length; i += 3) {
const x = verts[i] / size;
const y = verts[i + 2] / size;
const height =
Math.sin(x * 10) * 0.5 +
Math.cos(y * 7) * 0.8 +
Math.sin((x + y) * 5) * 0.3;
verts[i + 1] = height * maxH;
}
geometry.computeVertexNormals();
scene.add(terrain);
}
// =======================================================
// === Modelo OBJ del gusano ===
// =======================================================
function loadWormModel() {
const objLoader = new THREE.OBJLoader();
objLoader.load("cascabel123.obj", (object) => {
const material = new THREE.MeshPhongMaterial({
color: 0x68e079,
shininess: 30
});
object.traverse((child) => {
if (child.isMesh) child.material = material;
});
wormMesh = object;
wormMesh.scale.set(10, 10, 10);
wormMesh.position.set(0, 5, 0);
scene.add(wormMesh);
});
}
// =======================================================
// === Movimiento ===
// =======================================================
function moveWorm() {
if (!wormMesh) return;
let moved = false;
const prev = wormMesh.position.clone();
if (keys["w"]) { wormMesh.position.z -= movementSpeed; wormMesh.rotation.y = 0; moved = true; }
if (keys["s"]) { wormMesh.position.z += movementSpeed; wormMesh.rotation.y = Math.PI; moved = true; }
if (keys["a"]) { wormMesh.position.x -= movementSpeed; wormMesh.rotation.y = Math.PI/2; moved = true; }
if (keys["d"]) { wormMesh.position.x += movementSpeed; wormMesh.rotation.y = -Math.PI/2; moved = true; }
if (cameraFollow && moved) {
const delta = wormMesh.position.clone().sub(prev);
camera.position.add(delta);
}
}
// =======================================================
// === Render Loop ===
// =======================================================
function animate() {
requestAnimationFrame(animate);
moveWorm();
if (controls) {
if (cameraFollow && wormMesh) {
controls.target.copy(wormMesh.position);
}
controls.update();
}
renderer.render(scene, camera);
}
// =======================================================
// === Resize ===
// =======================================================
function onWindowResize() {
camera.aspect = container.clientWidth / container.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
}
init();
animate();
</script>
</body>
</html>