0% found this document useful (0 votes)
59 views18 pages

Advanced Top-Down Shooter Game Code

The document outlines a Python script for an advanced top-down shooter game using Pygame, featuring multiple levels, various enemy types, and weapon options. It includes mechanics for player movement, shooting, enemy behaviors, power-ups, and score tracking. The game is designed to be played without external assets, relying solely on shapes and colors.

Uploaded by

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

Advanced Top-Down Shooter Game Code

The document outlines a Python script for an advanced top-down shooter game using Pygame, featuring multiple levels, various enemy types, and weapon options. It includes mechanics for player movement, shooting, enemy behaviors, power-ups, and score tracking. The game is designed to be played without external assets, relying solely on shapes and colors.

Uploaded by

aukshay09
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

SAMPLE CODE :

# top_down_shooter_advanced.py

"""

Top-Down Shooter — Advanced (Pygame)

Features:

- Multiple levels with waves

- Boss every N levels with patterns

- Enemy behaviours: seeker, zigzag, ranged

- Weapons: single, spread, rapid-fire (switch with Q)

- Powerups (health, weapon upgrade)

- Persistent high-score saved to [Link]

- No external assets required (shapes only)

Author: ChatGPT (for Griesh)

"""

import pygame

import random

import math

import sys

import json

import os

from collections import deque

# ---------------- CONFIG ----------------

WIDTH, HEIGHT = 900, 650

FPS = 60

PLAYER_COLOR = (50, 200, 255)

PLAYER_RADIUS = 16

PLAYER_SPEED = 4.2

PLAYER_MAX_HEALTH = 6
BULLET_COLOR = (255, 220, 80)

BULLET_SPEED = 12

BULLET_RADIUS = 4

BULLET_COOLDOWN = 160 # base ms between shots (modified by weapon)

ENEMY_COLOR = (220, 80, 80)

ENEMY_RADIUS = 14

ENEMY_BASE_SPEED = 1.2

POWERUP_COLOR = (80, 220, 120)

POWERUP_RADIUS = 10

SCORES_FILE = "[Link]"

MAX_SCORES = 10

# Level/wave config

WAVES_PER_LEVEL = 4

ENEMIES_BASE_PER_WAVE = 5

BOSS_EVERY = 3 # boss appears every 3 levels

# Weapons config

WEAPONS = ["Single", "Spread", "Rapid"]

