Py.Cafe

vaidya.pushkar/

missile.py

Shiny Slider Interaction

DocsPricing
  • app.py
  • missile.py
  • requirements.txt
missile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import pygame
import math

# --- 1. SETTINGS & MATH ---
WIDTH, HEIGHT = 1100, 700
CEILING_FT = 70000
DERATE_FT = 60000
THIRTY_K_FT_Y = HEIGHT - (30000 * (HEIGHT / CEILING_FT))

JET_SPEED_BASE = 6
MISSILE_SPEED = JET_SPEED_BASE * 1.1
JET_TURN_RATE = 5
MISSILE_TURN_RATE = JET_TURN_RATE / 1.2

class Entity:
    def __init__(self, x, y, speed, turn_rate, color, fuel, is_missile=False):
        self.start_pos = pygame.Vector2(x, y)
        self.pos = pygame.Vector2(x, y)
        self.angle = 0
        self.speed = speed
        self.turn_rate = turn_rate
        self.color = color
        self.max_fuel = fuel
        self.fuel = fuel
        self.is_missile = is_missile
        self.falling = False  # For the "out of fuel" tumble

    def reset(self):
        self.pos = pygame.Vector2(self.start_pos.x, self.start_pos.y)
        self.fuel = self.max_fuel
        self.angle = 0
        self.falling = False

# --- 2. INITIALIZE ---
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
font_small = pygame.font.SysFont("Courier New", 20, bold=True)
font_big = pygame.font.SysFont("Arial", 60, bold=True)

# 67% Fuel Logic: Jet = 100 units, Missile = 67 units
jet = Entity(100, 200, JET_SPEED_BASE, JET_TURN_RATE, (30, 60, 150), 100)
missile = None
game_active = True
dodged_count = 0
frame_count = 0

def draw_jet(surface, color, pos, angle):
    rad = math.radians(angle)
    points = [(pos.x + 25 * math.cos(rad), pos.y + 25 * math.sin(rad)),
              (pos.x + 15 * math.cos(rad + 2.4), pos.y + 15 * math.sin(rad + 2.4)),
              (pos.x + 5 * math.cos(rad + 3.14), pos.y + 5 * math.sin(rad + 3.14)),
              (pos.x + 15 * math.cos(rad - 2.4), pos.y + 15 * math.sin(rad - 2.4))]
    pygame.draw.polygon(surface, color, points)

def draw_missile(surface, pos, angle, fuel):
    rad = math.radians(angle)
    color = (255, 0, 0) if fuel > 0 else (100, 100, 100) # Turns grey when empty
    points = [(pos.x + 18 * math.cos(rad), pos.y + 18 * math.sin(rad)),
              (pos.x + 12 * math.cos(rad + 2.8), pos.y + 12 * math.sin(rad + 2.8)),
              (pos.x + 6 * math.cos(rad + 3.14), pos.y + 6 * math.sin(rad + 3.14)),
              (pos.x + 12 * math.cos(rad - 2.8), pos.y + 12 * math.sin(rad - 2.8))]
    pygame.draw.polygon(surface, color, points)
    if fuel > 0: # Rocket flame
        pygame.draw.circle(surface, (255, 255, 0), (int(pos.x - 8 * math.cos(rad)), int(pos.y - 8 * math.sin(rad))), 4)

def reset_game():
    global missile, game_active, dodged_count
    jet.reset()
    missile = None
    game_active = True
    dodged_count = 0

# --- 3. MAIN LOOP ---
running = True
while running:
    frame_count += 1
    current_alt = int(((HEIGHT - jet.pos.y) / HEIGHT) * CEILING_FT)
    
    # Derated Speed Logic
    current_speed = jet.speed * 0.9 if current_alt > DERATE_FT else jet.speed
    is_derated = current_alt > DERATE_FT

    screen.fill((10, 20, 50) if current_alt > 50000 else (100, 149, 237))

    for event in pygame.event.get():
        if event.type == pygame.QUIT: running = False
        if event.type == pygame.KEYDOWN and not game_active and event.key == pygame.K_r:
            reset_game()

    if game_active:
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:  jet.angle -= jet.turn_rate
        if keys[pygame.K_RIGHT]: jet.angle += jet.turn_rate
        if keys[pygame.K_UP] and jet.pos.y > 10: jet.pos.y -= 3 
        if keys[pygame.K_DOWN]: jet.pos.y += 3

        # Update Jet
        j_vel = pygame.Vector2(); j_vel.from_polar((current_speed, jet.angle))
        jet.pos += j_vel
        jet.fuel -= 0.012

        # Missile System (67% Fuel Logic)
        if missile is None and current_alt < 30000:
            missile = Entity(jet.pos.x % WIDTH, HEIGHT, MISSILE_SPEED, MISSILE_TURN_RATE, (255, 0, 0), 67, True)
        
        if missile:
            if missile.fuel > 0:
                dx, dy = (jet.pos.x % WIDTH) - missile.pos.x, jet.pos.y - missile.pos.y
                target_angle = math.degrees(math.atan2(dy, dx))
                angle_diff = (target_angle - missile.angle + 180) % 360 - 180
                missile.angle += max(min(angle_diff, missile.turn_rate), -missile.turn_rate)
                
                m_vel = pygame.Vector2(); m_vel.from_polar((missile.speed, missile.angle))
                missile.pos += m_vel
                missile.fuel -= 0.08

                if missile.pos.distance_to(pygame.Vector2(jet.pos.x % WIDTH, jet.pos.y)) < 18:
                    game_active = False
            else:
                # Tumble Out of Fuel
                missile.pos.y += 5
                missile.angle += 10 # Spin
                if missile.pos.y > HEIGHT:
                    missile = None
                    dodged_count += 1

        if current_alt <= 0 or jet.fuel <= 0: game_active = False

    # --- 4. DRAWING ---
    pygame.draw.line(screen, (255, 255, 255), (0, THIRTY_K_FT_Y), (WIDTH, THIRTY_K_FT_Y), 1)
    draw_jet(screen, jet.color, pygame.Vector2(jet.pos.x % WIDTH, jet.pos.y), jet.angle)
    if missile: draw_missile(screen, missile.pos, missile.angle, missile.fuel)

    # HUD
    screen.blit(font_small.render(f"ALTITUDE: {max(0, current_alt)} FT", True, (255,255,255)), (20, 20))
    screen.blit(font_small.render(f"DODGED:   {dodged_count}", True, (255,255,255)), (20, 50))
    if is_derated: screen.blit(font_small.render("DERATED", True, (255,255,0)), (20, 80))

    # Fuel Bars
    pygame.draw.rect(screen, (0,255,100), (WIDTH-120, 20, jet.fuel, 15)) # Jet
    if missile and missile.fuel > 0:
        pygame.draw.rect(screen, (255,0,0), (WIDTH-120, 45, (missile.fuel/67)*100, 10))

    if not game_active:
        screen.blit(font_big.render("MISSION FAILED", True, (255,0,0)), (WIDTH//2-200, HEIGHT//2))
        screen.blit(font_small.render("Press 'R' to Restart", True, (255,255,255)), (WIDTH//2-110, HEIGHT//2+70))

    pygame.display.flip()
    clock.tick(60)
pygame.quit()