Menú

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)
```