WEAPON_SETTINGS = {

"Single": {"cooldown": 160, "bullets": 1, "spread_deg": 0},

"Spread": {"cooldown": 380, "bullets": 5, "spread_deg": 40},

"Rapid": {"cooldown": 80, "bullets": 1, "spread_deg": 0},

# UI

FONT_NAME = None

# ----------------------------------------

[Link]()

screen = [Link].set_mode((WIDTH, HEIGHT))


[Link].set_caption("Top-Down Shooter — Advanced")

clock = [Link]()

font = [Link](FONT_NAME, 20)

big_font = [Link](FONT_NAME, 48)

# ---------------- Helpers ----------------

def clamp(v, a, b):

return max(a, min(b, v))

def dist(a, b):

return [Link](a[0]-b[0], a[1]-b[1])

def normalize(dx, dy):

d = [Link](dx, dy)

if d == 0:

return 0,0

return dx/d, dy/d

def load_scores():

if not [Link](SCORES_FILE):

return []

try:

with open(SCORES_FILE, "r") as f:

return [Link](f)

except Exception:

return []

def save_scores(scores):

scores = sorted(scores, key=lambda e: (-e["score"], e["time"]))[:MAX_SCORES]

with open(SCORES_FILE, "w") as f:

[Link](scores, f, indent=2)

def add_score(name, score, time_seconds):

s = load_scores()
[Link]({"name": name, "score": score, "time": time_seconds, "date": [Link].get_ticks()})

save_scores(s)

# --------------- Game classes ---------------

class Player:

def __init__(self, x, y):

self.x = x; self.y = y

[Link] = PLAYER_RADIUS

[Link] = PLAYER_SPEED

self.max_health = PLAYER_MAX_HEALTH

[Link] = self.max_health

self.last_shot = 0

self.auto_fire = False

self.weapon_index = 0 # index in WEAPONS

@property

def weapon(self):

return WEAPONS[self.weapon_index]

def switch_weapon(self):

self.weapon_index = (self.weapon_index + 1) % len(WEAPONS)

def can_shoot(self):

w = [Link]

cooldown = WEAPON_SETTINGS[w]["cooldown"]

return [Link].get_ticks() - self.last_shot >= cooldown

def shoot(self, target_pos):

if not self.can_shoot():

return []

self.last_shot = [Link].get_ticks()

w = [Link]

cfg = WEAPON_SETTINGS[w]

bullets = []
dx = target_pos[0] - self.x

dy = target_pos[1] - self.y

base_angle = [Link](math.atan2(dy, dx))

count = cfg["bullets"]

spread = cfg["spread_deg"]

if count == 1:

angle = [Link](base_angle)

nx, ny = [Link](angle), [Link](angle)

[Link](Bullet(self.x + nx*([Link]+6), self.y + ny*([Link]+6), nx*BULLET_SPEED,


ny*BULLET_SPEED))

else:

# spread centered at base_angle

start = base_angle - spread/2

for i in range(count):

ang = [Link](start + (spread/(count-1))*i)

nx, ny = [Link](ang), [Link](ang)

[Link](Bullet(self.x + nx*([Link]+6), self.y + ny*([Link]+6), nx*BULLET_SPEED,


ny*BULLET_SPEED))

return bullets

def move(self, keys):

dx = dy = 0

if keys[pygame.K_w] or keys[pygame.K_UP]:

dy -= 1

if keys[pygame.K_s] or keys[pygame.K_DOWN]:

dy += 1

if keys[pygame.K_a] or keys[pygame.K_LEFT]:

dx -= 1

if keys[pygame.K_d] or keys[pygame.K_RIGHT]:

dx += 1

if dx != 0 or dy != 0:

nx, ny = normalize(dx, dy)

self.x += nx * [Link]

self.y += ny * [Link]

# clamp
self.x = clamp(self.x, [Link], WIDTH - [Link])

self.y = clamp(self.y, [Link], HEIGHT - [Link])

def draw(self, surf):

[Link](surf, PLAYER_COLOR, (int(self.x), int(self.y)), [Link])

# health bar

for i in range(self.max_health):

hx = 10 + i*20

rect = (hx, 10, 16, 12)

if i < [Link]:

[Link](surf, (200,30,30), rect)

else:

[Link](surf, (60,60,60), rect, 2)

# weapon label

[Link]([Link](f"Weapon: {[Link]}", True, (230,230,230)), (10, 30))

class Bullet:

def __init__(self, x, y, vx, vy, owner="player"):

self.x = x; self.y = y

[Link] = vx; [Link] = vy

[Link] = BULLET_RADIUS

[Link] = False

[Link] = owner

[Link] = 1 if owner == "player" else 1

def update(self):

self.x += [Link]

self.y += [Link]

if self.x < -30 or self.x > WIDTH + 30 or self.y < -30 or self.y > HEIGHT + 30:

[Link] = True

def draw(self, surf):

[Link](surf, BULLET_COLOR, (int(self.x), int(self.y)), [Link])


class Enemy:

"""

behaviors:

- seeker: always move toward player

- zigzag: move toward player but with oscillation

- ranged: keeps distance and shoots at player

- boss: big, multiple attacks & phases

"""

def __init__(self, x, y, kind="seeker", level=1):

self.x = x; self.y = y

[Link] = kind

[Link] = level

[Link] = ENEMY_BASE_SPEED + 0.08*level

[Link] = ENEMY_RADIUS + (0 if kind!="boss" else 10)

# HP depends on kind

base_hp = {"seeker":1, "zigzag":1, "ranged":1, "boss":10 + level*3}

[Link] = base_hp.get(kind, 1)

[Link] = False

self.last_shot = 0

self.shoot_interval = max(700 - level*20, 400) # for ranged

# zigzag params

self.zig_t = [Link]()*1000

self.zig_amp = 40 + level*2

self.zig_freq = 0.02 + level*0.005

def update(self, player, bullets):

if [Link] == "seeker":

dx = player.x - self.x; dy = player.y - self.y

nx, ny = normalize(dx, dy)

self.x += nx * [Link]

self.y += ny * [Link]

elif [Link] == "zigzag":

dx = player.x - self.x; dy = player.y - self.y

nx, ny = normalize(dx, dy)


# perpendicular oscillation

perp_x, perp_y = -ny, nx

t = self.zig_t

osc = [Link](t * self.zig_freq) * (self.zig_amp/(1 + [Link]*0.1))

self.x += nx * [Link] + perp_x * osc * 0.01

self.y += ny * [Link] + perp_y * osc * 0.01

self.zig_t += 1

elif [Link] == "ranged":

# try to maintain some distance

dx = player.x - self.x; dy = player.y - self.y

d = [Link](dx, dy)

if d > 260:

nx, ny = normalize(dx, dy)

self.x += nx * [Link]

self.y += ny * [Link]

elif d < 180:

nx, ny = normalize(dx, dy)

self.x -= nx * [Link] # back off

self.y -= ny * [Link]

# shoot if possible

now = [Link].get_ticks()

if now - self.last_shot >= self.shoot_interval:

self.last_shot = now

# shoot a bullet toward player

nx, ny = normalize(dx, dy)

bx = self.x + nx*([Link]+6); by = self.y + ny*([Link]+6)

[Link](Bullet(bx, by, nx*6, ny*6, owner="enemy"))

elif [Link] == "boss":

# more complex boss: moves slowly, large HP; occasionally fires many shots

dx = player.x - self.x; dy = player.y - self.y

nx, ny = normalize(dx, dy)

# slow chase plus small random motion

self.x += nx * ([Link]*0.4) + [Link](-0.8,0.8)

self.y += ny * ([Link]*0.4) + [Link](-0.8,0.8)


# boss attacks: bursts + radial

now = [Link].get_ticks()

if now % 3500 < 60: # radial burst occasionally

for a_deg in range(0,360,30):

a = [Link](a_deg + [Link](-6,6))

[Link](Bullet(self.x + [Link](a)*([Link]+6), self.y + [Link](a)*([Link]+6),

[Link](a)*5, [Link](a)*5, owner="enemy"))

if now - self.last_shot >= 900:

self.last_shot = now

# aimed triple shot

dx = player.x - self.x; dy = player.y - self.y

base = [Link](math.atan2(dy, dx))

for deg in (-8, 0, 8):

ang = [Link](base + deg)

nx, ny = [Link](ang), [Link](ang)

[Link](Bullet(self.x + nx*([Link]+6), self.y + ny*([Link]+6), nx*6, ny*6,


owner="enemy"))

def draw(self, surf):

col = ENEMY_COLOR if [Link] != "boss" else (200, 80, 200)

[Link](surf, col, (int(self.x), int(self.y)), [Link])

# small HP bar for boss

if [Link] == "boss":

w = 80

pct = clamp([Link] / (10 + [Link]*3), 0, 1)

[Link](surf, (60,60,60), (int(self.x - w/2), int(self.y - [Link] - 12), w, 8))

[Link](surf, (200,40,40), (int(self.x - w/2), int(self.y - [Link] - 12), int(w*pct), 8))

class Powerup:

def __init__(self, x, y, kind="health"):

self.x = x; self.y = y

[Link] = kind # 'health' or 'weapon'

[Link] = POWERUP_RADIUS

[Link] = False
self.spawn_time = [Link].get_ticks()

def draw(self, surf):

if [Link] == "health":

[Link](surf, POWERUP_COLOR, (int(self.x)-8, int(self.y)-8, 16, 16))

[Link](surf, (255,255,255), (self.x-3, self.y), (self.x+3, self.y), 2)

[Link](surf, (255,255,255), (self.x, self.y-3), (self.x, self.y+3), 2)

else:

# weapon

[Link](surf, (255,200,60), (int(self.x), int(self.y)), 10)

[Link]([Link]("W", True, (20,20,20)), (int(self.x)-6, int(self.y)-8))

# --------------- Game flow & spawn ---------------

def spawn_enemy(level):

kind = [Link](["seeker","zigzag","ranged"], weights=[0.5,0.25,0.25])[0]

side = [Link](["top","bottom","left","right"])

if side == "top":

x = [Link](0, WIDTH); y = -20

elif side == "bottom":

x = [Link](0, WIDTH); y = HEIGHT + 20

elif side == "left":

x = -20; y = [Link](0, HEIGHT)

else:

x = WIDTH + 20; y = [Link](0, HEIGHT)

return Enemy(x, y, kind=kind, level=level)

def spawn_boss(level):

# boss spawn at random near edge

x = WIDTH//2 + [Link](-100,100)

y = -120

return Enemy(x, y, kind="boss", level=level)

# ---------------- Main game ----------------

def draw_text_center(surf, text, y, size=36, color=(240,240,240)):


f = [Link](FONT_NAME, size)

[Link]([Link](text, True, color), [Link](text, True, color).get_rect(center=(WIDTH//2, y)))

def main_game():

player = Player(WIDTH//2, HEIGHT//2)

bullets = []

enemies = []

powerups = []

score = 0

level = 1

wave = 1

spawn_timer = 0

enemies_spawned_this_wave = 0

enemies_to_spawn = ENEMIES_BASE_PER_WAVE + (level-1)*2

wave_in_progress = True

game_over = False

start_time = [Link].get_ticks()

while True:

dt = [Link](FPS)

now = [Link].get_ticks()

for event in [Link]():

if [Link] == [Link]:

[Link](); [Link]()

if [Link] == [Link]:

if [Link] == pygame.K_ESCAPE:

return ("menu", None)

if [Link] == pygame.K_SPACE:

player.auto_fire = not player.auto_fire

if [Link] == pygame.K_q:

player.switch_weapon()

if [Link] == pygame.K_r and game_over:

return ("restart", None)

if [Link] == [Link]:
if [Link] == 1 and not game_over:

new = [Link]([Link].get_pos())

[Link](new)

keys = [Link].get_pressed()

if not game_over:

[Link](keys)

# auto fire

if player.auto_fire:

new = [Link]([Link].get_pos())

[Link](new)

# spawn logic

if BOSS_EVERY and level % BOSS_EVERY == 0 and wave == WAVES_PER_LEVEL + 1 and not


any([Link] == "boss" for e in enemies):

# spawn boss

[Link](spawn_boss(level))

wave_in_progress = True

else:

# normal waves

spawn_interval = max(280, 1000 - level*40)

if enemies_spawned_this_wave < enemies_to_spawn and now - spawn_timer > spawn_interval:

[Link](spawn_enemy(level))

enemies_spawned_this_wave += 1

spawn_timer = now

# update bullets

for b in bullets:

[Link]()

bullets = [b for b in bullets if not [Link]]

# update enemies

for e in enemies:

[Link](player, bullets)
# collisions: bullets vs enemies

for b in bullets:

if [Link] == "player":

for e in enemies:

if not [Link] and dist((b.x,b.y),(e.x,e.y)) < [Link] + [Link]:

[Link] -= [Link]

[Link] = True

if [Link] <= 0:

[Link] = True

# score depends on kind

score += 10 if [Link] != "boss" else 200 + level*30

# chance to drop powerup

if [Link]() < 0.18:

kind = "health" if [Link]() < 0.6 else "weapon"

[Link](Powerup(e.x, e.y, kind=kind))

enemies = [e for e in enemies if not [Link]]

# bullets from enemy hitting player

for b in bullets:

if [Link] == "enemy" and dist((b.x,b.y),(player.x, player.y)) < [Link] + [Link]:

[Link] = True

[Link] -= 1

if [Link] <= 0:

game_over = True

end_time = [Link].get_ticks()

total_time = (end_time - start_time) // 1000

# enemies colliding melee with player

for e in enemies:

if dist((e.x,e.y),(player.x,player.y)) < [Link] + [Link] - 6:

# damage player and destroy enemy (or hurt boss)

[Link] -= 1

if [Link] != "boss":
[Link] = True

score += 5

else:

[Link] -= 2

if [Link] <= 0:

[Link] = True

score += 200 + level*30

if [Link] <= 0:

game_over = True

end_time = [Link].get_ticks()

total_time = (end_time - start_time) // 1000

# pickups

for p in powerups:

if dist((p.x,p.y),(player.x,player.y)) < [Link] + [Link]:

if [Link] == "health":

[Link] = min(player.max_health, [Link] + 2)

else:

# swap to next weapon and give a brief cooldown reset

player.switch_weapon()

player.last_shot = 0

[Link] = True

powerups = [p for p in powerups if not [Link] and [Link].get_ticks() - p.spawn_time < 20_000]

# wave completion

if not enemies and enemies_spawned_this_wave >= enemies_to_spawn:

if wave < WAVES_PER_LEVEL:

wave += 1

enemies_spawned_this_wave = 0

enemies_to_spawn = ENEMIES_BASE_PER_WAVE + (level-1)*2 + (wave-1)*2

else:

# level complete

level += 1

wave = 1
enemies_spawned_this_wave = 0

enemies_to_spawn = ENEMIES_BASE_PER_WAVE + (level-1)*2

# small heal between levels

[Link] = min(player.max_health, [Link] + 1)

# DRAW

[Link]((12,12,20))

# background grid

for gx in range(0, WIDTH, 48):

[Link](screen, (16,16,26), (gx,0), (gx, HEIGHT))

for gy in range(0, HEIGHT, 48):

[Link](screen, (16,16,26), (0,gy), (WIDTH, gy))

# draw entities

for b in bullets:

[Link](screen)

for e in enemies:

[Link](screen)

for p in powerups:

[Link](screen)

[Link](screen)

# HUD

[Link]([Link](f"Score: {score}", True, (230,230,230)), (WIDTH-170, 10))

[Link]([Link](f"Level: {level} Wave: {wave}/{WAVES_PER_LEVEL}", True, (230,230,230)),


(WIDTH-320, 10))

[Link]([Link](f"Weapon: {[Link]} AutoFire: {'ON' if player.auto_fire else 'OFF'}", True,


(210,210,210)), (10, HEIGHT-28))

# show remaining enemies count

[Link]([Link](f"Enemies: {len(enemies)}", True, (210,210,210)), (WIDTH-320, 34))

if game_over:

overlay = [Link]((WIDTH, HEIGHT), [Link])

[Link]((0,0,0,180))

[Link](overlay, (0,0))
draw_text_center(screen, "GAME OVER", HEIGHT//2 - 80, size=64, color=(255,100,100))

draw_text_center(screen, f"Score: {score}", HEIGHT//2 - 20, size=36)

draw_text_center(screen, "Press R to Restart or ESC to Menu", HEIGHT//2 + 40, size=22)

[Link]()

# wait for player entry of name to save score

# simple keyboard loop to type name, only if new high score

entries = load_scores()

best_scores = sorted(entries, key=lambda e: -e["score"])

is_high = len(entries) < MAX_SCORES or score > best_scores[-1]["score"] if entries else True

if is_high:

name = ""

entry_done = False

while not entry_done:

for ev in [Link]():

if [Link] == [Link]:

[Link](); [Link]()

if [Link] == [Link]:

if [Link] == pygame.K_RETURN:

entry_done = True

elif [Link] == pygame.K_BACKSPACE:

name = name[:-1]

elif [Link] == pygame.K_ESCAPE:

entry_done = True

else:

ch = [Link]

if [Link]() and len(name) < 12:

name += ch

# show name entry overlay

overlay = [Link]((WIDTH, HEIGHT), [Link])

[Link]((0,0,0,220))

[Link](overlay, (0,0))

draw_text_center(screen, "NEW HIGH SCORE! Enter name and press Enter", HEIGHT//2 - 40,
size=28)
[Link]([Link](name + ("|" if int([Link].get_ticks()/400)%2==0 else ""), True,
(255,255,255)), (WIDTH//2 - 100, HEIGHT//2 + 10))

[Link]()

[Link](FPS)

if [Link]():

add_score([Link](), score, ([Link].get_ticks() - start_time)//1000)

# wait until R or ESC pressed

waiting = True

while waiting:

for ev in [Link]():

if [Link] == [Link]:

[Link](); [Link]()

if [Link] == [Link]:

if [Link] == pygame.K_r:

return ("restart", None)

if [Link] == pygame.K_ESCAPE:

return ("menu", None)

[Link](FPS)

[Link]()

# ---------------- Title & Scoreboard ----------------

def title_screen():

while True:

[Link]((8,8,18))

draw_text_center(screen, "TOP-DOWN SHOOTER - ADVANCED", HEIGHT//2 - 100, size=48)

draw_text_center(screen, "WASD to move Mouse to aim/fire Q to switch weapon Space toggle autofire",
HEIGHT//2 - 20, size=18)

draw_text_center(screen, "Press ENTER to Play | H to view High Scores | Q to Quit", HEIGHT//2 +


40, size=20)

[Link]()

for ev in [Link]():

if [Link] == [Link]:

[Link](); [Link]()

if [Link] == [Link]:
if [Link] == pygame.K_RETURN:

res = main_game()

if res and res[0] == "restart":

continue

if [Link] == pygame.K_h:

show_scores()

if [Link] == pygame.K_q or [Link] == pygame.K_ESCAPE:

[Link](); [Link]()

[Link](FPS)

def show_scores():

entries = load_scores()

entries = sorted(entries, key=lambda e: -e["score"])

showing = True

while showing:

[Link]((6,6,20))

draw_text_center(screen, "HIGH SCORES", 60, size=48)

y = 120

for i, e in enumerate(entries[:MAX_SCORES], start=1):

line = f"{i:2}. {e['name'][:12]:12} Score:{e['score']:6} Time:{[Link]('time','?')}s"

[Link]([Link](line, True, (220,220,220)), (80, y))

y += 30

draw_text_center(screen, "Press any key to return", HEIGHT - 40, size=18)

[Link]()

for ev in [Link]():

if [Link] == [Link]:

[Link](); [Link]()

if [Link] == [Link] or [Link] == [Link]:

showing = False

[Link](FPS)

# ---------- Run ----------

if __name__ == "__main__":

title_screen()

You might also like