Score: 0 | Speed Lv: 1 | Jump Lv: 1
Game Over
Press R to Restart
';
document.body.appendChild(adDiv);
/* ========================= MAIN LOOP ========================= */
let spawnTimer=0, upgradeTimer=0;
function animate(){
requestAnimationFrame(animate);
if(!gameOver){
speed+=0.00015;
score+=speed*2;
player.position.x=lanes[currentLane];
if(isJumping){jumpVelocity+=gravity; player.position.y+=jumpVelocity; if(player.position.y<=1){player.position.y=1; isJumping=false;}}
obstacles.forEach(o=>{o.position.z+=speed*2.2; if(hit(player,o)) endGame();});
upgrades.forEach(u=>{u.position.z+=speed*2.2; u.rotation.y+=0.05;
if(hit(player,u,1.3,1.5,1)){
if(u.userData.type==="speed"){speedLevel++; speed+=0.04;}
else{jumpLevel++; jumpStrength+=0.08;}
scene.remove(u); upgrades.splice(upgrades.indexOf(u),1);
}
});
obstacles=obstacles.filter(o=>o.position.z<=10);
upgrades=upgrades.filter(u=>u.position.z<=10);
spawnTimer+=speed; upgradeTimer+=speed;
if(spawnTimer>5){spawnObstacle(); spawnTimer=0;}
if(upgradeTimer>18){spawnUpgrade(); upgradeTimer=0;}
camera.position.z=player.position.z+7;
camera.position.x=player.position.x*0.3;
camera.lookAt(player.position.x,1.4,player.position.z-5);
document.getElementById("hud").textContent="Score: "+Math.floor(score)+" | Speed Lv: "+speedLevel+" | Jump Lv: "+jumpLevel;
}
// Position ad above player in screen space
const vector = player.position.clone();
vector.project(camera);
const x = (vector.x*0.5+0.5)*window.innerWidth;
const y = (-vector.y*0.5+0.5)*window.innerHeight - 50;
adDiv.style.left = x + "px";
adDiv.style.top = y + "px";
renderer.render(scene,camera);
}
animate();
/* ========================= RESIZE ========================= */
window.addEventListener("resize",()=>{
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
});