4 games in total: A shooting range game, a spaceship game, a futuristic frogger game and a 3D First
```python
"""
Arcade Suite - Four small games in one file using pygame:
1) Shooting Range
2) Spaceship Shooter
3) Futuristic Frogger
4) Minimal Raycast 3D First-Person Shooter
Run: python arcade_suite.py
Controls shown in menu for each game.
Requires: pygame
"""
import pygame, sys, math, random, time
from pygame.locals import *
pygame.init()
SCREEN = pygame.display.set_mode((1024, 640))
pygame.display.set_caption("Arcade Suite")
FONT = pygame.font.SysFont("Consolas", 20)
CLOCK = pygame.time.Clock()
def draw_text(surface, txt, x, y, c=(255,255,255)):
surface.blit(FONT.render(txt, True, c), (x,y))
def menu():
while True:
SCREEN.fill((18,18,30))
draw_text(SCREEN, "Arcade Suite", 420, 40)
draw_text(SCREEN, "1: Shooting Range", 420, 120)
draw_text(SCREEN, "2: Spaceship Shooter", 420, 160)
draw_text(SCREEN, "3: Futuristic Frogger", 420, 200)
draw_text(SCREEN, "4: Mini 3D FPS (raycast)", 420, 240)
draw_text(SCREEN, "ESC: Quit", 420, 320)
pygame.display.flip()
for e in pygame.event.get():
if e.type==QUIT: pygame.quit(); sys.exit()
if e.type==KEYDOWN:
if e.key==K_1: shooting_range()
if e.key==K_2: spaceship()
if e.key==K_3: frogger()
if e.key==K_4: raycast_fps()
if e.key==K_ESCAPE: pygame.quit(); sys.exit()
CLOCK.tick(30)
# ---------------- Shooting Range ----------------
def shooting_range():
targets = []
score = 0
start = time.time()
duration = 40
spawn_timer = 0
cross = pygame.cursors.crosshair
while True:
dt = CLOCK.tick(60)/1000.0
spawn_timer += dt
if spawn_timer > max(0.6, 1.6 - (score*0.03)):
spawn_timer = 0
r = random.randint(20,60)
x = random.randint(100, 924)
y = random.randint(100, 540)
targets.append({"x":x,"y":y,"r":r,"hp":1+ r//40, "t": time.time()})
for e in pygame.event.get():
if e.type==QUIT: return
if e.type==KEYDOWN and e.key==K_ESCAPE: return
if e.type==MOUSEBUTTONDOWN and e.button==1:
mx,my = e.pos
for t in targets[:]:
if (mx-t["x"])**2 + (my-t["y"])**2 <= t["r"]**2:
score += 10 * t["hp"]
targets.remove(t)
break
SCREEN.fill((10,12,28))
draw_text(SCREEN, "Shooting Range - Click targets! ESC to return", 20,20)
draw_text(SCREEN, f"Time left: {max(0, int(duration - (time.time()-start)))}", 20, 50)
draw_text(SCREEN, f"Score: {score}", 20, 80)
for t in targets[:]:
age = time.time()-t["t"]
col = (255, 100 + int(155*math.sin(age*3)%155), 60)
pygame.draw.circle(SCREEN, col, (t["x"], t["y"]), t["r"])
pygame.draw.circle(SCREEN, (255,255,255), (t["x"], t["y"]), int(t["r"]*0.6), 2)
if age > 3.5:
try: targets.remove(t)
except: pass
if time.time() - start > duration:
draw_text(SCREEN, f"Time up! Final score: {score} (press any key)", 300, 300, (255,200,0))
pygame.display.flip()
wait_for_key()
return
pygame.display.set_cursor(*cross)
pygame.display.flip()
# ---------------- Spaceship Shooter ----------------
def spaceship():
ship = pygame.Rect(480, 540, 48, 24)
bullets = []
asteroids = []
score = 0
spawn = 0
lives = 3
while True:
dt = CLOCK.tick(60)/1000.0
spawn += dt
for e in pygame.event.get():
if e.type==QUIT: return
if e.type==KEYDOWN and e.key==K_ESCAPE: return
if e.type==KEYDOWN and e.key==K_SPACE:
bullets.append([ship.centerx, ship.top, -400])
keys = pygame.key.get_pressed()
if keys[K_LEFT]: ship.x -= int(400*dt)
if keys[K_RIGHT]: ship.x += int(400*dt)
ship.x = max(0, min(1024-ship.width, ship.x))
if spawn > 0.7:
spawn = 0
x = random.randint(20, 1004)
vy = random.uniform(80,220)
r = random.randint(12,38)
asteroids.append([x, -r, vy, r])
for b in bullets[:]:
b[1] += b[2]*dt
if b[1] < -50:
bullets.remove(b)
for a in asteroids[:]:
a[1] += a[2]*dt
if a[1] - a[3] > 720:
asteroids.remove(a)
lives -= 1
else:
for b in bullets[:]:
if (b[0]-a[0])**2 + (b[1]-a[1])**2 < (a[3]+4)**2:
try:
asteroids.remove(a)
bullets.remove(b)
except:
pass
score += max(1, 50-a[3])
break
SCREEN.fill((3,3,18))
draw_text(SCREEN, "Spaceship Shooter - Arrow keys to move, SPACE to shoot, ESC to return", 12, 12)
draw_text(SCREEN, f"Score: {score} Lives: {lives}", 12, 40)
pygame.draw.polygon(SCREEN, (80,200,240), [(ship.left, ship.bottom),(ship.right, ship.bottom),(ship.centerx, ship.top)])
for b in bullets:
pygame.draw.rect(SCREEN, (255,240,80), pygame.Rect(b[0]-3, b[1]-10, 6, 12))
for a in asteroids:
pygame.draw.circle(SCREEN, (120,80,50), (int(a[0]), int(a[1])), a[3])
pygame.draw.circle(SCREEN, (200,200,200), (int(a[0]), int(a[1])), max(2,a[3]//4))
if lives <= 0:
draw_text(SCREEN, f"Game Over! Score {score} - press any key", 360, 300, (255,180,0))
pygame.display.flip()
wait_for_key()
return
pygame.display.flip()
# ---------------- Futuristic Frogger ----------------
def frogger():
frog = pygame.Rect(492, 580, 40, 40)
lanes = []
for i in range(5):
y = 120 + i*72
speed = random.choice([80,120,160]) * (1 if i%2==0 else -1)
lanes.append({"y":y,"speed":speed,"cars":[]})
for k in range(3):
x = random.randint(0, 900)
lanes[-1]["cars"].append([x, y+6, random.randint(60,120)])
lives = 3
score = 0
while True:
dt = CLOCK.tick(60)/1000.0
for e in pygame.event.get():
if e.type==QUIT: return
if e.type==KEYDOWN:
if e.key==K_ESCAPE: return
if e.key==K_UP: frog.y -= 72
if e.key==K_DOWN: frog.y += 72
if e.key==K_LEFT: frog.x -= 80
if e.key==K_RIGHT: frog.x += 80
frog.x = max(0,min(1024-frog.width, frog.x))
frog.y = max(60, min(620-frog.height, frog.y))
for lane in lanes:
for car in lane["cars"]:
car[0] += lane["speed"]*dt
if lane["speed"]>0 and car[0] > 1100:
car[0] = -150
if lane["speed"]<0 and car[0] < -200:
car[0] = 1100
hit = False
for lane in lanes:
for car in lane["cars"]:
crect = pygame.Rect(int(car[0]), int(car[1]), 120, 48)
if crect.colliderect(frog):
hit = True
SCREEN.fill((8,10,30))
draw_text(SCREEN, "Futuristic Frogger - Arrow keys to move. Cross to top! ESC to return", 8, 8)
draw_text(SCREEN, f"Lives: {lives} Score: {score}", 8, 40)
# draw lanes
for lane in lanes:
pygame.draw.rect(SCREEN, (30,30,40), (0, lane["y"]-8, 1024, 56))
for car in lane["cars"]:
pygame.draw.rect(SCREEN, (200,80,80), pygame.Rect(int(car[0]), int(car[1]), 120, 48))
pygame.draw.rect(SCREEN, (70,220,70), frog)
if frog.top < 100:
score += 10
frog.x, frog.y = 492, 580
if hit:
lives -= 1
frog.x, frog.y = 492, 580
time.sleep(0.4)
if lives <= 0:
draw_text(SCREEN, f"Game Over! Score {score} - press any key", 360, 300, (255,180,0))
pygame.display.flip()
wait_for_key()
return
pygame.display.flip()
# ---------------- Minimal Raycast 3D FPS ----------------
def raycast_fps():
W, H = 1024, 640
map_grid = [
"################",
"#......#.......#",
"#..##..#..##...#",
"#..##..#..##...#",
"#......#.......#",
"#......#...#...#",
"#......#...#...#",
"################",
]
MAP_W = len(map_grid[0]); MAP_H = len(map_grid)
tile = 64
player_x, player_y, player_a = 150.0, 150.0, 0.0
speed = 120.0
rot_speed = 2.5
FOV = math.pi/3
max_depth = 800
bullet_list = []
while True:
dt = CLOCK.tick(60)/1000.0
for e in pygame.event.get():
if e.type==QUIT: return
if e.type==KEYDOWN and e.key==K_ESCAPE: return
if e.type==MOUSEBUTTONDOWN and e.button==1:
# shoot bullet forward
bx = player_x + math.cos(player_a)*20
by = player_y + math.sin(player_a)*20
bullet_list.append([bx,by,player_a, 480])
keys = pygame.key.get_pressed()
if keys[K_w]:
nx = player_x + math.cos(player_a) * speed * dt
ny = player_y + math.sin(player_a) * speed * dt
if not hit_wall(nx, ny, map_grid, tile):
player_x, player_y = nx, ny
if keys[K_s]:
nx = player_x - math.cos(player_a) * speed * dt
ny = player_y - math.sin(player_a) * speed * dt
if not hit_wall(nx, ny, map_grid, tile):
player_x, player_y = nx, ny
if keys[K_a]:
player_a -= rot_speed*dt
if keys[K_d]:
player_a += rot_speed*dt
# draw 3D via raycasting
SCREEN.fill((70,120,200))
# floor and ceiling
pygame.draw.rect(SCREEN, (30,30,30), (0, H//2, W, H//2))
num_rays = 200
for i in range(num_rays):
ray_angle = (player_a - FOV/2.0) + (i/num_rays)*FOV
distance, shade = cast_ray(player_x, player_y, ray_angle, map_grid, tile, max_depth)
# correct fish-eye
distance *= math.cos(player_a - ray_angle)
if distance<=0: distance=0.001
line_height = (tile*300)/distance
color = (max(10, 255 - shade), max(10, 255 - shade//2), max(10, 255 - shade//3))
x = int(i * (W/num_rays))
pygame.draw.rect(SCREEN, color, (x, int(H/2 - line_height/2), int(W/num_rays)+1, int(line_height)))
# bullets update
for b in bullet_list[:]:
b[0] += math.cos(b[2])*400*dt
b[1] += math.sin(b[2])*400*dt
b[3] -= 400*dt
pygame.draw.circle(SCREEN, (255,255,50), (int(b[0]/(MAP_W*tile)*W), int(b[1]/(MAP_H*tile)*H)), 3)
if hit_wall(b[0], b[1], map_grid, tile) or b[3]<=0:
try: bullet_list.remove(b)
except: pass
# HUD
draw_text(SCREEN, "Mini 3D FPS - WASD to move, mouse click to shoot, ESC to quit", 8,8)
pygame.display.flip()
def hit_wall(x,y,map_grid,tile):
gx = int(x//tile)
gy = int(y//tile)
if gy<0 or gy>=len(map_grid) or gx<0 or gx>=len(map_grid[0]): return True
return map_grid[gy][gx] == '#'
def cast_ray(px, py, ang, map_grid, tile, max_depth):
sin_a = math.sin(ang); cos_a = math.cos(ang)
step = 4.0
dist = 0.0
shade = 0
while dist < max_depth:
cx = px + cos_a * dist
cy = py + sin_a * dist
if hit_wall(cx, cy, map_grid, tile):
shade = min(240, int(dist/3))
return dist, shade
dist += step
return max_depth, 240
def wait_for_key():
while True:
for e in pygame.event.get():
if e.type==QUIT: pygame.quit(); sys.exit()
if e.type==KEYDOWN or e.type==MOUSEBUTTONDOWN:
return
if __name__ == "__main__":
try:
menu()
except Exception as ex:
pygame.quit()
print("Error:", ex)
```