works
This commit is contained in:
		
							
								
								
									
										869
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										869
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,869 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Zombie Survival Shooter</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        * {
 | 
			
		||||
            margin: 0;
 | 
			
		||||
            padding: 0;
 | 
			
		||||
            box-sizing: border-box;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        body {
 | 
			
		||||
            background: linear-gradient(135deg, #1a1a1a 0%, #2d2d30 100%);
 | 
			
		||||
            font-family: 'Courier New', monospace;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            height: 100vh;
 | 
			
		||||
            width: 100vw;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        canvas {
 | 
			
		||||
            display: block;
 | 
			
		||||
            background: linear-gradient(45deg, #3a3a3a 0%, #4a4a4a 100%);
 | 
			
		||||
            image-rendering: pixelated;
 | 
			
		||||
            image-rendering: -moz-crisp-edges;
 | 
			
		||||
            image-rendering: crisp-edges;
 | 
			
		||||
            width: 100vw;
 | 
			
		||||
            height: 100vh;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .ui {
 | 
			
		||||
            position: fixed;
 | 
			
		||||
            top: 20px;
 | 
			
		||||
            left: 20px;
 | 
			
		||||
            color: white;
 | 
			
		||||
            font-size: 18px;
 | 
			
		||||
            z-index: 10;
 | 
			
		||||
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .weapon-info {
 | 
			
		||||
            background: linear-gradient(135deg, rgba(0, 0, 0, 0.8) 0%, rgba(20, 20, 20, 0.9) 100%);
 | 
			
		||||
            padding: 15px 20px;
 | 
			
		||||
            border-radius: 10px;
 | 
			
		||||
            border: 2px solid rgba(255, 255, 255, 0.1);
 | 
			
		||||
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);
 | 
			
		||||
            backdrop-filter: blur(5px);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .weapon-info div {
 | 
			
		||||
            margin: 5px 0;
 | 
			
		||||
            font-weight: bold;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .weapon-info span {
 | 
			
		||||
            color: #00ff88;
 | 
			
		||||
            text-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        #score {
 | 
			
		||||
            color: #ffaa00 !important;
 | 
			
		||||
            text-shadow: 0 0 10px rgba(255, 170, 0, 0.5) !important;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        #health {
 | 
			
		||||
            color: #ff4444 !important;
 | 
			
		||||
            text-shadow: 0 0 10px rgba(255, 68, 68, 0.5) !important;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <canvas id="gameCanvas"></canvas>
 | 
			
		||||
    <div class="ui">
 | 
			
		||||
        <div class="weapon-info">
 | 
			
		||||
            <div>Weapon: <span id="weaponName">Pistol</span></div>
 | 
			
		||||
            <div>Ammo: <span id="ammoCount">∞</span></div>
 | 
			
		||||
            <div>Health: <span id="health">100</span></div>
 | 
			
		||||
            <div>Score: <span id="score">0</span></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <script>
 | 
			
		||||
        const canvas = document.getElementById('gameCanvas');
 | 
			
		||||
        const ctx = canvas.getContext('2d');
 | 
			
		||||
        
 | 
			
		||||
        // Make canvas fullscreen
 | 
			
		||||
        function resizeCanvas() {
 | 
			
		||||
            canvas.width = window.innerWidth;
 | 
			
		||||
            canvas.height = window.innerHeight;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        resizeCanvas();
 | 
			
		||||
        window.addEventListener('resize', resizeCanvas);
 | 
			
		||||
        
 | 
			
		||||
        // Game state
 | 
			
		||||
        const game = {
 | 
			
		||||
            player: null,
 | 
			
		||||
            zombies: [],
 | 
			
		||||
            bullets: [],
 | 
			
		||||
            weapons: [],
 | 
			
		||||
            weaponDrops: [],
 | 
			
		||||
            score: 0,
 | 
			
		||||
            keys: {},
 | 
			
		||||
            mouse: { x: 0, y: 0, down: false },
 | 
			
		||||
            map: null,
 | 
			
		||||
            camera: { x: 0, y: 0 },
 | 
			
		||||
            tileSize: 32,
 | 
			
		||||
            mapWidth: 50,
 | 
			
		||||
            mapHeight: 40
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        // Sprite loader
 | 
			
		||||
        const sprites = {};
 | 
			
		||||
        const spriteList = [
 | 
			
		||||
            'main-character.png',
 | 
			
		||||
            'zombie.png', 'zombie2.png', 'zombie3.png', 'zombie4.png',
 | 
			
		||||
            'pistol.png', 'shotgun.png', 'burst-rifle.png', 'machine-gun.png',
 | 
			
		||||
            'bullet.png', 'bullet-shotgun.png',
 | 
			
		||||
            'zombie-dead.png'
 | 
			
		||||
        ];
 | 
			
		||||
        
 | 
			
		||||
        let spritesLoaded = 0;
 | 
			
		||||
        
 | 
			
		||||
        function loadSprites() {
 | 
			
		||||
            spriteList.forEach(spriteName => {
 | 
			
		||||
                const img = new Image();
 | 
			
		||||
                img.onload = () => {
 | 
			
		||||
                    spritesLoaded++;
 | 
			
		||||
                    if (spritesLoaded === spriteList.length) {
 | 
			
		||||
                        initGame();
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                img.src = spriteName;
 | 
			
		||||
                sprites[spriteName] = img;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Weapon definitions
 | 
			
		||||
        const weaponTypes = {
 | 
			
		||||
            pistol: {
 | 
			
		||||
                name: 'Pistol',
 | 
			
		||||
                ammo: Infinity,
 | 
			
		||||
                damage: 25,
 | 
			
		||||
                fireRate: 300,
 | 
			
		||||
                spread: 0,
 | 
			
		||||
                bulletsPerShot: 1,
 | 
			
		||||
                range: 400,
 | 
			
		||||
                autoFire: false,
 | 
			
		||||
                burstCount: 1,
 | 
			
		||||
                sprite: 'pistol.png'
 | 
			
		||||
            },
 | 
			
		||||
            shotgun: {
 | 
			
		||||
                name: 'Shotgun',
 | 
			
		||||
                ammo: 8,
 | 
			
		||||
                damage: 40,
 | 
			
		||||
                fireRate: 800,
 | 
			
		||||
                spread: 0.5,
 | 
			
		||||
                bulletsPerShot: 5,
 | 
			
		||||
                range: 200,
 | 
			
		||||
                autoFire: false,
 | 
			
		||||
                burstCount: 1,
 | 
			
		||||
                sprite: 'shotgun.png'
 | 
			
		||||
            },
 | 
			
		||||
            burstRifle: {
 | 
			
		||||
                name: 'Burst Rifle',
 | 
			
		||||
                ammo: 30,
 | 
			
		||||
                damage: 55,
 | 
			
		||||
                fireRate: 100,
 | 
			
		||||
                spread: 0.1,
 | 
			
		||||
                bulletsPerShot: 1,
 | 
			
		||||
                range: 350,
 | 
			
		||||
                autoFire: false,
 | 
			
		||||
                burstCount: 3,
 | 
			
		||||
                sprite: 'burst-rifle.png'
 | 
			
		||||
            },
 | 
			
		||||
            machineGun: {
 | 
			
		||||
                name: 'Machine Gun',
 | 
			
		||||
                ammo: 50,
 | 
			
		||||
                damage: 45,
 | 
			
		||||
                fireRate: 100,
 | 
			
		||||
                spread: 0.2,
 | 
			
		||||
                bulletsPerShot: 1,
 | 
			
		||||
                range: 300,
 | 
			
		||||
                autoFire: true,
 | 
			
		||||
                burstCount: 1,
 | 
			
		||||
                sprite: 'machine-gun.png'
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        // Tile system
 | 
			
		||||
        const TILE_TYPES = {
 | 
			
		||||
            FLOOR: 0,
 | 
			
		||||
            WALL: 1,
 | 
			
		||||
            BUILDING: 2,
 | 
			
		||||
            ROAD: 3
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        function createTileSVG(type, size = 32) {
 | 
			
		||||
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
 | 
			
		||||
            svg.setAttribute('width', size);
 | 
			
		||||
            svg.setAttribute('height', size);
 | 
			
		||||
            svg.setAttribute('viewBox', `0 0 ${size} ${size}`);
 | 
			
		||||
            
 | 
			
		||||
            switch(type) {
 | 
			
		||||
                case TILE_TYPES.FLOOR:
 | 
			
		||||
                    // Concrete floor with texture
 | 
			
		||||
                    svg.innerHTML = `
 | 
			
		||||
                        <rect width="${size}" height="${size}" fill="#4a4a4a"/>
 | 
			
		||||
                        <rect x="0" y="0" width="16" height="16" fill="#525252"/>
 | 
			
		||||
                        <rect x="16" y="16" width="16" height="16" fill="#525252"/>
 | 
			
		||||
                        <rect x="2" y="2" width="2" height="2" fill="#3a3a3a"/>
 | 
			
		||||
                        <rect x="28" y="6" width="2" height="2" fill="#3a3a3a"/>
 | 
			
		||||
                        <rect x="8" y="24" width="2" height="2" fill="#3a3a3a"/>
 | 
			
		||||
                        <rect x="22" y="28" width="2" height="2" fill="#3a3a3a"/>
 | 
			
		||||
                    `;
 | 
			
		||||
                    break;
 | 
			
		||||
                case TILE_TYPES.WALL:
 | 
			
		||||
                    // Brick wall
 | 
			
		||||
                    svg.innerHTML = `
 | 
			
		||||
                        <rect width="${size}" height="${size}" fill="#8B4513"/>
 | 
			
		||||
                        <rect x="0" y="0" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                        <rect x="16" y="0" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                        <rect x="8" y="8" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                        <rect x="0" y="16" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                        <rect x="16" y="16" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                        <rect x="8" y="24" width="16" height="8" fill="#A0522D" stroke="#654321" stroke-width="1"/>
 | 
			
		||||
                    `;
 | 
			
		||||
                    break;
 | 
			
		||||
                case TILE_TYPES.BUILDING:
 | 
			
		||||
                    // Building tile
 | 
			
		||||
                    svg.innerHTML = `
 | 
			
		||||
                        <rect width="${size}" height="${size}" fill="#2F4F4F"/>
 | 
			
		||||
                        <rect x="2" y="2" width="${size-4}" height="${size-4}" fill="#708090"/>
 | 
			
		||||
                        <rect x="6" y="6" width="8" height="8" fill="#4682B4"/>
 | 
			
		||||
                        <rect x="18" y="6" width="8" height="8" fill="#4682B4"/>
 | 
			
		||||
                        <rect x="6" y="18" width="8" height="8" fill="#4682B4"/>
 | 
			
		||||
                        <rect x="18" y="18" width="8" height="8" fill="#4682B4"/>
 | 
			
		||||
                        <rect x="7" y="7" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="11" y="7" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="19" y="7" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="23" y="7" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="7" y="19" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="11" y="19" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="19" y="19" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                        <rect x="23" y="19" width="2" height="2" fill="#87CEEB"/>
 | 
			
		||||
                    `;
 | 
			
		||||
                    break;
 | 
			
		||||
                case TILE_TYPES.ROAD:
 | 
			
		||||
                    // Asphalt road
 | 
			
		||||
                    svg.innerHTML = `
 | 
			
		||||
                        <rect width="${size}" height="${size}" fill="#2F2F2F"/>
 | 
			
		||||
                        <rect x="0" y="14" width="${size}" height="4" fill="#FFFF00"/>
 | 
			
		||||
                        <rect x="4" y="4" width="2" height="2" fill="#1F1F1F"/>
 | 
			
		||||
                        <rect x="26" y="8" width="2" height="2" fill="#1F1F1F"/>
 | 
			
		||||
                        <rect x="12" y="22" width="2" height="2" fill="#1F1F1F"/>
 | 
			
		||||
                        <rect x="20" y="26" width="2" height="2" fill="#1F1F1F"/>
 | 
			
		||||
                    `;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return svg;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function generateMap() {
 | 
			
		||||
            const map = [];
 | 
			
		||||
            for (let y = 0; y < game.mapHeight; y++) {
 | 
			
		||||
                const row = [];
 | 
			
		||||
                for (let x = 0; x < game.mapWidth; x++) {
 | 
			
		||||
                    // Border walls
 | 
			
		||||
                    if (x === 0 || x === game.mapWidth - 1 || y === 0 || y === game.mapHeight - 1) {
 | 
			
		||||
                        row.push(TILE_TYPES.WALL);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Buildings in clusters
 | 
			
		||||
                    else if (Math.random() < 0.15 && x > 5 && x < game.mapWidth - 5 && y > 5 && y < game.mapHeight - 5) {
 | 
			
		||||
                        row.push(TILE_TYPES.BUILDING);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Walls for structure
 | 
			
		||||
                    else if (Math.random() < 0.08) {
 | 
			
		||||
                        row.push(TILE_TYPES.WALL);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Roads
 | 
			
		||||
                    else if ((x % 8 === 0 || y % 8 === 0) && Math.random() < 0.3) {
 | 
			
		||||
                        row.push(TILE_TYPES.ROAD);
 | 
			
		||||
                    }
 | 
			
		||||
                    // Default floor
 | 
			
		||||
                    else {
 | 
			
		||||
                        row.push(TILE_TYPES.FLOOR);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                map.push(row);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Ensure starting area is clear
 | 
			
		||||
            const centerX = Math.floor(game.mapWidth / 2);
 | 
			
		||||
            const centerY = Math.floor(game.mapHeight / 2);
 | 
			
		||||
            for (let dy = -2; dy <= 2; dy++) {
 | 
			
		||||
                for (let dx = -2; dx <= 2; dx++) {
 | 
			
		||||
                    if (centerX + dx >= 0 && centerX + dx < game.mapWidth && 
 | 
			
		||||
                        centerY + dy >= 0 && centerY + dy < game.mapHeight) {
 | 
			
		||||
                        map[centerY + dy][centerX + dx] = TILE_TYPES.FLOOR;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function renderTileToCanvas(type, x, y) {
 | 
			
		||||
            const svg = createTileSVG(type, game.tileSize);
 | 
			
		||||
            const svgData = new XMLSerializer().serializeToString(svg);
 | 
			
		||||
            const img = new Image();
 | 
			
		||||
            const blob = new Blob([svgData], {type: 'image/svg+xml'});
 | 
			
		||||
            const url = URL.createObjectURL(blob);
 | 
			
		||||
            
 | 
			
		||||
            img.onload = function() {
 | 
			
		||||
                ctx.drawImage(img, x * game.tileSize, y * game.tileSize);
 | 
			
		||||
                URL.revokeObjectURL(url);
 | 
			
		||||
            };
 | 
			
		||||
            img.src = url;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function isWalkable(tileType) {
 | 
			
		||||
            return tileType === TILE_TYPES.FLOOR || tileType === TILE_TYPES.ROAD;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function getTileAt(x, y) {
 | 
			
		||||
            const tileX = Math.floor(x / game.tileSize);
 | 
			
		||||
            const tileY = Math.floor(y / game.tileSize);
 | 
			
		||||
            
 | 
			
		||||
            if (tileX < 0 || tileX >= game.mapWidth || tileY < 0 || tileY >= game.mapHeight) {
 | 
			
		||||
                return TILE_TYPES.WALL;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return game.map[tileY][tileX];
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        class Player {
 | 
			
		||||
            constructor(x, y) {
 | 
			
		||||
                this.x = x;
 | 
			
		||||
                this.y = y;
 | 
			
		||||
                this.width = 32;
 | 
			
		||||
                this.height = 32;
 | 
			
		||||
                this.speed = 3;
 | 
			
		||||
                this.weapon = { ...weaponTypes.pistol };
 | 
			
		||||
                this.lastShot = 0;
 | 
			
		||||
                this.burstCount = 0;
 | 
			
		||||
                this.burstTimer = 0;
 | 
			
		||||
                this.health = 100;
 | 
			
		||||
                this.maxHealth = 100;
 | 
			
		||||
                this.lastDamage = 0;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            update() {
 | 
			
		||||
                // Movement with collision detection
 | 
			
		||||
                let newX = this.x;
 | 
			
		||||
                let newY = this.y;
 | 
			
		||||
                
 | 
			
		||||
                if (game.keys['w'] || game.keys['W']) newY -= this.speed;
 | 
			
		||||
                if (game.keys['s'] || game.keys['S']) newY += this.speed;
 | 
			
		||||
                if (game.keys['a'] || game.keys['A']) newX -= this.speed;
 | 
			
		||||
                if (game.keys['d'] || game.keys['D']) newX += this.speed;
 | 
			
		||||
                
 | 
			
		||||
                // Check collision for X movement
 | 
			
		||||
                if (isWalkable(getTileAt(newX - this.width/2, this.y)) && 
 | 
			
		||||
                    isWalkable(getTileAt(newX + this.width/2, this.y))) {
 | 
			
		||||
                    this.x = newX;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Check collision for Y movement
 | 
			
		||||
                if (isWalkable(getTileAt(this.x, newY - this.height/2)) && 
 | 
			
		||||
                    isWalkable(getTileAt(this.x, newY + this.height/2))) {
 | 
			
		||||
                    this.y = newY;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Keep player in map bounds
 | 
			
		||||
                this.x = Math.max(this.width/2, Math.min(game.mapWidth * game.tileSize - this.width/2, this.x));
 | 
			
		||||
                this.y = Math.max(this.height/2, Math.min(game.mapHeight * game.tileSize - this.height/2, this.y));
 | 
			
		||||
                
 | 
			
		||||
                // Shooting
 | 
			
		||||
                const now = Date.now();
 | 
			
		||||
                if (this.burstCount > 0 && now - this.burstTimer > this.weapon.fireRate) {
 | 
			
		||||
                    this.shoot();
 | 
			
		||||
                    this.burstCount--;
 | 
			
		||||
                    this.burstTimer = now;
 | 
			
		||||
                } else if ((game.mouse.down && this.weapon.autoFire) || this.burstCount > 0) {
 | 
			
		||||
                    if (now - this.lastShot > this.weapon.fireRate) {
 | 
			
		||||
                        if (this.burstCount === 0) {
 | 
			
		||||
                            this.burstCount = this.weapon.burstCount;
 | 
			
		||||
                            this.burstTimer = now;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Check weapon pickups
 | 
			
		||||
                game.weaponDrops.forEach((drop, index) => {
 | 
			
		||||
                    const dx = this.x - drop.x;
 | 
			
		||||
                    const dy = this.y - drop.y;
 | 
			
		||||
                    if (Math.sqrt(dx * dx + dy * dy) < 30) {
 | 
			
		||||
                        this.weapon = { ...drop.weapon };
 | 
			
		||||
                        game.weaponDrops.splice(index, 1);
 | 
			
		||||
                        updateUI();
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            shoot() {
 | 
			
		||||
                if (this.weapon.ammo <= 0) {
 | 
			
		||||
                    if (this.weapon.name !== 'Pistol') {
 | 
			
		||||
                        this.weapon = { ...weaponTypes.pistol };
 | 
			
		||||
                        updateUI();
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                const dx = game.mouse.x - this.x;
 | 
			
		||||
                const dy = game.mouse.y - this.y;
 | 
			
		||||
                const angle = Math.atan2(dy, dx);
 | 
			
		||||
                
 | 
			
		||||
                for (let i = 0; i < this.weapon.bulletsPerShot; i++) {
 | 
			
		||||
                    const spread = (Math.random() - 0.5) * this.weapon.spread;
 | 
			
		||||
                    const bulletAngle = angle + spread;
 | 
			
		||||
                    
 | 
			
		||||
                    game.bullets.push(new Bullet(
 | 
			
		||||
                        this.x, this.y, bulletAngle, this.weapon.damage, this.weapon.range
 | 
			
		||||
                    ));
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (this.weapon.ammo !== Infinity) {
 | 
			
		||||
                    this.weapon.ammo--;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                this.lastShot = Date.now();
 | 
			
		||||
                updateUI();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            draw() {
 | 
			
		||||
                ctx.drawImage(sprites['main-character.png'], 
 | 
			
		||||
                    this.x - this.width/2 + game.camera.x, this.y - this.height/2 + game.camera.y, this.width, this.height);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        class Zombie {
 | 
			
		||||
            constructor(x, y) {
 | 
			
		||||
                this.x = x;
 | 
			
		||||
                this.y = y;
 | 
			
		||||
                this.width = 32;
 | 
			
		||||
                this.height = 32;
 | 
			
		||||
                this.speed = 1 + Math.random() * 0.5;
 | 
			
		||||
                this.hp = 50 + Math.random() * 50;
 | 
			
		||||
                this.maxHp = this.hp;
 | 
			
		||||
                this.sprite = ['zombie.png', 'zombie2.png', 'zombie3.png', 'zombie4.png'][Math.floor(Math.random() * 4)];
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            update() {
 | 
			
		||||
                // Move towards player with collision detection
 | 
			
		||||
                const dx = game.player.x - this.x;
 | 
			
		||||
                const dy = game.player.y - this.y;
 | 
			
		||||
                const distance = Math.sqrt(dx * dx + dy * dy);
 | 
			
		||||
                
 | 
			
		||||
                if (distance > 0) {
 | 
			
		||||
                    let newX = this.x + (dx / distance) * this.speed;
 | 
			
		||||
                    let newY = this.y + (dy / distance) * this.speed;
 | 
			
		||||
                    
 | 
			
		||||
                    // Check collision for X movement
 | 
			
		||||
                    if (isWalkable(getTileAt(newX - this.width/2, this.y)) && 
 | 
			
		||||
                        isWalkable(getTileAt(newX + this.width/2, this.y))) {
 | 
			
		||||
                        this.x = newX;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    // Check collision for Y movement
 | 
			
		||||
                    if (isWalkable(getTileAt(this.x, newY - this.height/2)) && 
 | 
			
		||||
                        isWalkable(getTileAt(this.x, newY + this.height/2))) {
 | 
			
		||||
                        this.y = newY;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            takeDamage(damage) {
 | 
			
		||||
                this.hp -= damage;
 | 
			
		||||
                return this.hp <= 0;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            draw() {
 | 
			
		||||
                const screenX = this.x + game.camera.x;
 | 
			
		||||
                const screenY = this.y + game.camera.y;
 | 
			
		||||
                
 | 
			
		||||
                ctx.drawImage(sprites[this.sprite], 
 | 
			
		||||
                    screenX - this.width/2, screenY - this.height/2, this.width, this.height);
 | 
			
		||||
                    
 | 
			
		||||
                // Enhanced health bar
 | 
			
		||||
                const barWidth = this.width + 4;
 | 
			
		||||
                const barHeight = 6;
 | 
			
		||||
                const healthPercent = this.hp / this.maxHp;
 | 
			
		||||
                const barX = screenX - barWidth/2;
 | 
			
		||||
                const barY = screenY - this.height/2 - 12;
 | 
			
		||||
                
 | 
			
		||||
                // Health bar background (dark border)
 | 
			
		||||
                ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
 | 
			
		||||
                ctx.fillRect(barX - 1, barY - 1, barWidth + 2, barHeight + 2);
 | 
			
		||||
                
 | 
			
		||||
                // Health bar background (red)
 | 
			
		||||
                ctx.fillStyle = '#330000';
 | 
			
		||||
                ctx.fillRect(barX, barY, barWidth, barHeight);
 | 
			
		||||
                
 | 
			
		||||
                // Health bar foreground with gradient effect
 | 
			
		||||
                const gradient = ctx.createLinearGradient(barX, barY, barX, barY + barHeight);
 | 
			
		||||
                if (healthPercent > 0.6) {
 | 
			
		||||
                    gradient.addColorStop(0, '#00ff44');
 | 
			
		||||
                    gradient.addColorStop(1, '#00cc33');
 | 
			
		||||
                } else if (healthPercent > 0.3) {
 | 
			
		||||
                    gradient.addColorStop(0, '#ffaa00');
 | 
			
		||||
                    gradient.addColorStop(1, '#ff8800');
 | 
			
		||||
                } else {
 | 
			
		||||
                    gradient.addColorStop(0, '#ff4444');
 | 
			
		||||
                    gradient.addColorStop(1, '#cc0000');
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                ctx.fillStyle = gradient;
 | 
			
		||||
                ctx.fillRect(barX, barY, barWidth * healthPercent, barHeight);
 | 
			
		||||
                
 | 
			
		||||
                // Health bar highlight
 | 
			
		||||
                ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
 | 
			
		||||
                ctx.fillRect(barX, barY, barWidth * healthPercent, 2);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        class Bullet {
 | 
			
		||||
            constructor(x, y, angle, damage, range) {
 | 
			
		||||
                this.x = x;
 | 
			
		||||
                this.y = y;
 | 
			
		||||
                this.startX = x;
 | 
			
		||||
                this.startY = y;
 | 
			
		||||
                this.vx = Math.cos(angle) * 8;
 | 
			
		||||
                this.vy = Math.sin(angle) * 8;
 | 
			
		||||
                this.damage = damage;
 | 
			
		||||
                this.range = range;
 | 
			
		||||
                this.width = 4;
 | 
			
		||||
                this.height = 4;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            update() {
 | 
			
		||||
                this.x += this.vx;
 | 
			
		||||
                this.y += this.vy;
 | 
			
		||||
                
 | 
			
		||||
                // Check range
 | 
			
		||||
                const dx = this.x - this.startX;
 | 
			
		||||
                const dy = this.y - this.startY;
 | 
			
		||||
                if (Math.sqrt(dx * dx + dy * dy) > this.range) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Check bounds
 | 
			
		||||
                if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            draw() {
 | 
			
		||||
                // Enhanced bullet with glow effect
 | 
			
		||||
                ctx.shadowBlur = 10;
 | 
			
		||||
                ctx.shadowColor = '#ffff00';
 | 
			
		||||
                ctx.fillStyle = '#ffff44';
 | 
			
		||||
                ctx.fillRect(this.x - 2 + game.camera.x, this.y - 2 + game.camera.y, 4, 4);
 | 
			
		||||
                
 | 
			
		||||
                // Reset shadow
 | 
			
		||||
                ctx.shadowBlur = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        class WeaponDrop {
 | 
			
		||||
            constructor(x, y, weaponType) {
 | 
			
		||||
                this.x = x;
 | 
			
		||||
                this.y = y;
 | 
			
		||||
                this.weapon = { ...weaponTypes[weaponType] };
 | 
			
		||||
                this.sprite = this.weapon.sprite;
 | 
			
		||||
                this.width = 24;
 | 
			
		||||
                this.height = 24;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            draw() {
 | 
			
		||||
                // Weapon drop with pulsing glow effect
 | 
			
		||||
                const time = Date.now() * 0.005;
 | 
			
		||||
                const glowIntensity = (Math.sin(time) + 1) * 0.5;
 | 
			
		||||
                
 | 
			
		||||
                ctx.shadowBlur = 15 + glowIntensity * 10;
 | 
			
		||||
                ctx.shadowColor = '#00aaff';
 | 
			
		||||
                ctx.drawImage(sprites[this.sprite], 
 | 
			
		||||
                    this.x - this.width/2 + game.camera.x, this.y - this.height/2 + game.camera.y, this.width, this.height);
 | 
			
		||||
                
 | 
			
		||||
                // Reset shadow
 | 
			
		||||
                ctx.shadowBlur = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function spawnZombie() {
 | 
			
		||||
            const side = Math.floor(Math.random() * 4);
 | 
			
		||||
            let x, y;
 | 
			
		||||
            const mapPixelWidth = game.mapWidth * game.tileSize;
 | 
			
		||||
            const mapPixelHeight = game.mapHeight * game.tileSize;
 | 
			
		||||
            
 | 
			
		||||
            switch(side) {
 | 
			
		||||
                case 0: // Top
 | 
			
		||||
                    x = Math.random() * mapPixelWidth;
 | 
			
		||||
                    y = -32;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1: // Right
 | 
			
		||||
                    x = mapPixelWidth + 32;
 | 
			
		||||
                    y = Math.random() * mapPixelHeight;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2: // Bottom
 | 
			
		||||
                    x = Math.random() * mapPixelWidth;
 | 
			
		||||
                    y = mapPixelHeight + 32;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3: // Left
 | 
			
		||||
                    x = -32;
 | 
			
		||||
                    y = Math.random() * mapPixelHeight;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            game.zombies.push(new Zombie(x, y));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function checkCollisions() {
 | 
			
		||||
            // Bullet-zombie collisions
 | 
			
		||||
            for (let i = game.bullets.length - 1; i >= 0; i--) {
 | 
			
		||||
                const bullet = game.bullets[i];
 | 
			
		||||
                
 | 
			
		||||
                for (let j = game.zombies.length - 1; j >= 0; j--) {
 | 
			
		||||
                    const zombie = game.zombies[j];
 | 
			
		||||
                    
 | 
			
		||||
                    const dx = bullet.x - zombie.x;
 | 
			
		||||
                    const dy = bullet.y - zombie.y;
 | 
			
		||||
                    
 | 
			
		||||
                    if (Math.abs(dx) < zombie.width/2 && Math.abs(dy) < zombie.height/2) {
 | 
			
		||||
                        if (zombie.takeDamage(bullet.damage)) {
 | 
			
		||||
                            // Zombie died
 | 
			
		||||
                            game.score += 10;
 | 
			
		||||
                            
 | 
			
		||||
                            // Random weapon drop (increased rate)
 | 
			
		||||
                            if (Math.random() < 0.4) {
 | 
			
		||||
                                const weaponKeys = Object.keys(weaponTypes);
 | 
			
		||||
                                const randomWeapon = weaponKeys[Math.floor(Math.random() * weaponKeys.length)];
 | 
			
		||||
                                if (randomWeapon !== 'pistol') {
 | 
			
		||||
                                    game.weaponDrops.push(new WeaponDrop(zombie.x, zombie.y, randomWeapon));
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            game.zombies.splice(j, 1);
 | 
			
		||||
                        }
 | 
			
		||||
                        game.bullets.splice(i, 1);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Player-zombie collisions
 | 
			
		||||
            const now = Date.now();
 | 
			
		||||
            for (let i = game.zombies.length - 1; i >= 0; i--) {
 | 
			
		||||
                const zombie = game.zombies[i];
 | 
			
		||||
                const dx = game.player.x - zombie.x;
 | 
			
		||||
                const dy = game.player.y - zombie.y;
 | 
			
		||||
                const distance = Math.sqrt(dx * dx + dy * dy);
 | 
			
		||||
                
 | 
			
		||||
                if (distance < (game.player.width + zombie.width) / 2) {
 | 
			
		||||
                    // Damage player (once per second per zombie)
 | 
			
		||||
                    if (now - game.player.lastDamage > 1000) {
 | 
			
		||||
                        game.player.health -= 10;
 | 
			
		||||
                        game.player.lastDamage = now;
 | 
			
		||||
                        updateUI();
 | 
			
		||||
                        
 | 
			
		||||
                        if (game.player.health <= 0) {
 | 
			
		||||
                            // Game over - restart
 | 
			
		||||
                            game.player.health = game.player.maxHealth;
 | 
			
		||||
                            game.player.x = canvas.width / 2;
 | 
			
		||||
                            game.player.y = canvas.height / 2;
 | 
			
		||||
                            game.zombies = [];
 | 
			
		||||
                            game.bullets = [];
 | 
			
		||||
                            game.weaponDrops = [];
 | 
			
		||||
                            game.score = 0;
 | 
			
		||||
                            updateUI();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateUI() {
 | 
			
		||||
            document.getElementById('weaponName').textContent = game.player.weapon.name;
 | 
			
		||||
            document.getElementById('ammoCount').textContent = 
 | 
			
		||||
                game.player.weapon.ammo === Infinity ? '∞' : game.player.weapon.ammo;
 | 
			
		||||
            document.getElementById('health').textContent = game.player.health;
 | 
			
		||||
            document.getElementById('score').textContent = game.score;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function drawMap() {
 | 
			
		||||
            // Pre-rendered tile canvases for performance
 | 
			
		||||
            if (!game.tileCanvases) {
 | 
			
		||||
                game.tileCanvases = {};
 | 
			
		||||
                Object.values(TILE_TYPES).forEach(type => {
 | 
			
		||||
                    const tileCanvas = document.createElement('canvas');
 | 
			
		||||
                    tileCanvas.width = game.tileSize;
 | 
			
		||||
                    tileCanvas.height = game.tileSize;
 | 
			
		||||
                    const tileCtx = tileCanvas.getContext('2d');
 | 
			
		||||
                    
 | 
			
		||||
                    // Draw tile directly to canvas
 | 
			
		||||
                    switch(type) {
 | 
			
		||||
                        case TILE_TYPES.FLOOR:
 | 
			
		||||
                            tileCtx.fillStyle = '#4a4a4a';
 | 
			
		||||
                            tileCtx.fillRect(0, 0, game.tileSize, game.tileSize);
 | 
			
		||||
                            tileCtx.fillStyle = '#525252';
 | 
			
		||||
                            tileCtx.fillRect(0, 0, 16, 16);
 | 
			
		||||
                            tileCtx.fillRect(16, 16, 16, 16);
 | 
			
		||||
                            tileCtx.fillStyle = '#3a3a3a';
 | 
			
		||||
                            tileCtx.fillRect(2, 2, 2, 2);
 | 
			
		||||
                            tileCtx.fillRect(28, 6, 2, 2);
 | 
			
		||||
                            tileCtx.fillRect(8, 24, 2, 2);
 | 
			
		||||
                            tileCtx.fillRect(22, 28, 2, 2);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case TILE_TYPES.WALL:
 | 
			
		||||
                            tileCtx.fillStyle = '#8B4513';
 | 
			
		||||
                            tileCtx.fillRect(0, 0, game.tileSize, game.tileSize);
 | 
			
		||||
                            tileCtx.fillStyle = '#A0522D';
 | 
			
		||||
                            tileCtx.strokeStyle = '#654321';
 | 
			
		||||
                            tileCtx.lineWidth = 1;
 | 
			
		||||
                            for (let row = 0; row < 4; row++) {
 | 
			
		||||
                                for (let col = 0; col < 2; col++) {
 | 
			
		||||
                                    let x = col * 16 + (row % 2) * 8;
 | 
			
		||||
                                    let y = row * 8;
 | 
			
		||||
                                    if (x + 16 <= game.tileSize) {
 | 
			
		||||
                                        tileCtx.fillRect(x, y, 16, 8);
 | 
			
		||||
                                        tileCtx.strokeRect(x, y, 16, 8);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
                        case TILE_TYPES.BUILDING:
 | 
			
		||||
                            tileCtx.fillStyle = '#2F4F4F';
 | 
			
		||||
                            tileCtx.fillRect(0, 0, game.tileSize, game.tileSize);
 | 
			
		||||
                            tileCtx.fillStyle = '#708090';
 | 
			
		||||
                            tileCtx.fillRect(2, 2, game.tileSize-4, game.tileSize-4);
 | 
			
		||||
                            tileCtx.fillStyle = '#4682B4';
 | 
			
		||||
                            tileCtx.fillRect(6, 6, 8, 8);
 | 
			
		||||
                            tileCtx.fillRect(18, 6, 8, 8);
 | 
			
		||||
                            tileCtx.fillRect(6, 18, 8, 8);
 | 
			
		||||
                            tileCtx.fillRect(18, 18, 8, 8);
 | 
			
		||||
                            tileCtx.fillStyle = '#87CEEB';
 | 
			
		||||
                            [[7,7], [11,7], [19,7], [23,7], [7,19], [11,19], [19,19], [23,19]].forEach(([x,y]) => {
 | 
			
		||||
                                tileCtx.fillRect(x, y, 2, 2);
 | 
			
		||||
                            });
 | 
			
		||||
                            break;
 | 
			
		||||
                        case TILE_TYPES.ROAD:
 | 
			
		||||
                            tileCtx.fillStyle = '#2F2F2F';
 | 
			
		||||
                            tileCtx.fillRect(0, 0, game.tileSize, game.tileSize);
 | 
			
		||||
                            tileCtx.fillStyle = '#FFFF00';
 | 
			
		||||
                            tileCtx.fillRect(0, 14, game.tileSize, 4);
 | 
			
		||||
                            tileCtx.fillStyle = '#1F1F1F';
 | 
			
		||||
                            [[4,4], [26,8], [12,22], [20,26]].forEach(([x,y]) => {
 | 
			
		||||
                                tileCtx.fillRect(x, y, 2, 2);
 | 
			
		||||
                            });
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    game.tileCanvases[type] = tileCanvas;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Draw visible tiles
 | 
			
		||||
            const startX = Math.max(0, Math.floor(-game.camera.x / game.tileSize));
 | 
			
		||||
            const endX = Math.min(game.mapWidth, Math.ceil((canvas.width - game.camera.x) / game.tileSize));
 | 
			
		||||
            const startY = Math.max(0, Math.floor(-game.camera.y / game.tileSize));
 | 
			
		||||
            const endY = Math.min(game.mapHeight, Math.ceil((canvas.height - game.camera.y) / game.tileSize));
 | 
			
		||||
            
 | 
			
		||||
            for (let y = startY; y < endY; y++) {
 | 
			
		||||
                for (let x = startX; x < endX; x++) {
 | 
			
		||||
                    const tileType = game.map[y][x];
 | 
			
		||||
                    const screenX = x * game.tileSize + game.camera.x;
 | 
			
		||||
                    const screenY = y * game.tileSize + game.camera.y;
 | 
			
		||||
                    ctx.drawImage(game.tileCanvases[tileType], screenX, screenY);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function gameLoop() {
 | 
			
		||||
            // Clear canvas
 | 
			
		||||
            ctx.clearRect(0, 0, canvas.width, canvas.height);
 | 
			
		||||
            
 | 
			
		||||
            // Update camera to follow player
 | 
			
		||||
            game.camera.x = canvas.width / 2 - game.player.x;
 | 
			
		||||
            game.camera.y = canvas.height / 2 - game.player.y;
 | 
			
		||||
            
 | 
			
		||||
            // Draw map
 | 
			
		||||
            drawMap();
 | 
			
		||||
            
 | 
			
		||||
            // Update
 | 
			
		||||
            game.player.update();
 | 
			
		||||
            
 | 
			
		||||
            game.zombies.forEach(zombie => zombie.update());
 | 
			
		||||
            
 | 
			
		||||
            game.bullets = game.bullets.filter(bullet => bullet.update());
 | 
			
		||||
            
 | 
			
		||||
            checkCollisions();
 | 
			
		||||
            
 | 
			
		||||
            // Spawn zombies (reduced spawn rate)
 | 
			
		||||
            if (Math.random() < 0.01 + game.score * 0.00005) {
 | 
			
		||||
                spawnZombie();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Draw
 | 
			
		||||
            game.zombies.forEach(zombie => zombie.draw());
 | 
			
		||||
            game.bullets.forEach(bullet => bullet.draw());
 | 
			
		||||
            game.weaponDrops.forEach(drop => drop.draw());
 | 
			
		||||
            game.player.draw();
 | 
			
		||||
            
 | 
			
		||||
            requestAnimationFrame(gameLoop);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function initGame() {
 | 
			
		||||
            // Generate the map
 | 
			
		||||
            game.map = generateMap();
 | 
			
		||||
            
 | 
			
		||||
            // Place player at center of map
 | 
			
		||||
            const centerX = Math.floor(game.mapWidth / 2) * game.tileSize;
 | 
			
		||||
            const centerY = Math.floor(game.mapHeight / 2) * game.tileSize;
 | 
			
		||||
            game.player = new Player(centerX, centerY);
 | 
			
		||||
            
 | 
			
		||||
            // Spawn initial zombies at map edges
 | 
			
		||||
            for (let i = 0; i < 5; i++) {
 | 
			
		||||
                spawnZombie();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            updateUI();
 | 
			
		||||
            gameLoop();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Event listeners
 | 
			
		||||
        document.addEventListener('keydown', (e) => {
 | 
			
		||||
            game.keys[e.key] = true;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        document.addEventListener('keyup', (e) => {
 | 
			
		||||
            game.keys[e.key] = false;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        canvas.addEventListener('mousemove', (e) => {
 | 
			
		||||
            const rect = canvas.getBoundingClientRect();
 | 
			
		||||
            game.mouse.x = e.clientX - rect.left - game.camera.x;
 | 
			
		||||
            game.mouse.y = e.clientY - rect.top - game.camera.y;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        canvas.addEventListener('mousedown', (e) => {
 | 
			
		||||
            game.mouse.down = true;
 | 
			
		||||
            if (!game.player.weapon.autoFire) {
 | 
			
		||||
                game.player.burstCount = game.player.weapon.burstCount;
 | 
			
		||||
                game.player.burstTimer = Date.now();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        canvas.addEventListener('mouseup', (e) => {
 | 
			
		||||
            game.mouse.down = false;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        // Start loading sprites
 | 
			
		||||
        loadSprites();
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user