Meta Description" name="description" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>3D War Realistic</title>
<style>
body { margin:0; overflow:hidden; background:black; touch-action:none; }
canvas { display:block; }
/* Botones */
#attackBtn, #axeBtn{
position:absolute;
width:75px;
height:75px;
border-radius:50%;
text-align:center;
line-height:75px;
font-size:22px;
color:white;
opacity:0.9;
}
#attackBtn{
right:25px;
bottom:60px;
background:#8b0000;
}
#axeBtn{
right:120px;
bottom:130px;
background:#555;
}
/* Joystick visual */
#joystickBase{
position:absolute;
left:40px;
bottom:80px;
width:120px;
height:120px;
border-radius:50%;
background:rgba(255,255,255,0.1);
}
#joystickStick{
position:absolute;
left:80px;
bottom:120px;
width:60px;
height:60px;
border-radius:50%;
background:rgba(255,255,255,0.3);
}
</style>
</head>
<body>
<div id="attackBtn">⚔</div>
<div id="axeBtn">🪓</div>
<div id="joystickBase"></div>
<div id="joystickStick"></div>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<script>
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x101015);
scene.fog = new THREE.Fog(0x000000, 10, 40);
const camera = new THREE.PerspectiveCamera(70, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Luces
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.8);
scene.add(hemiLight);
const dirLight = new THREE.DirectionalLight(0xffffff,1);
dirLight.position.set(5,10,7);
dirLight.castShadow = true;
scene.add(dirLight);
// Suelo
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(100,100),
new THREE.MeshStandardMaterial({color:0x222222})
);
floor.rotation.x = -Math.PI/2;
floor.receiveShadow = true;
scene.add(floor);
// ===== JUGADOR MÁS REALISTA =====
const player = new THREE.Group();
function createLimb(w,h,d,color,y){
const limb = new THREE.Mesh(
new THREE.BoxGeometry(w,h,d),
new THREE.MeshStandardMaterial({color})
);
limb.position.y = y;
limb.castShadow = true;
return limb;
}
// Cuerpo
player.add(createLimb(1,2,0.6,0xaa0000,1.5));
// Cabeza
player.add(createLimb(0.8,0.8,0.8,0xffcc99,3));
// Piernas
player.add(createLimb(0.4,1.5,0.4,0x550000,0.75));
player.add(createLimb(0.4,1.5,0.4,0x550000,0.75)).position.x=0.6;
// Brazos
player.add(createLimb(0.4,1.5,0.4,0xaa0000,2)).position.x=-0.9;
player.add(createLimb(0.4,1.5,0.4,0xaa0000,2)).position.x=0.9;
scene.add(player);
// ===== HACHA =====
const axe = new THREE.Mesh(
new THREE.CylinderGeometry(0.1,0.1,2,8),
new THREE.MeshStandardMaterial({color:0x8b4513})
);
axe.rotation.z=Math.PI/2;
axe.visible=false;
scene.add(axe);
let axeState="idle";
let axeDir=new THREE.Vector3();
// ===== ENEMIGOS =====
let enemies=[];
function spawnEnemy(){
const enemy = createLimb(1,2,0.6,0x006600,1);
enemy.position.set((Math.random()-0.5)*20,1,(Math.random()-0.5)*20);
scene.add(enemy);
enemies.push(enemy);
}
setInterval(spawnEnemy,3000);
// ===== JOYSTICK =====
let joystick={dx:0,dy:0};
const stick=document.getElementById("joystickStick");
renderer.domElement.addEventListener("touchmove", e=>{
const t=e.touches[0];
if(t.clientX<200){
let dx=t.clientX-100;
let dy=t.clientY-(window.innerHeight-140);
let mag=Math.sqrt(dx*dx+dy*dy);
if(mag>40){ dx/=mag; dy/=mag; }
joystick.dx=dx/40;
joystick.dy=dy/40;
stick.style.left=(80+dx)+"px";
stick.style.bottom=(120-dy)+"px";
}
});
renderer.domElement.addEventListener("touchend", ()=>{
joystick.dx=0; joystick.dy=0;
stick.style.left="80px";
stick.style.bottom="120px";
});
// Ataque
document.getElementById("attackBtn").addEventListener("touchstart", ()=>{
enemies.forEach((e,i)=>{
if(player.position.distanceTo(e.position)<3){
scene.remove(e);
enemies.splice(i,1);
}
});
});
// Lanzar hacha
document.getElementById("axeBtn").addEventListener("touchstart", ()=>{
if(axeState==="idle"){
axe.visible=true;
axe.position.copy(player.position);
axeDir.set(joystick.dx,0,joystick.dy).normalize();
if(axeDir.length()===0) axeDir.set(0,0,-1);
axeState="forward";
}
});
// Cámara
camera.position.set(0,6,10);
// Loop
function animate(){
requestAnimationFrame(animate);
player.position.x+=joystick.dx*0.2;
player.position.z+=joystick.dy*0.2;
enemies.forEach(e=>{
e.position.lerp(player.position,0.005);
});
if(axeState==="forward"){
axe.position.addScaledVector(axeDir,0.6);
if(axe.position.distanceTo(player.position)>8) axeState="return";
} else if(axeState==="return"){
let dir=new THREE.Vector3().subVectors(player.position,axe.position).normalize();
axe.position.addScaledVector(dir,0.7);
if(axe.position.distanceTo(player.position)<1){
axeState="idle";
axe.visible=false;
}
}
enemies.forEach((e,i)=>{
if(axe.visible && axe.position.distanceTo(e.position)<1.5){
scene.remove(e);
enemies.splice(i,1);
}
});
camera.position.x=player.position.x;
camera.position.z=player.position.z+10;
camera.lookAt(player.position);
renderer.render(scene,camera);
}
animate();
</script>
</body>
</html>2
2
160KB
624KB
1,900.0ms
120.0ms
1,900.0ms