0% found this document useful (0 votes)
18 views6 pages

Fps Trainer - HTML

The document is an HTML file for a Mini FPS Target Trainer, featuring a user interface for selecting guns, adjusting sensitivity, recoil intensity, and target speed. It utilizes Three.js for rendering a 3D scene where users can shoot at moving targets, with functionalities for spawning targets, resetting the game, and tracking performance metrics like FPS and hit counts. The script includes event listeners for user interactions such as shooting, changing guns, and adjusting settings, along with a basic animation loop for rendering the scene and moving targets.

Uploaded by

xzxycx123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views6 pages

Fps Trainer - HTML

The document is an HTML file for a Mini FPS Target Trainer, featuring a user interface for selecting guns, adjusting sensitivity, recoil intensity, and target speed. It utilizes Three.js for rendering a 3D scene where users can shoot at moving targets, with functionalities for spawning targets, resetting the game, and tracking performance metrics like FPS and hit counts. The script includes event listeners for user interactions such as shooting, changing guns, and adjusting settings, along with a basic animation loop for rendering the scene and moving targets.

Uploaded by

xzxycx123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

<!

doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Mini FPS Target Trainer</title>
<style>
html,body{height:100%;margin:0;overflow:hidden;font-family:Inter,system-
ui,Segoe UI,Roboto,'Helvetica Neue',Arial}
#ui{position:fixed;left:12px;top:12px;z-
index:20;background:rgba(0,0,0,0.5);color:#fff;padding:12px;border-
radius:8px;backdrop-filter:blur(4px)}
#ui label{display:block;font-size:13px;margin-top:6px}
#crosshair{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-
index:15;pointer-events:none;font-size:22px;color:#fff}
#debug{position:fixed;right:12px;top:12px;z-
index:20;background:rgba(0,0,0,0.5);color:#0f0;padding:8px;border-radius:6px;font-
family:monospace}
button,select,input{margin-top:6px}
canvas{display:block}
</style>
</head>
<body>
<div id="ui">
<div>
<label>Gun
<select id="gunSelect">
<option value="pistol">Pistol (semi)</option>
<option value="smg">SMG (auto)</option>
<option value="rifle">Rifle (burst)</option>
</select>
</label>
<label>Sensitivity <input id="sens" type="range" min="0.2" max="3"
step="0.05" value="1"> <span id="sensVal">1.00</span></label>
<label>Recoil Intensity <input id="recoil" type="range" min="0" max="2"
step="0.05" value="1"> <span id="recoilVal">1.00</span></label>
<label>Target Speed <input id="tgtSpeed" type="range" min="0.2" max="3"
step="0.1" value="1"> <span id="tgtSpeedVal">1.00</span></label>
<div>
<button id="spawn">Spawn Targets</button>
<button id="reset">Reset</button>
</div>
<div style="margin-top:8px;font-size:13px;opacity:0.9">Click to lock pointer.
Left click to shoot. R to reload. Mouse wheel to change guns.</div>
</div>
</div>
<div id="crosshair">+</div>
<div id="debug">FPS: <span id="fps">0</span><br>Bullets: <span
id="bullets">0</span><br>Hits: <span id="hits">0</span><br>Spread: <span
id="spread">0</span></div>

<script src="https://cdn.jsdelivr.net/npm/three@0.154.0/build/three.min.js"></
script>
<script src="https://cdn.jsdelivr.net/npm/three@0.154.0/examples/js/controls/
PointerLockControls.js"></script>

<script>
// Basic scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1,
1000);
camera.position.set(0,1.6,0);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth,innerHeight);
document.body.appendChild(renderer.domElement);

// light
const amb = new THREE.HemisphereLight(0xffffff,0x444444,0.8);
scene.add(amb);
const dir = new THREE.DirectionalLight(0xffffff,0.7);
dir.position.set(5,10,7);
scene.add(dir);

// floor
const floorGeo = new THREE.PlaneGeometry(200,200);
const floorMat = new THREE.MeshStandardMaterial({color:0x222222});
const floor = new THREE.Mesh(floorGeo,floorMat);
floor.rotation.x = -Math.PI/2;
scene.add(floor);

// simple crosshair raycaster


const raycaster = new THREE.Raycaster();

