Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Theft Auto Grand - 盗窃汽车大</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- background: #000;
- font-family: 'Courier New', monospace;
- overflow: hidden;
- color: white;
- }
- #gameCanvas {
- display: block;
- border: 2px solid #333;
- }
- #ui {
- position: absolute;
- top: 10px;
- left: 10px;
- z-index: 100;
- }
- #healthBar, #shieldBar {
- width: 200px;
- height: 20px;
- border: 2px solid #fff;
- margin-bottom: 5px;
- background: #333;
- }
- #healthFill {
- height: 100%;
- background: linear-gradient(90deg, #ff0000, #ff4444);
- transition: width 0.3s;
- }
- #shieldFill {
- height: 100%;
- background: linear-gradient(90deg, #0066ff, #4488ff);
- transition: width 0.3s;
- }
- #weaponInfo {
- color: #fff;
- font-size: 14px;
- margin-top: 5px;
- }
- #wantedStars {
- margin-top: 10px;
- }
- .star {
- color: #ffdd00;
- font-size: 20px;
- margin-right: 5px;
- }
- #terminal {
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 80%;
- background: rgba(0, 0, 0, 0.8);
- border: 2px solid #00ff00;
- display: none;
- z-index: 200;
- }
- #terminalOutput {
- height: 200px;
- overflow-y: auto;
- padding: 10px;
- color: #00ff00;
- font-size: 12px;
- background: rgba(0, 20, 0, 0.9);
- }
- #terminalInput {
- width: 100%;
- padding: 10px;
- background: #000;
- color: #00ff00;
- border: none;
- font-family: 'Courier New', monospace;
- font-size: 14px;
- }
- #intellisense {
- position: absolute;
- background: rgba(0, 50, 0, 0.95);
- border: 1px solid #00ff00;
- max-height: 150px;
- overflow-y: auto;
- color: #00ff00;
- font-size: 12px;
- display: none;
- }
- .intellisense-item {
- padding: 5px 10px;
- cursor: pointer;
- }
- .intellisense-item:hover {
- background: rgba(0, 100, 0, 0.5);
- }
- #instructions {
- position: absolute;
- top: 10px;
- right: 10px;
- color: #fff;
- font-size: 12px;
- background: rgba(0, 0, 0, 0.7);
- padding: 10px;
- border-radius: 5px;
- max-width: 300px;
- }
- </style>
- </head>
- <body>
- <canvas id="gameCanvas" width="1200" height="800"></canvas>
- <div id="ui">
- <div id="shieldBar">
- <div id="shieldFill" style="width: 100%"></div>
- </div>
- <div id="healthBar">
- <div id="healthFill" style="width: 100%"></div>
- </div>
- <div id="weaponInfo">Weapon: Fists (0/∞)</div>
- <div id="wantedStars"></div>
- </div>
- <div id="instructions">
- <strong>盗窃汽车大 - Theft Auto Grand</strong><br>
- WASD: Move | Space: Enter/Exit Vehicle<br>
- Mouse: Aim/Shoot | 1-8: Select Weapons<br>
- 9: Random Weapon | ~: Terminal<br>
- Japanese/Chinese Market Edition
- </div>
- <div id="terminal">
- <div id="terminalOutput"></div>
- <div id="intellisense"></div>
- <input type="text" id="terminalInput" placeholder="Type command... (try 'help')">
- </div>
- <script>
- class Game {
- constructor() {
- this.canvas = document.getElementById('gameCanvas');
- this.ctx = this.canvas.getContext('2d');
- this.width = this.canvas.width;
- this.height = this.canvas.height;
- this.player = {
- x: 600,
- y: 400,
- size: 12,
- speed: 3,
- health: 100,
- shield: 100,
- maxHealth: 100,
- maxShield: 100,
- angle: 0,
- inVehicle: false,
- vehicle: null,
- godMode: false
- };
- this.weapons = [
- { name: 'Fists', damage: 5, range: 30, ammo: Infinity, fireRate: 500 },
- { name: 'Machete', damage: 999, range: 40, ammo: Infinity, fireRate: 400 },
- { name: 'Pistol', damage: 20, range: 250, ammo: 120, fireRate: 300 },
- { name: 'SMG', damage: 15, range: 150, ammo: 250, fireRate: 100 },
- { name: 'AK-47', damage: 30, range: 200, ammo: 180, fireRate: 150 },
- { name: 'MP-6', damage: 20, range: 120, ammo: 200, fireRate: 80 },
- { name: 'Machine Gun', damage: 25, range: 180, ammo: 500, fireRate: 60 },
- { name: 'Rocket Launcher', damage: 100, range: 250, ammo: 10, fireRate: 1000 }
- ];
- this.currentWeapon = 0;
- this.lastShot = 0;
- this.wantedLevel = 0;
- this.killCount = 0;
- this.npcs = [];
- this.vehicles = [];
- this.bullets = [];
- this.enemies = [];
- this.buildings = [];
- this.camera = { x: 0, y: 0 };
- this.keys = {};
- this.mouse = { x: 0, y: 0, down: false };
- this.terminalOpen = false;
- this.terminalHistory = [];
- this.initializeWorld();
- this.setupEventListeners();
- this.initializeTerminal();
- this.gameLoop();
- }
- initializeWorld() {
- // Generate buildings
- for (let i = 0; i < 50; i++) {
- this.buildings.push({
- x: Math.random() * 2000,
- y: Math.random() * 2000,
- width: 60 + Math.random() * 40,
- height: 60 + Math.random() * 40,
- color: `rgb(${50 + Math.random() * 100}, ${50 + Math.random() * 100}, ${50 + Math.random() * 100})`
- });
- }
- // Generate NPCs (UltraSims)
- for (let i = 0; i < 100; i++) {
- this.npcs.push({
- x: Math.random() * 2000,
- y: Math.random() * 2000,
- vx: (Math.random() - 0.5) * 2,
- vy: (Math.random() - 0.5) * 2,
- health: 100,
- alive: true,
- type: 'civilian'
- });
- }
- // Generate Estal vehicles
- for (let i = 0; i < 30; i++) {
- this.vehicles.push({
- x: Math.random() * 2000,
- y: Math.random() * 2000,
- width: 40,
- height: 20,
- angle: Math.random() * Math.PI * 2,
- speed: 1 + Math.random() * 2,
- occupied: false,
- color: `hsl(${Math.random() * 360}, 70%, 50%)`
- });
- }
- }
- setupEventListeners() {
- document.addEventListener('keydown', (e) => {
- this.keys[e.key.toLowerCase()] = true;
- if (e.key === '`' || e.key === '~') {
- this.toggleTerminal();
- }
- if (!this.terminalOpen) {
- // Weapon selection
- const weaponKeys = ['1', '2', '3', '4', '5', '6', '7', '8'];
- if (weaponKeys.includes(e.key)) {
- this.currentWeapon = parseInt(e.key) - 1;
- }
- if (e.key === '9') {
- this.currentWeapon = Math.floor(Math.random() * 8);
- }
- }
- });
- document.addEventListener('keyup', (e) => {
- this.keys[e.key.toLowerCase()] = false;
- });
- this.canvas.addEventListener('mousemove', (e) => {
- const rect = this.canvas.getBoundingClientRect();
- this.mouse.x = e.clientX - rect.left;
- this.mouse.y = e.clientY - rect.top;
- });
- this.canvas.addEventListener('mousedown', () => {
- this.mouse.down = true;
- });
- this.canvas.addEventListener('mouseup', () => {
- this.mouse.down = false;
- });
- }
- initializeTerminal() {
- const input = document.getElementById('terminalInput');
- const output = document.getElementById('terminalOutput');
- const intellisense = document.getElementById('intellisense');
- const commands = [
- 'help', 'add health', 'add shield', 'godmode', 'clear wanted', 'spawn vehicle',
- 'spawn weapon', 'teleport', 'kill all', 'explode all', 'weather rain',
- 'weather clear', 'time day', 'time night', 'invincible', 'unlimited ammo',
- 'max wanted', 'clear npcs', 'spawn army', 'nuke city', 'matrix mode',
- 'slow motion', 'fast forward', 'invisible', 'super speed', 'mega jump'
- ];
- input.addEventListener('keydown', (e) => {
- if (e.key === 'Enter') {
- this.executeCommand(input.value);
- input.value = '';
- intellisense.style.display = 'none';
- }
- });
- input.addEventListener('input', (e) => {
- const value = e.target.value.toLowerCase();
- const matches = commands.filter(cmd => cmd.startsWith(value));
- if (matches.length > 0 && value.length > 0) {
- intellisense.innerHTML = matches.map(cmd =>
- `<div class="intellisense-item" onclick="this.selectCommand('${cmd}')">${cmd}</div>`
- ).join('');
- intellisense.style.display = 'block';
- } else {
- intellisense.style.display = 'none';
- }
- });
- window.selectCommand = (cmd) => {
- input.value = cmd;
- intellisense.style.display = 'none';
- input.focus();
- };
- }
- toggleTerminal() {
- this.terminalOpen = !this.terminalOpen;
- const terminal = document.getElementById('terminal');
- terminal.style.display = this.terminalOpen ? 'block' : 'none';
- if (this.terminalOpen) {
- document.getElementById('terminalInput').focus();
- }
- }
- executeCommand(cmd) {
- const output = document.getElementById('terminalOutput');
- const parts = cmd.toLowerCase().split(' ');
- let response = '';
- switch (parts[0]) {
- case 'help':
- response = 'Available commands:\nadd health [amount] - Add health\nadd shield [amount] - Add shield\ngodmode - Toggle invincibility\nclear wanted - Reset wanted level\nspawn vehicle - Spawn nearby vehicle\nteleport [x] [y] - Teleport to coordinates\nkill all - Eliminate all NPCs\nexplode all - Explode all vehicles\nweather [rain/clear] - Change weather\ntime [day/night] - Change time\nunlimited ammo - Toggle infinite ammo\nmax wanted - Set max wanted level\nsuper speed - Toggle super speed';
- break;
- case 'add':
- if (parts[1] === 'health') {
- const amount = parseInt(parts[2]) || 50;
- this.player.health = Math.min(this.player.maxHealth, this.player.health + amount);
- response = `Added ${amount} health. Current: ${this.player.health}/${this.player.maxHealth}`;
- } else if (parts[1] === 'shield') {
- const amount = parseInt(parts[2]) || 50;
- this.player.shield = Math.min(this.player.maxShield, this.player.shield + amount);
- response = `Added ${amount} shield. Current: ${this.player.shield}/${this.player.maxShield}`;
- }
- break;
- case 'godmode':
- this.player.godMode = !this.player.godMode;
- response = `God mode: ${this.player.godMode ? 'ON' : 'OFF'}`;
- break;
- case 'clear':
- if (parts[1] === 'wanted') {
- this.wantedLevel = 0;
- this.enemies = [];
- response = 'Wanted level cleared';
- }
- break;
- case 'spawn':
- if (parts[1] === 'vehicle') {
- this.vehicles.push({
- x: this.player.x + 50,
- y: this.player.y,
- width: 40,
- height: 20,
- angle: 0,
- speed: 2,
- occupied: false,
- color: `hsl(${Math.random() * 360}, 70%, 50%)`
- });
- response = 'Vehicle spawned nearby';
- }
- break;
- case 'teleport':
- const x = parseInt(parts[1]) || 0;
- const y = parseInt(parts[2]) || 0;
- this.player.x = x;
- this.player.y = y;
- response = `Teleported to (${x}, ${y})`;
- break;
- case 'kill':
- if (parts[1] === 'all') {
- this.npcs.forEach(npc => npc.alive = false);
- response = 'All NPCs eliminated';
- }
- break;
- case 'max':
- if (parts[1] === 'wanted') {
- this.wantedLevel = 5;
- response = 'Wanted level set to maximum!';
- }
- break;
- default:
- response = `Unknown command: ${cmd}. Type 'help' for available commands.`;
- }
- output.innerHTML += `> ${cmd}\n${response}\n\n`;
- output.scrollTop = output.scrollHeight;
- }
- update() {
- // Only update game state when terminal is closed
- if (!this.terminalOpen) {
- this.updatePlayer();
- this.updateNPCs();
- this.updateVehicles();
- this.updateBullets();
- this.updateEnemies();
- this.updateCamera();
- this.updateWantedLevel();
- if (this.mouse.down) {
- this.shoot();
- }
- }
- // Always update UI regardless of terminal state
- this.updateUI();
- }
- updatePlayer() {
- let moveX = 0, moveY = 0;
- if (this.keys['w']) moveY -= 1;
- if (this.keys['s']) moveY += 1;
- if (this.keys['a']) moveX -= 1;
- if (this.keys['d']) moveX += 1;
- if (this.keys[' ']) {
- this.toggleVehicle();
- this.keys[' '] = false; // Prevent continuous triggering
- }
- const speed = this.player.inVehicle ? 5 : this.player.speed;
- if (moveX !== 0 || moveY !== 0) {
- const length = Math.sqrt(moveX * moveX + moveY * moveY);
- moveX /= length;
- moveY /= length;
- this.player.x += moveX * speed;
- this.player.y += moveY * speed;
- if (this.player.inVehicle && this.player.vehicle) {
- this.player.vehicle.x = this.player.x;
- this.player.vehicle.y = this.player.y;
- this.player.vehicle.angle = Math.atan2(moveY, moveX);
- }
- }
- // Update player angle based on mouse position
- const worldMouseX = this.mouse.x + this.camera.x;
- const worldMouseY = this.mouse.y + this.camera.y;
- this.player.angle = Math.atan2(worldMouseY - this.player.y, worldMouseX - this.player.x);
- }
- toggleVehicle() {
- if (this.player.inVehicle) {
- // Exit vehicle
- this.player.inVehicle = false;
- if (this.player.vehicle) {
- this.player.vehicle.occupied = false;
- this.player.vehicle = null;
- }
- } else {
- // Find nearby vehicle
- for (let vehicle of this.vehicles) {
- const dist = Math.sqrt((vehicle.x - this.player.x) ** 2 + (vehicle.y - this.player.y) ** 2);
- if (dist < 50 && !vehicle.occupied) {
- this.player.inVehicle = true;
- this.player.vehicle = vehicle;
- vehicle.occupied = true;
- this.player.x = vehicle.x;
- this.player.y = vehicle.y;
- break;
- }
- }
- }
- }
- updateNPCs() {
- this.npcs.forEach((npc, index) => {
- if (!npc.alive) return;
- // Simple AI movement
- npc.x += npc.vx;
- npc.y += npc.vy;
- // Boundary check
- if (npc.x < 0 || npc.x > 2000) npc.vx *= -1;
- if (npc.y < 0 || npc.y > 2000) npc.vy *= -1;
- // Random direction change
- if (Math.random() < 0.01) {
- npc.vx = (Math.random() - 0.5) * 2;
- npc.vy = (Math.random() - 0.5) * 2;
- }
- });
- }
- updateVehicles() {
- this.vehicles.forEach(vehicle => {
- if (!vehicle.occupied) {
- // Estal AI driving
- vehicle.x += Math.cos(vehicle.angle) * vehicle.speed;
- vehicle.y += Math.sin(vehicle.angle) * vehicle.speed;
- // Random steering
- if (Math.random() < 0.02) {
- vehicle.angle += (Math.random() - 0.5) * 0.5;
- }
- // Boundary wrap
- if (vehicle.x < 0) vehicle.x = 2000;
- if (vehicle.x > 2000) vehicle.x = 0;
- if (vehicle.y < 0) vehicle.y = 2000;
- if (vehicle.y > 2000) vehicle.y = 0;
- // Check for NPC collisions (Estal vehicles can be dangerous)
- this.npcs.forEach(npc => {
- if (!npc.alive) return;
- const dist = Math.sqrt((vehicle.x - npc.x) ** 2 + (vehicle.y - npc.y) ** 2);
- if (dist < 25) {
- npc.alive = false;
- this.killCount++;
- }
- });
- }
- });
- }
- updateBullets() {
- this.bullets.forEach((bullet, index) => {
- bullet.x += bullet.vx;
- bullet.y += bullet.vy;
- bullet.life--;
- if (bullet.life <= 0) {
- this.bullets.splice(index, 1);
- return;
- }
- // Check NPC hits
- this.npcs.forEach(npc => {
- if (!npc.alive) return;
- const dist = Math.sqrt((bullet.x - npc.x) ** 2 + (bullet.y - npc.y) ** 2);
- if (dist < 15) {
- npc.alive = false;
- this.bullets.splice(index, 1);
- this.killCount++;
- }
- });
- // Check enemy hits
- this.enemies.forEach((enemy, enemyIndex) => {
- const dist = Math.sqrt((bullet.x - enemy.x) ** 2 + (bullet.y - enemy.y) ** 2);
- if (dist < 15) {
- enemy.health -= bullet.damage;
- this.bullets.splice(index, 1);
- if (enemy.health <= 0) {
- this.enemies.splice(enemyIndex, 1);
- }
- }
- });
- });
- }
- updateEnemies() {
- // Spawn enemies based on wanted level
- if (this.wantedLevel > 0 && this.enemies.length < this.wantedLevel * 5) {
- const spawnDistance = 300 + Math.random() * 200;
- const angle = Math.random() * Math.PI * 2;
- let enemyType = 'police';
- let health = 100;
- let damage = 10;
- if (this.wantedLevel >= 2) enemyType = 'armored_police', health = 150;
- if (this.wantedLevel >= 3) enemyType = 'swat', health = 200, damage = 15;
- if (this.wantedLevel >= 4) enemyType = 'fbi', health = 250, damage = 20;
- if (this.wantedLevel >= 5) enemyType = 'army', health = 300, damage = 25;
- this.enemies.push({
- x: this.player.x + Math.cos(angle) * spawnDistance,
- y: this.player.y + Math.sin(angle) * spawnDistance,
- health: health,
- maxHealth: health,
- type: enemyType,
- damage: damage,
- lastShot: 0,
- angle: 0
- });
- }
- // Update enemy AI
- this.enemies.forEach((enemy, index) => {
- // Move toward player
- const dx = this.player.x - enemy.x;
- const dy = this.player.y - enemy.y;
- const dist = Math.sqrt(dx * dx + dy * dy);
- if (dist > 0) {
- const speed = enemy.type === 'army' ? 2 : 1.5;
- enemy.x += (dx / dist) * speed;
- enemy.y += (dy / dist) * speed;
- enemy.angle = Math.atan2(dy, dx);
- }
- // Shoot at player
- if (dist < 200 && Date.now() - enemy.lastShot > 800) {
- const bulletSpeed = 8;
- this.bullets.push({
- x: enemy.x,
- y: enemy.y,
- vx: Math.cos(enemy.angle) * bulletSpeed,
- vy: Math.sin(enemy.angle) * bulletSpeed,
- life: 100,
- damage: enemy.damage,
- fromEnemy: true
- });
- enemy.lastShot = Date.now();
- }
- });
- // Check enemy bullets hitting player
- this.bullets.forEach((bullet, index) => {
- if (!bullet.fromEnemy) return;
- const dist = Math.sqrt((bullet.x - this.player.x) ** 2 + (bullet.y - this.player.y) ** 2);
- if (dist < 15) {
- if (!this.player.godMode) {
- if (this.player.shield > 0) {
- this.player.shield -= bullet.damage;
- if (this.player.shield < 0) {
- this.player.health += this.player.shield;
- this.player.shield = 0;
- }
- } else {
- this.player.health -= bullet.damage;
- }
- }
- this.bullets.splice(index, 1);
- }
- });
- }
- updateWantedLevel() {
- let newWantedLevel = 0;
- if (this.killCount >= 1) newWantedLevel = 1;
- if (this.killCount >= 5) newWantedLevel = 2;
- if (this.killCount >= 15) newWantedLevel = 3;
- if (this.killCount >= 30) newWantedLevel = 4;
- if (this.killCount >= 60) newWantedLevel = 5;
- this.wantedLevel = newWantedLevel;
- }
- shoot() {
- const weapon = this.weapons[this.currentWeapon];
- if (Date.now() - this.lastShot < weapon.fireRate) return;
- if (weapon.ammo <= 0) return;
- const bulletSpeed = 10;
- const spread = weapon.name === 'SMG' || weapon.name === 'Machine Gun' ? 0.1 : 0.02;
- const angle = this.player.angle + (Math.random() - 0.5) * spread;
- this.bullets.push({
- x: this.player.x,
- y: this.player.y,
- vx: Math.cos(angle) * bulletSpeed,
- vy: Math.sin(angle) * bulletSpeed,
- life: weapon.range / bulletSpeed,
- damage: weapon.damage,
- fromEnemy: false
- });
- if (weapon.ammo !== Infinity) {
- weapon.ammo--;
- }
- this.lastShot = Date.now();
- }
- updateCamera() {
- this.camera.x = this.player.x - this.width / 2;
- this.camera.y = this.player.y - this.height / 2;
- }
- updateUI() {
- document.getElementById('healthFill').style.width = (this.player.health / this.player.maxHealth * 100) + '%';
- document.getElementById('shieldFill').style.width = (this.player.shield / this.player.maxShield * 100) + '%';
- const weapon = this.weapons[this.currentWeapon];
- document.getElementById('weaponInfo').textContent =
- `Weapon: ${weapon.name} (${weapon.ammo === Infinity ? '∞' : weapon.ammo}/${weapon.ammo === Infinity ? '∞' : weapon.ammo})`;
- const starsHtml = '★'.repeat(this.wantedLevel) + '☆'.repeat(5 - this.wantedLevel);
- document.getElementById('wantedStars').innerHTML = `<div class="star">Wanted: ${starsHtml}</div>`;
- }
- render() {
- this.ctx.fillStyle = '#2a4a2a';
- this.ctx.fillRect(0, 0, this.width, this.height);
- this.ctx.save();
- this.ctx.translate(-this.camera.x, -this.camera.y);
- // Draw buildings
- this.buildings.forEach(building => {
- this.ctx.fillStyle = building.color;
- this.ctx.fillRect(building.x, building.y, building.width, building.height);
- this.ctx.strokeStyle = '#000';
- this.ctx.strokeRect(building.x, building.y, building.width, building.height);
- });
- // Draw NPCs
- this.npcs.forEach(npc => {
- if (!npc.alive) return;
- this.ctx.fillStyle = '#ff9999';
- this.ctx.beginPath();
- this.ctx.arc(npc.x, npc.y, 8, 0, Math.PI * 2);
- this.ctx.fill();
- // UltraSim label
- this.ctx.fillStyle = '#fff';
- this.ctx.font = '8px Arial';
- this.ctx.fillText('US', npc.x - 8, npc.y - 12);
- });
- // Draw vehicles
- this.vehicles.forEach(vehicle => {
- this.ctx.save();
- this.ctx.translate(vehicle.x, vehicle.y);
- this.ctx.rotate(vehicle.angle);
- this.ctx.fillStyle = vehicle.color;
- this.ctx.fillRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
- this.ctx.strokeStyle = '#000';
- this.ctx.strokeRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
- // Estal brand logo
- this.ctx.fillStyle = '#fff';
- this.ctx.font = '6px Arial';
- this.ctx.fillText('ESTAL', -12, 2);
- this.ctx.restore();
- });
- // Draw bullets
- this.bullets.forEach(bullet => {
- this.ctx.fillStyle = bullet.fromEnemy ? '#ff4444' : '#ffff44';
- this.ctx.beginPath();
- this.ctx.arc(bullet.x, bullet.y, 2, 0, Math.PI * 2);
- this.ctx.fill();
- });
- // Draw enemies
- this.enemies.forEach(enemy => {
- let color = '#4444ff';
- if (enemy.type === 'armored_police') color = '#666699';
- if (enemy.type === 'swat') color = '#333366';
- if (enemy.type === 'fbi') color = '#000033';
- if (enemy.type === 'army') color = '#006600';
- this.ctx.fillStyle = color;
- this.ctx.beginPath();
- this.ctx.arc(enemy.x, enemy.y, 10, 0, Math.PI * 2);
- this.ctx.fill();
- // Health bar
- const barWidth = 20;
- const healthPercent = enemy.health / enemy.maxHealth;
- this.ctx.fillStyle = '#333';
- this.ctx.fillRect(enemy.x - barWidth/2, enemy.y - 18, barWidth, 4);
- this.ctx.fillStyle = '#ff0000';
- this.ctx.fillRect(enemy.x - barWidth/2, enemy.y - 18, barWidth * healthPercent, 4);
- // Type label
- this.ctx.fillStyle = '#fff';
- this.ctx.font = '8px Arial';
- this.ctx.fillText(enemy.type.toUpperCase(), enemy.x - 15, enemy.y + 20);
- });
- // Draw player
- if (this.player.inVehicle && this.player.vehicle) {
- // Player is in vehicle, draw vehicle differently
- const vehicle = this.player.vehicle;
- this.ctx.save();
- this.ctx.translate(vehicle.x, vehicle.y);
- this.ctx.rotate(vehicle.angle);
- this.ctx.fillStyle = '#ffaa00'; // Player vehicle highlight
- this.ctx.fillRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
- this.ctx.strokeStyle = '#fff';
- this.ctx.lineWidth = 2;
- this.ctx.strokeRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
- this.ctx.restore();
- } else {
- // Draw player on foot
- this.ctx.save();
- this.ctx.translate(this.player.x, this.player.y);
- this.ctx.rotate(this.player.angle);
- // Player body
- this.ctx.fillStyle = this.player.godMode ? '#00ffff' : '#ffaa00';
- this.ctx.beginPath();
- this.ctx.arc(0, 0, this.player.size, 0, Math.PI * 2);
- this.ctx.fill();
- // Weapon indicator
- const weapon = this.weapons[this.currentWeapon];
- this.ctx.strokeStyle = '#fff';
- this.ctx.lineWidth = 2;
- this.ctx.beginPath();
- this.ctx.moveTo(0, 0);
- this.ctx.lineTo(weapon.range / 10, 0);
- this.ctx.stroke();
- this.ctx.restore();
- // Player name
- this.ctx.fillStyle = '#fff';
- this.ctx.font = '10px Arial';
- this.ctx.fillText('UltraSim™ Player', this.player.x - 30, this.player.y - 20);
- }
- this.ctx.restore();
- // Game over check
- if (this.player.health <= 0) {
- this.ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
- this.ctx.fillRect(0, 0, this.width, this.height);
- this.ctx.fillStyle = '#ff0000';
- this.ctx.font = '48px Arial';
- this.ctx.textAlign = 'center';
- this.ctx.fillText('WASTED', this.width/2, this.height/2);
- this.ctx.fillText('盗窃汽车大', this.width/2, this.height/2 + 60);
- this.ctx.fillStyle = '#fff';
- this.ctx.font = '16px Arial';
- this.ctx.fillText('Press F5 to restart', this.width/2, this.height/2 + 100);
- this.ctx.textAlign = 'left';
- }
- }
- gameLoop() {
- this.update();
- this.render();
- requestAnimationFrame(() => this.gameLoop());
- }
- }
- // Initialize game when page loads
- window.addEventListener('load', () => {
- new Game();
- });
- // Prevent context menu on canvas
- document.getElementById('gameCanvas').addEventListener('contextmenu', (e) => {
- e.preventDefault();
- });
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment