Senin, 13 April 2026

Python Animation - Drone 16

 




import tkinter as tk

import math


# --- CONFIG ---

CANVAS_WIDTH = 800

CANVAS_HEIGHT = 600

DRONE_WIDTH = 100

DRONE_HEIGHT = 40

PROPELLER_RADIUS = 15

MISSILE_SPEED = 10

DRONE_SPEED = 5

ENEMY_WIDTH = 60

ENEMY_HEIGHT = 40


class UnderseaGame:

    def __init__(self, root):

        self.root = root

        self.root.title("Undersea Drone Animation")


        self.canvas = tk.Canvas(root, width=CANVAS_WIDTH, height=CANVAS_HEIGHT, bg="lightblue")

        self.canvas.pack()


        # Drone position

        self.drone_x = CANVAS_WIDTH // 2

        self.drone_y = CANVAS_HEIGHT // 2

        self.drone_angle = 0  # For propeller rotation


        # Missile list

        self.missiles = []


        # Enemy

        self.enemy = self.canvas.create_rectangle(

            600, 200, 600 + ENEMY_WIDTH, 200 + ENEMY_HEIGHT, fill="red"

        )


        # Bind keys

        self.root.bind("<KeyPress>", self.key_press)


        # Start animation

        self.animate()


    def draw_drone(self):

        # Clear old drone

        self.canvas.delete("drone")


        # Drone body

        x1 = self.drone_x - DRONE_WIDTH // 2

        y1 = self.drone_y - DRONE_HEIGHT // 2

        x2 = self.drone_x + DRONE_WIDTH // 2

        y2 = self.drone_y + DRONE_HEIGHT // 2

        self.canvas.create_rectangle(x1, y1, x2, y2, fill="gray", tags="drone")


        # Propeller center (left side of drone)

        prop_x = x1 - PROPELLER_RADIUS - 5

        prop_y = self.drone_y


        # Draw propeller circle

        self.canvas.create_oval(

            prop_x - PROPELLER_RADIUS, prop_y - PROPELLER_RADIUS,

            prop_x + PROPELLER_RADIUS, prop_y + PROPELLER_RADIUS,

            outline="black", fill="silver", tags="drone"

        )


        # Draw 4 spokes (rotating)

        for i in range(4):

            angle = math.radians(self.drone_angle + i * 90)

            x_end = prop_x + PROPELLER_RADIUS * math.cos(angle)

            y_end = prop_y + PROPELLER_RADIUS * math.sin(angle)

            self.canvas.create_line(prop_x, prop_y, x_end, y_end, fill="black", tags="drone")


    def draw_missiles(self):

        self.canvas.delete("missile")

        for missile in self.missiles:

            x, y = missile["pos"]

            self.canvas.create_rectangle(

                x - 3, y - 3, x + 3, y + 3, fill="yellow", tags="missile"

            )


    def move_missiles(self):

        for missile in self.missiles[:]:

            missile["pos"] = (missile["pos"][0] + MISSILE_SPEED, missile["pos"][1])

            # Remove if out of bounds

            if missile["pos"][0] > CANVAS_WIDTH:

                self.missiles.remove(missile)

            else:

                self.check_collision(missile)


    def check_collision(self, missile):

        if self.enemy:

            ex1, ey1, ex2, ey2 = self.canvas.coords(self.enemy)

            mx, my = missile["pos"]

            if ex1 <= mx <= ex2 and ey1 <= my <= ey2:

                # Hit enemy

                self.canvas.delete(self.enemy)

                self.enemy = None

                self.missiles.remove(missile)


    def key_press(self, event):

        if event.keysym.lower() == "w":

            self.drone_y = max(DRONE_HEIGHT // 2, self.drone_y - DRONE_SPEED)

        elif event.keysym.lower() == "s":

            self.drone_y = min(CANVAS_HEIGHT - DRONE_HEIGHT // 2, self.drone_y + DRONE_SPEED)

        elif event.keysym.lower() == "a":

            self.drone_x = max(DRONE_WIDTH // 2, self.drone_x - DRONE_SPEED)

        elif event.keysym.lower() == "d":

            self.drone_x = min(CANVAS_WIDTH - DRONE_WIDTH // 2, self.drone_x + DRONE_SPEED)

        elif event.keysym.lower() == "space":

            # Launch missile from front of drone

            missile_x = self.drone_x + DRONE_WIDTH // 2

            missile_y = self.drone_y

            self.missiles.append({"pos": (missile_x, missile_y)})


    def animate(self):

        # Rotate propeller

        self.drone_angle = (self.drone_angle + 15) % 360


        # Move missiles

        self.move_missiles()


        # Redraw everything

        self.draw_drone()

        self.draw_missiles()


        # Repeat

        self.root.after(50, self.animate)


# --- RUN GAME ---

if __name__ == "__main__":

    root = tk.Tk()

    game = UnderseaGame(root)

    root.mainloop()

Python Animation - Drone 15

 



import tkinter as tk

import math

import random


# Window setup

WIDTH, HEIGHT = 800, 600

root = tk.Tk()

root.title("Drone Animation with Missile and Enemy")


canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="skyblue")

canvas.pack()


# Drone properties

drone_x, drone_y = WIDTH // 2, HEIGHT // 2

drone_size = 100

propeller_radius = 15

spoke_count = 4

spoke_angle = 0  # For rotation animation


# Missile properties

missiles = []  # List of (x, y, dx, dy, id)

missile_speed = 10


# Enemy properties

enemy_size = 60

enemy_x = random.randint(100, WIDTH - 100)

enemy_y = random.randint(100, HEIGHT - 100)

enemy_id = canvas.create_rectangle(enemy_x, enemy_y,

                                   enemy_x + enemy_size, enemy_y + enemy_size,

                                   fill="red")


# Movement control

keys_pressed = set()

drone_speed = 5



def draw_drone():

    """Draws the drone with rotating propellers."""

    global spoke_angle

    canvas.delete("drone")


    # Drone body

    body_id = canvas.create_rectangle(drone_x - drone_size // 2,

                                      drone_y - drone_size // 4,

                                      drone_x + drone_size // 2,

                                      drone_y + drone_size // 4,

                                      fill="gray", tags="drone")


    # Propeller positions (top-left, top-right, bottom-left, bottom-right)

    offsets = [(-drone_size // 2, -drone_size // 4),

               (drone_size // 2, -drone_size // 4),

               (-drone_size // 2, drone_size // 4),

               (drone_size // 2, drone_size // 4)]


    for ox, oy in offsets:

        cx = drone_x + ox

        cy = drone_y + oy

        canvas.create_oval(cx - propeller_radius, cy - propeller_radius,

                           cx + propeller_radius, cy + propeller_radius,

                           fill="black", tags="drone")


        # Draw rotating spokes

        for i in range(spoke_count):

            angle = spoke_angle + (i * math.pi / (spoke_count / 2))

            x1 = cx + math.cos(angle) * propeller_radius

            y1 = cy + math.sin(angle) * propeller_radius

            x2 = cx - math.cos(angle) * propeller_radius

            y2 = cy - math.sin(angle) * propeller_radius

            canvas.create_line(x1, y1, x2, y2, fill="white", tags="drone")


    spoke_angle += 0.2  # Rotation speed



def move_drone():

    """Moves the drone based on pressed keys."""

    global drone_x, drone_y

    if "w" in keys_pressed and drone_y - drone_speed > 0:

        drone_y -= drone_speed

    if "s" in keys_pressed and drone_y + drone_speed < HEIGHT:

        drone_y += drone_speed

    if "a" in keys_pressed and drone_x - drone_speed > 0:

        drone_x -= drone_speed

    if "d" in keys_pressed and drone_x + drone_speed < WIDTH:

        drone_x += drone_speed



def fire_missile():

    """Launches a missile from the drone's front."""

    mx = drone_x + drone_size // 2

    my = drone_y

    missiles.append([mx, my, missile_speed, 0, None])



def update_missiles():

    """Moves missiles and checks for collisions."""

    global enemy_id

    for missile in missiles[:]:

        missile[0] += missile[2]

        missile[1] += missile[3]


        # Remove if out of bounds

        if missile[0] > WIDTH or missile[0] < 0 or missile[1] > HEIGHT or missile[1] < 0:

            missiles.remove(missile)

            continue


        # Draw missile

        if missile[4] is not None:

            canvas.delete(missile[4])

        missile[4] = canvas.create_rectangle(missile[0] - 5, missile[1] - 2,

                                             missile[0] + 5, missile[1] + 2,

                                             fill="yellow", tags="missile")


        # Collision with enemy

        if enemy_id is not None:

            ex1, ey1, ex2, ey2 = canvas.coords(enemy_id)

            if ex1 <= missile[0] <= ex2 and ey1 <= missile[1] <= ey2:

                canvas.delete(enemy_id)

                enemy_id = None

                missiles.remove(missile)



def game_loop():

    """Main animation loop."""

    move_drone()

    draw_drone()

    update_missiles()

    root.after(30, game_loop)



# Key bindings

def key_press(event):

    keys_pressed.add(event.keysym.lower())

    if event.keysym.lower() == "space":

        fire_missile()



def key_release(event):

    if event.keysym.lower() in keys_pressed:

        keys_pressed.remove(event.keysym.lower())



root.bind("<KeyPress>", key_press)

root.bind("<KeyRelease>", key_release)


# Start game

game_loop()

root.mainloop()


Python Animation - Drone 14

 




import tkinter as tk

import math

import time


# =========================

# Drone Animation Class

# =========================

class DroneApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Drone Animation with Missile Launch")


        # Canvas setup

        self.canvas = tk.Canvas(root, width=800, height=600, bg="skyblue")

        self.canvas.pack()


        # Drone properties

        self.drone_width = 100

        self.drone_height = 40

        self.x = 400

        self.y = 300

        self.propeller_radius = 15

        self.spoke_count = 4

        self.angle = 0  # rotation angle for propellers


        # Movement speed

        self.speed = 5


        # Missile properties

        self.missiles = []  # list of (id, x, y)

        self.missile_speed = 10


        # Key bindings

        self.root.bind("<KeyPress>", self.key_press)


        # Start animation loop

        self.animate()


    def draw_drone(self):

        # Clear canvas

        self.canvas.delete("all")


        # Draw drone body

        left = self.x - self.drone_width / 2

        top = self.y - self.drone_height / 2

        right = self.x + self.drone_width / 2

        bottom = self.y + self.drone_height / 2

        self.canvas.create_rectangle(left, top, right, bottom, fill="gray", outline="black", width=2)


        # Propeller positions (corners)

        offsets = [

            (-self.drone_width / 2, -self.drone_height / 2),  # top-left

            (self.drone_width / 2, -self.drone_height / 2),   # top-right

            (-self.drone_width / 2, self.drone_height / 2),   # bottom-left

            (self.drone_width / 2, self.drone_height / 2)     # bottom-right

        ]


        for dx, dy in offsets:

            cx = self.x + dx

            cy = self.y + dy

            self.draw_propeller(cx, cy)


        # Draw missiles

        for missile in self.missiles:

            self.canvas.create_oval(missile[0] - 3, missile[1] - 3,

                                    missile[0] + 3, missile[1] + 3,

                                    fill="red")


    def draw_propeller(self, cx, cy):

        # Draw propeller circle

        self.canvas.create_oval(cx - self.propeller_radius, cy - self.propeller_radius,

                                cx + self.propeller_radius, cy + self.propeller_radius,

                                outline="black", width=2)


        # Draw spokes

        for i in range(self.spoke_count):

            angle_rad = math.radians(self.angle + (360 / self.spoke_count) * i)

            x_end = cx + self.propeller_radius * math.cos(angle_rad)

            y_end = cy + self.propeller_radius * math.sin(angle_rad)

            self.canvas.create_line(cx, cy, x_end, y_end, fill="black", width=1)


    def key_press(self, event):

        key = event.keysym.lower()

        if key == "w":

            self.y -= self.speed

        elif key == "s":

            self.y += self.speed

        elif key == "a":

            self.x -= self.speed

        elif key == "d":

            self.x += self.speed

        elif key == "space":

            self.launch_missile()


    def launch_missile(self):

        # Missile starts from center front of drone

        missile_x = self.x + self.drone_width / 2

        missile_y = self.y

        self.missiles.append([missile_x, missile_y])


    def update_missiles(self):

        # Move missiles forward

        for missile in self.missiles:

            missile[0] += self.missile_speed

        # Remove missiles that go off screen

        self.missiles = [m for m in self.missiles if m[0] < 800]


    def animate(self):

        # Rotate propellers

        self.angle = (self.angle + 15) % 360


        # Update missiles

        self.update_missiles()


        # Redraw drone

        self.draw_drone()


        # Schedule next frame

        self.root.after(50, self.animate)



# =========================

# Run the Application

# =========================

if __name__ == "__main__":

    root = tk.Tk()

    app = DroneApp(root)

    root.mainloop()

Python Animation - Drone 13

 



import tkinter as tk
import math

class DroneAnimation:
    def __init__(self, root):
        self.root = root
        self.canvas = tk.Canvas(root, width=600, height=500, bg='white')
        self.canvas.pack()

        # Drone properties
        self.x, self.y = 300, 250
        self.speed = 10
        self.angle = 0
        self.prop_radius = 20
        self.drone_size = 40

        # Draw Drone Elements
        self.body = self.canvas.create_oval(self.x-self.drone_size, self.y-self.drone_size,
                                             self.x+self.drone_size, self.y+self.drone_size, fill='gray')
        
        # Propeller positions (4 corners)
        self.props = []
        prop_offsets = [(-30, -30), (30, -30), (-30, 30), (30, 30)]
        for dx, dy in prop_offsets:
            p_center = (self.x + dx, self.y + dy)
            circle = self.canvas.create_oval(p_center[0]-self.prop_radius, p_center[1]-self.prop_radius,
                                              p_center[0]+self.prop_radius, p_center[1]+self.prop_radius, outline='blue', width=2)
            
            # 4 spokes
            spokes = [self.canvas.create_line(p_center[0], p_center[1], p_center[0], p_center[1], fill='blue') for _ in range(4)]
            self.props.append({'circle': circle, 'spokes': spokes, 'center': (dx, dy)})

        # Key Bindings
        self.root.bind("<KeyPress>", self.move)
        
        # Start Animation
        self.animate()

    def animate(self):
        self.angle += 15
        
        # Update Propellers
        for prop in self.props:
            dx, dy = prop['center']
            px, py = self.x + dx, self.y + dy
            
            # Rotate spokes
            for i, spoke in enumerate(prop['spokes']):
                spoke_angle = self.angle + (i * 90)
                end_x = px + self.prop_radius * math.cos(math.radians(spoke_angle))
                end_y = py + self.prop_radius * math.sin(math.radians(spoke_angle))
                self.canvas.coords(spoke, px, py, end_x, end_y)
            
            # Move propeller circles
            self.canvas.coords(prop['circle'], px-self.prop_radius, py-self.prop_radius,
                                px+self.prop_radius, py+self.prop_radius)
        
        # Move body
        self.canvas.coords(self.body, self.x-self.drone_size, self.y-self.drone_size,
                           self.x+self.drone_size, self.y+self.drone_size)
        
        self.root.after(50, self.animate)

    def move(self, event):
        if event.keysym == 'w': self.y -= self.speed
        elif event.keysym == 's': self.y += self.speed
        elif event.keysym == 'a': self.x -= self.speed
        elif event.keysym == 'd': self.x += self.speed

if __name__ == "__main__":
    root = tk.Tk()
    root.title("2D Drone Animation")
    app = DroneAnimation(root)
    root.mainloop()


Python Animation - Drone 12

 



import tkinter as tk
import math

class DroneAnimation:
    def __init__(self, root):
        self.root = root
        self.root.title("2D Drone Animation with Rotating Propellers")

        # Canvas setup
        self.canvas_width = 600
        self.canvas_height = 400
        self.canvas = tk.Canvas(root, width=self.canvas_width, height=self.canvas_height, bg="skyblue")
        self.canvas.pack()

        # Drone parameters
        self.drone_center = [300, 200]
        self.body_width = 120
        self.body_height = 40
        self.propeller_radius = 20
        self.spokes = 4
        self.angle = 0  # rotation angle for propellers
        self.fly_dx = 2  # horizontal movement speed
        self.fly_dy = 1  # vertical movement speed

        # Draw drone body
        self.body = self.canvas.create_rectangle(
            self.drone_center[0] - self.body_width // 2,
            self.drone_center[1] - self.body_height // 2,
            self.drone_center[0] + self.body_width // 2,
            self.drone_center[1] + self.body_height // 2,
            fill="gray", outline="black"
        )

        # Propeller positions (relative to body)
        self.propeller_offsets = [
            (-self.body_width // 2, -self.body_height // 2),  # top-left
            (self.body_width // 2, -self.body_height // 2),   # top-right
            (-self.body_width // 2, self.body_height // 2),   # bottom-left
            (self.body_width // 2, self.body_height // 2)     # bottom-right
        ]

        # Store propeller parts
        self.propeller_circles = []
        self.propeller_spokes = []

        for offset in self.propeller_offsets:
            cx = self.drone_center[0] + offset[0]
            cy = self.drone_center[1] + offset[1]
            circle = self.canvas.create_oval(
                cx - self.propeller_radius, cy - self.propeller_radius,
                cx + self.propeller_radius, cy + self.propeller_radius,
                outline="black", width=2
            )
            self.propeller_circles.append(circle)

            spokes_list = []
            for _ in range(self.spokes):
                spoke = self.canvas.create_line(cx, cy, cx, cy, fill="black", width=2)
                spokes_list.append(spoke)
            self.propeller_spokes.append(spokes_list)

        self.animate()

    def animate(self):
        # Move drone
        self.drone_center[0] += self.fly_dx
        self.drone_center[1] += self.fly_dy

        # Bounce off walls
        if self.drone_center[0] < 100 or self.drone_center[0] > self.canvas_width - 100:
            self.fly_dx *= -1
        if self.drone_center[1] < 60 or self.drone_center[1] > self.canvas_height - 60:
            self.fly_dy *= -1

        # Move body
        self.canvas.coords(
            self.body,
            self.drone_center[0] - self.body_width // 2,
            self.drone_center[1] - self.body_height // 2,
            self.drone_center[0] + self.body_width // 2,
            self.drone_center[1] + self.body_height // 2
        )

        # Rotate propellers
        self.angle += 15  # rotation speed
        for i, offset in enumerate(self.propeller_offsets):
            cx = self.drone_center[0] + offset[0]
            cy = self.drone_center[1] + offset[1]

            # Update circle position
            self.canvas.coords(
                self.propeller_circles[i],
                cx - self.propeller_radius, cy - self.propeller_radius,
                cx + self.propeller_radius, cy + self.propeller_radius
            )

            # Update spokes
            for j, spoke in enumerate(self.propeller_spokes[i]):
                spoke_angle = math.radians(self.angle + (360 / self.spokes) * j)
                x_end = cx + self.propeller_radius * math.cos(spoke_angle)
                y_end = cy + self.propeller_radius * math.sin(spoke_angle)
                self.canvas.coords(spoke, cx, cy, x_end, y_end)

        # Schedule next frame
        self.root.after(50, self.animate)

# Run the animation
if __name__ == "__main__":
    root = tk.Tk()
    app = DroneAnimation(root)
    root.mainloop()


Python Animation - Drone 11

 



import tkinter as tk
import math
import time

class DroneAnimation:
    def __init__(self, root):
        self.root = root
        self.root.title("2D Drone Animation with Rotating Propellers")

        # Canvas setup
        self.canvas_width = 800
        self.canvas_height = 400
        self.canvas = tk.Canvas(root, width=self.canvas_width, height=self.canvas_height, bg="skyblue")
        self.canvas.pack()

        # Drone properties
        self.drone_width = 120
        self.drone_height = 40
        self.propeller_radius = 15
        self.spokes = 4
        self.angle = 0  # rotation angle for propellers
        self.speed = 3  # horizontal speed

        # Initial drone position
        self.x = 50
        self.y = 200

        # Draw drone body and propellers
        self.body = self.canvas.create_rectangle(
            self.x, self.y,
            self.x + self.drone_width, self.y + self.drone_height,
            fill="gray", outline="black"
        )

        # Propeller positions (relative to body)
        self.propeller_offsets = [
            (-20, -20),  # top-left
            (self.drone_width + 20, -20),  # top-right
            (-20, self.drone_height + 20),  # bottom-left
            (self.drone_width + 20, self.drone_height + 20)  # bottom-right
        ]

        # Create propeller spoke lines
        self.propellers = []
        for _ in range(4):
            lines = []
            for _ in range(self.spokes):
                line = self.canvas.create_line(0, 0, 0, 0, fill="black", width=2)
                lines.append(line)
            self.propellers.append(lines)

        self.animate()

    def draw_propeller(self, cx, cy, angle, lines):
        """Draws a propeller with spokes rotated by given angle."""
        spoke_angle = 360 / self.spokes
        for i, line in enumerate(lines):
            theta = math.radians(angle + i * spoke_angle)
            x_end = cx + self.propeller_radius * math.cos(theta)
            y_end = cy + self.propeller_radius * math.sin(theta)
            self.canvas.coords(line, cx, cy, x_end, y_end)

    def animate(self):
        # Move drone horizontally
        self.x += self.speed
        if self.x > self.canvas_width:
            self.x = -self.drone_width  # wrap around

        # Update drone body position
        self.canvas.coords(
            self.body,
            self.x, self.y,
            self.x + self.drone_width, self.y + self.drone_height
        )

        # Update propellers
        self.angle = (self.angle + 20) % 360  # rotation speed
        for idx, (dx, dy) in enumerate(self.propeller_offsets):
            cx = self.x + dx
            cy = self.y + dy
            self.draw_propeller(cx, cy, self.angle, self.propellers[idx])

        # Schedule next frame
        self.root.after(50, self.animate)


if __name__ == "__main__":
    root = tk.Tk()
    app = DroneAnimation(root)
    root.mainloop()


Minggu, 12 April 2026

Python Animation - Drone 10

 





import tkinter as tk

import math


# =========================

# Quadcopter Animation App

# =========================

class QuadcopterApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Quadcopter Animation")


        # Canvas setup

        self.canvas = tk.Canvas(root, width=800, height=600, bg="skyblue")

        self.canvas.pack()


        # Start button

        self.start_btn = tk.Button(root, text="Start Animation", command=self.start_animation)

        self.start_btn.pack(pady=10)


        # Quadcopter state

        self.qx, self.qy = 400, 300  # center position

        self.prop_angle = 0

        self.running = False

        self.missiles = []  # list of active missiles


        # Bind keys

        self.root.bind("<KeyPress>", self.key_press)


    def start_animation(self):

        """Start the animation loop."""

        if not self.running:

            self.running = True

            self.animate()


    def key_press(self, event):

        """Handle movement and missile launch."""

        if not self.running:

            return

        step = 10

        if event.keysym.lower() == "w":

            self.qy -= step

        elif event.keysym.lower() == "s":

            self.qy += step

        elif event.keysym.lower() == "a":

            self.qx -= step

        elif event.keysym.lower() == "d":

            self.qx += step

        elif event.keysym == "space":

            self.launch_missile()


    def launch_missile(self):

        """Create a missile starting from quadcopter center."""

        missile = {

            "x": self.qx,

            "y": self.qy - 20,

            "id": None

        }

        self.missiles.append(missile)


    def draw_quadcopter(self):

        """Draw the quadcopter body and rotating propellers."""

        # Body

        body_size = 40

        self.canvas.create_rectangle(

            self.qx - body_size/2, self.qy - body_size/2,

            self.qx + body_size/2, self.qy + body_size/2,

            fill="gray", outline="black"

        )


        # Arm length

        arm_len = 50

        prop_radius = 10


        # Propeller positions (relative to center)

        offsets = [

            (-arm_len, -arm_len),

            (arm_len, -arm_len),

            (-arm_len, arm_len),

            (arm_len, arm_len)

        ]


        for dx, dy in offsets:

            cx = self.qx + dx

            cy = self.qy + dy

            # Draw propeller hub

            self.canvas.create_oval(cx - prop_radius, cy - prop_radius,

                                    cx + prop_radius, cy + prop_radius,

                                    fill="black")

            # Draw rotating blades

            blade_len = 20

            angle_rad = math.radians(self.prop_angle)

            x1 = cx + blade_len * math.cos(angle_rad)

            y1 = cy + blade_len * math.sin(angle_rad)

            x2 = cx - blade_len * math.cos(angle_rad)

            y2 = cy - blade_len * math.sin(angle_rad)

            self.canvas.create_line(x1, y1, x2, y2, fill="white", width=2)


            # Second blade (perpendicular)

            angle_rad2 = angle_rad + math.pi / 2

            x3 = cx + blade_len * math.cos(angle_rad2)

            y3 = cy + blade_len * math.sin(angle_rad2)

            x4 = cx - blade_len * math.cos(angle_rad2)

            y4 = cy - blade_len * math.sin(angle_rad2)

            self.canvas.create_line(x3, y3, x4, y4, fill="white", width=2)


    def draw_missiles(self):

        """Draw and update missiles."""

        missile_speed = 15

        for missile in self.missiles[:]:

            missile["y"] -= missile_speed

            if missile["y"] < 0:

                self.missiles.remove(missile)

                continue

            missile["id"] = self.canvas.create_rectangle(

                missile["x"] - 2, missile["y"] - 10,

                missile["x"] + 2, missile["y"],

                fill="red"

            )


    def animate(self):

        """Main animation loop."""

        if not self.running:

            return


        self.canvas.delete("all")  # Clear frame


        # Update propeller rotation

        self.prop_angle = (self.prop_angle + 20) % 360


        # Draw quadcopter

        self.draw_quadcopter()


        # Draw missiles

        self.draw_missiles()


        # Schedule next frame

        self.root.after(50, self.animate)



# =========================

# Run the App

# =========================

if __name__ == "__main__":

    root = tk.Tk()

    app = QuadcopterApp(root)

    root.mainloop()