// UI
const sens = document.getElementById('sens'); const sensVal =
document.getElementById('sensVal');
const recoilSlider = document.getElementById('recoil'); const recoilVal =
document.getElementById('recoilVal');
const gunSelect = document.getElementById('gunSelect');
const tgtSpeed = document.getElementById('tgtSpeed'); const tgtSpeedVal =
document.getElementById('tgtSpeedVal');
const fpsEl = document.getElementById('fps'), bulletsEl =
document.getElementById('bullets'), hitsEl = document.getElementById('hits'),
spreadEl = document.getElementById('spread');
sensVal.innerText = parseFloat(sens.value).toFixed(2);
recoilVal.innerText = parseFloat(recoilSlider.value).toFixed(2);
tgtSpeedVal.innerText = parseFloat(tgtSpeed.value).toFixed(2);

sens.addEventListener('input',()=>sensVal.innerText =
parseFloat(sens.value).toFixed(2));
recoilSlider.addEventListener('input',()=>recoilVal.innerText =
parseFloat(recoilSlider.value).toFixed(2));
tgtSpeed.addEventListener('input',()=>tgtSpeedVal.innerText =
parseFloat(tgtSpeed.value).toFixed(2));

// stats (simple)
let lastTime = performance.now(), frames = 0, fps = 0;

// pointer lock
const controls = new THREE.PointerLockControls(camera, document.body);
document.body.addEventListener('click', ()=>{ if(!controls.isLocked)
controls.lock(); });

controls.addEventListener('lock',
()=>{ document.getElementById('ui').style.display='block'; });
controls.addEventListener('unlock',
()=>{ document.getElementById('ui').style.display='block'; });
// guns config
const GUNS = {
pistol: {fireMode:'semi',rpm:300,mag:12, reload:1.2, recoil:0.8, spread:0.8},
smg: {fireMode:'auto',rpm:900,mag:40, reload:2.2, recoil:1.2, spread:1.4},
rifle: {fireMode:'burst',rpm:700,mag:30, reload:2.5, recoil:1.6, spread:1.0}
};

let currentGun = GUNS[gunSelect.value];


gunSelect.addEventListener('change', ()=>{ currentGun =
GUNS[gunSelect.value]; });

// ammo
let bullets = currentGun.mag, bulletsFired = 0, hits=0;

// shooting control
let firing=false; let lastShotTime=0; let canFire=true; let spread=0;

function getTime(){return performance.now()/1000}

function shoot(){
const now = getTime();
const delay = 60/currentGun.rpm;
if(!canFire) return;
if(now - lastShotTime < delay) return;
if(bullets<=0) { /* click */ return; }
lastShotTime = now;
bullets--; bulletsFired++;
bulletsEl.innerText = bulletsFired;

// recoil: apply camera pitch and yaw slight offset


const recoilAmount = currentGun.recoil * parseFloat(recoilSlider.value);
camera.rotation.x -= THREE.MathUtils.degToRad( (0.5 + Math.random()*0.6) *
recoilAmount );
camera.rotation.y += THREE.MathUtils.degToRad( (Math.random()-0.5) *
recoilAmount * 0.6 );

// spread increases
spread += currentGun.spread * 0.02 * parseFloat(recoilSlider.value);
spread = Math.min(spread, 0.6);

// raycast with spread


const center = new THREE.Vector3();
camera.getWorldDirection(center);

// apply random spread


const spreadAngle = spread;
const randX = (Math.random()-0.5)*spreadAngle;
const randY = (Math.random()-0.5)*spreadAngle;
const dir = center.clone().applyAxisAngle(new THREE.Vector3(0,1,0),
randY).applyAxisAngle(new THREE.Vector3(1,0,0), randX);

raycaster.set(camera.position, dir);
const hitsArr = raycaster.intersectObjects(targets.map(t=>t.mesh));
if(hitsArr.length>0){
const hit = hitsArr[0];
// find target
const t = targets.find(x=>x.mesh===hit.object);
if(t && !t.hit){
t.hit=true; t.mesh.material.color.set(0x00ff00);
hits++; hitsEl.innerText = hits;
}
}
}

// handle continuous fire


function handleAutoFire(){
if(currentGun.fireMode==='auto' && firing){ shoot(); }
}

// map mouse movement to camera rotation with sensitivity


