APK FET
đ Realistic Driving Mechanics
Experience a physics-based movement system where every input matters. The vehicle features:
Weight & Momentum: Feel the car's mass as you accelerate and decelerate.
Realistic Steering: The front-wheel-drive logic requires you to manage your turning radius carefully, especially when reversing into tight spots.
Visual Cues: Functional brake lights and headlights help you navigate the urban lot.
đĸ Urban Environment
Asphalt & Concrete: Navigate a parking lot designed with realistic textures, road markings, and solid curbs.
Collision System: A high-precision hit-box system ensures that even a small "paint-rub" against a concrete barrier results in a mission failure.
Target Zones: Standardized yellow safety-marked parking bays that require you to be perfectly centered to pass.
đšī¸ How to Play:
Ignition: Click "START ENGINE" to begin your shift.
Drive: Use WASD or Arrow Keys (Desktop) or the On-Screen D-Pad (Mobile).
The Goal: Maneuver your vehicle entirely inside the yellow lines.
Finalize: You must come to a complete stop (zero speed) inside the box to trigger a successful park.
Caution: Hitting any wall or gray concrete curb will cause a crash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Pro Parking Simulator</title>
<style>
:root {
--ui-accent: #2ecc71;
--ui-danger: #e74c3c;
--asphalt: #2c3e50;
--concrete: #95a5a6;
}
* {
box-sizing: border-box;
user-select: none;
touch-action: none;
}
body {
margin: 0;
padding: 0;
background-color: #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
overflow: hidden;
font-family: 'Segoe UI', Arial, sans-serif;
}
#game-container {
position: relative;
width: 100%;
max-width: 900px;
height: 100%;
max-height: 650px;
background: var(--asphalt);
border: 8px solid #333;
border-radius: 4px;
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
overflow: hidden;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
.hud {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 5;
}
.stat-box {
background: rgba(255, 255, 255, 0.9);
padding: 8px 15px;
border-radius: 4px;
border-bottom: 3px solid #ccc;
color: #333;
font-weight: 800;
font-size: 0.9rem;
text-transform: uppercase;
}
.overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
text-align: center;
color: white;
}
h1 {
font-size: 3rem;
margin: 0;
text-transform: uppercase;
font-style: italic;
border-bottom: 4px solid var(--ui-accent);
}
.btn-action {
margin-top: 25px;
padding: 15px 50px;
background: var(--ui-accent);
border: none;
color: white;
font-size: 1.2rem;
cursor: pointer;
border-radius: 4px;
transition: 0.2s;
font-weight: bold;
box-shadow: 0 4px 0 #27ae60;
}
.btn-action:hover {
transform: translateY(-2px);
box-shadow: 0 6px 0 #27ae60;
}
.btn-action:active {
transform: translateY(2px);
box-shadow: 0 0px 0 #27ae60;
}
.hidden { display: none !important; }
#mobile-controls {
position: absolute;
bottom: 20px;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 5;
}
.ctrl-btn {
width: 65px;
height: 65px;
background: rgba(255, 255, 255, 0.2);
border: 2px solid white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5rem;
backdrop-filter: blur(5px);
}
</style>
</head>
<body>
<div id="game-container">
<div class="hud">
<div class="stat-box">LEVEL <span id="level-val">1</span></div>
<div class="stat-box">TIME: <span id="time-val">0.0</span>s</div>
</div>
<div id="start-screen" class="overlay">
<h1>PARKING SIM</h1>
<p style="margin-top: 15px;">Precision Driving Challenge</p>
<button class="btn-action" id="start-btn">START ENGINE</button>
</div>
<div id="win-screen" class="overlay hidden">
<h1 style="color: var(--ui-accent); border-color: var(--ui-accent);">PARKED!</h1>
<p id="level-result" style="font-size: 1.2rem; margin-top: 10px;"></p>
<button class="btn-action" id="next-btn">NEXT LEVEL</button>
</div>
<div id="crash-screen" class="overlay hidden">
<h1 style="color: var(--ui-danger); border-color: var(--ui-danger);">CRASH!</h1>
<p style="margin-top: 10px;">Vehicle damaged. Please restart.</p>
<button class="btn-action" id="retry-btn">RETRY</button>
</div>
<canvas id="gameCanvas"></canvas>
<div id="mobile-controls">
<div style="display: flex; gap: 10px;">
<div class="ctrl-btn" id="btn-left">â</div>
<div class="ctrl-btn" id="btn-right">âļ</div>
</div>
<div style="display: flex; gap: 10px;">
<div class="ctrl-btn" id="btn-up">â˛</div>
<div class="ctrl-btn" id="btn-down">âŧ</div>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const levelVal = document.getElementById('level-val');
const timeVal = document.getElementById('time-val');
let currentLevel = 1;
let gameActive = false;
let startTime = 0;
let keys = {};
let car, parkingZone, walls, curbs;
const LEVELS = [
{
car: { x: 80, y: 325, angle: 0 },
parking: { x: 700, y: 280, w: 120, h: 90 },
curbs: [
{ x: 0, y: 250, w: 400, h: 10 },
{ x: 0, y: 400, w: 400, h: 10 },
{ x: 500, y: 0, w: 10, h: 300 },
{ x: 500, y: 400, w: 10, h: 250 }
]
},
{
car: { x: 100, y: 100, angle: 0 },
parking: { x: 700, y: 450, w: 120, h: 90 },
curbs: [
{ x: 0, y: 200, w: 700, h: 15 },
{ x: 200, y: 350, w: 700, h: 15 }
]
},
{
car: { x: 450, y: 80, angle: Math.PI/2 },
parking: { x: 100, y: 500, w: 120, h: 90 },
curbs: [
{ x: 0, y: 200, w: 400, h: 15 },
{ x: 500, y: 200, w: 400, h: 15 },
{ x: 400, y: 400, w: 500, h: 15 }
]
}
];
class Car {
constructor(x, y, angle) {
this.x = x;
this.y = y;
this.angle = angle;
this.speed = 0;
this.acc = 0.12;
this.friction = 0.97;
this.maxSpeed = 3.5;
this.width = 50;
this.height = 26;
this.steering = 0.035;
}
update() {
if (keys['ArrowUp'] || keys['KeyW'] || keys['up']) this.speed += this.acc;
if (keys['ArrowDown'] || keys['KeyS'] || keys['down']) this.speed -= this.acc;
this.speed *= this.friction;
if (Math.abs(this.speed) > this.maxSpeed) this.speed = this.maxSpeed * Math.sign(this.speed);
if (Math.abs(this.speed) < 0.05) this.speed = 0;
if (this.speed !== 0) {
const factor = this.speed > 0 ? 1 : -1;
const turnRadius = Math.min(1, Math.abs(this.speed) / 1.5);
if (keys['ArrowLeft'] || keys['KeyA'] || keys['left']) this.angle -= this.steering * factor * turnRadius;
if (keys['ArrowRight'] || keys['KeyD'] || keys['right']) this.angle += this.steering * factor * turnRadius;
}
this.x += Math.cos(this.angle) * this.speed;
this.y += Math.sin(this.angle) * this.speed;
if (this.x < 10 || this.x > canvas.width - 10 || this.y < 10 || this.y > canvas.height - 10) triggerCrash();
}
draw() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.fillRect(-this.width/2 + 4, -this.height/2 + 4, this.width, this.height);
// Car Body (Detailed drawing)
ctx.fillStyle = '#e67e22'; // Sedan Orange
ctx.fillRect(-this.width/2, -this.height/2, this.width, this.height);
// Roof
ctx.fillStyle = '#d35400';
ctx.fillRect(-this.width/4, -this.height/2 + 3, this.width/1.6, this.height - 6);
// Windows
ctx.fillStyle = '#34495e';
ctx.fillRect(0, -this.height/2 + 5, this.width/4, this.height - 10); // Front windshield
ctx.fillRect(-this.width/4 + 2, -this.height/2 + 5, 4, this.height - 10); // Back
// Headlights
ctx.fillStyle = '#fff';
ctx.fillRect(this.width/2 - 4, -this.height/2 + 2, 4, 6);
ctx.fillRect(this.width/2 - 4, this.height/2 - 8, 4, 6);
// Brake lights
if (this.speed < 0 || keys['ArrowDown']) {
ctx.fillStyle = '#f00';
ctx.fillRect(-this.width/2, -this.height/2 + 2, 3, 6);
ctx.fillRect(-this.width/2, this.height/2 - 8, 3, 6);
}
ctx.restore();
}
getBounds() {
// Simplified box for collision
return { x: this.x - 22, y: this.y - 11, w: 44, h: 22 };
}
}
function initLevel(lvlIdx) {
const data = LEVELS[(lvlIdx - 1) % LEVELS.length];
car = new Car(data.car.x, data.car.y, data.car.angle);
parkingZone = data.parking;
curbs = data.curbs;
levelVal.innerText = lvlIdx;
startTime = Date.now();
gameActive = true;
document.querySelectorAll('.overlay').forEach(el => el.classList.add('hidden'));
requestAnimationFrame(gameLoop);
}
function checkCollision(rect1, rect2) {
return rect1.x < rect2.x + rect2.w && rect1.x + rect1.w > rect2.x &&
rect1.y < rect2.y + rect2.h && rect1.y + rect1.h > rect2.y;
}
function triggerCrash() {
gameActive = false;
document.getElementById('crash-screen').classList.remove('hidden');
}
function triggerWin() {
gameActive = false;
const timeTaken = ((Date.now() - startTime) / 1000).toFixed(1);
document.getElementById('level-result').innerText = `Completed in ${timeTaken}s`;
document.getElementById('win-screen').classList.remove('hidden');
}
function gameLoop() {
if (!gameActive) return;
// Draw Asphalt
ctx.fillStyle = '#2c3e50';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw Road Markings
ctx.strokeStyle = 'rgba(255,255,255,0.1)';
ctx.setLineDash([20, 20]);
ctx.lineWidth = 2;
for(let i=100; i<canvas.height; i+=150) {
ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(canvas.width, i); ctx.stroke();
}
ctx.setLineDash([]);
// Draw Parking Spot
ctx.strokeStyle = '#f1c40f'; // Safety Yellow
ctx.lineWidth = 4;
ctx.strokeRect(parkingZone.x, parkingZone.y, parkingZone.w, parkingZone.h);
ctx.fillStyle = 'rgba(241, 196, 15, 0.1)';
ctx.fillRect(parkingZone.x, parkingZone.y, parkingZone.w, parkingZone.h);
// Draw Curbs/Obstacles
ctx.fillStyle = '#7f8c8d'; // Concrete gray
curbs.forEach(c => {
ctx.fillRect(c.x, c.y, c.w, c.h);
// Highlight top of curb
ctx.fillStyle = '#bdc3c7';
ctx.fillRect(c.x, c.y, c.w, 3);
ctx.fillStyle = '#7f8c8d';
if (checkCollision(car.getBounds(), c)) triggerCrash();
});
car.update();
car.draw();
// Win Check (Fully inside and stopped)
const b = car.getBounds();
const isInside = b.x > parkingZone.x && b.x + b.w < parkingZone.x + parkingZone.w &&
b.y > parkingZone.y && b.y + b.h < parkingZone.y + parkingZone.h;
if (isInside && Math.abs(car.speed) < 0.1) triggerWin();
timeVal.innerText = ((Date.now() - startTime) / 1000).toFixed(1);
requestAnimationFrame(gameLoop);
}
// Input
window.addEventListener('keydown', e => keys[e.code] = true);
window.addEventListener('keyup', e => keys[e.code] = false);
const bindMobile = (id, key) => {
const btn = document.getElementById(id);
btn.ontouchstart = (e) => { e.preventDefault(); keys[key] = true; };
btn.ontouchend = () => keys[key] = false;
};
bindMobile('btn-up', 'up'); bindMobile('btn-down', 'down');
bindMobile('btn-left', 'left'); bindMobile('btn-right', 'right');
document.getElementById('start-btn').onclick = () => initLevel(1);
document.getElementById('retry-btn').onclick = () => initLevel(currentLevel);
document.getElementById('next-btn').onclick = () => { currentLevel++; initLevel(currentLevel); };
function resize() {
const container = document.getElementById('game-container');
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
}
window.onload = resize; window.onresize = resize;
</script>
</body>
</html>