let yaw=0, pitch=0;
document.addEventListener('mousemove', (e)=>{
if(!controls.isLocked) return;
const s = parseFloat(sens.value);
const movementX = e.movementX || 0;
const movementY = e.movementY || 0;
camera.rotation.y -= movementX * 0.002 * s;
camera.rotation.x -= movementY * 0.002 * s;
camera.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2,
camera.rotation.x));
});

// keyboard
document.addEventListener('keydown', (e)=>{
if(e.code==='KeyR'){ bullets = currentGun.mag; }
if(e.code==='Space'){ /* could be jump */ }
if(e.code==='KeyV'){ /* toggle */ }
});

// mouse buttons
document.addEventListener('pointerdown', (e)=>{
if(e.button===0){ // left
firing=true;
if(currentGun.fireMode==='semi' || currentGun.fireMode==='burst') shoot();
}
});
document.addEventListener('pointerup', (e)=>{ if(e.button===0)
firing=false; });

// change gun with wheel


document.addEventListener('wheel', (e)=>{
const idx =
Array.from(gunSelect.options).findIndex(o=>o.value===gunSelect.value);
if(e.deltaY>0) gunSelect.selectedIndex = Math.min(gunSelect.options.length-1,
idx+1);
else gunSelect.selectedIndex = Math.max(0, idx-1);
gunSelect.dispatchEvent(new Event('change'));
}, {passive:true});

// simple recoil recovery and spread decay


function recoilRecovery(dt){
// recover camera pitch gradually
camera.rotation.x += dt * 1.5; // recovery speed
if(camera.rotation.x > 1.6) camera.rotation.x = 1.6;
spread = Math.max(0, spread - dt*0.6);
}

// targets system
const targets = [];
function createTarget(x,y,z){
const geo = new THREE.SphereGeometry(0.25,16,12);
const mat = new THREE.MeshStandardMaterial({color:0xff4444, metalness:0.2,
roughness:0.6});
const mesh = new THREE.Mesh(geo, mat);
mesh.position.set(x,y,z);
scene.add(mesh);
targets.push({mesh, baseX:x, baseY:y, baseZ:z, t:Math.random()*10,
hit:false});
}

function spawnTargets(n=6){
// clear existing
targets.forEach(t=>scene.remove(t.mesh)); targets.length=0;
for(let i=0;i<n;i++){
const x = (Math.random()-0.5)*20 + 0; const y = 1 + Math.random()*2; const
z = -10 - Math.random()*20;
createTarget(x,y,z);
}
bullets = currentGun.mag; bulletsFired = 0; hits = 0; bulletsEl.innerText =
bulletsFired; hitsEl.innerText = hits;
}

document.getElementById('spawn').addEventListener('click',
()=>spawnTargets(8));
document.getElementById('reset').addEventListener('click',
()=>{ spawnTargets(6); camera.rotation.set(0,0,0); spread=0; });

spawnTargets(6);

// animation loop
let prev = performance.now()/1000;
function animate(){
requestAnimationFrame(animate);
const nowMs = performance.now(); frames++; const dtMs = nowMs - lastTime;
if(nowMs - lastTime >= 250){ fps = Math.round((frames*1000)/(nowMs -
lastTime)); lastTime = nowMs; frames=0; fpsEl.innerText = fps; }

const now = performance.now()/1000; const dt = Math.min(now - prev, 0.05);


prev = now;

// move targets
const ts = parseFloat(tgtSpeed.value);
targets.forEach((t,i)=>{
t.t += dt * ts;
t.mesh.position.x = t.baseX + Math.sin(t.t*1.2 + i) * (1.5 +
Math.sin(i))*1.5;
t.mesh.position.y = t.baseY + Math.sin(t.t*1.7 + i) * 0.6;
});

// firing for auto


handleAutoFire();

// recoil recovery
recoilRecovery(dt);

// update spread display


spreadEl.innerText = spread.toFixed(3);
renderer.render(scene,camera);
}
animate();

// resize
window.addEventListener('resize', ()=>{ camera.aspect = innerWidth/innerHeight;
camera.updateProjectionMatrix(); renderer.setSize(innerWidth,innerHeight); });

// simple click-to-spawn targets on hit (for practice)


// (no additional code needed for now)

// extra: simple audio feedback (optional)


// omitted to keep single-file small

// keep UI visible
document.getElementById('ui').style.display='block';

</script>
</body>
</html>

You might also like