Sabtu, 02 Mei 2026

JAVA - Quadcopter Game - Shape Circle

 





/*

 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license

 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template

 */

package quadcopteranimation;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.AffineTransform;


public class QuadcopterSim extends JPanel implements ActionListener, KeyListener {

    private int x = 250, y = 250; // Body position

    private double angle = 0;      // Rotor rotation angle

    private final int speed = 5;   // Movement speed

    private Timer timer;


    public QuadcopterSim() {

        setFocusable(true);

        addKeyListener(this);

        // Timer fires every 16ms (~60 FPS)

        timer = new Timer(16, this);

        timer.start();

    }


    @Override

    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


        int bodyWidth = 35;

        int bodyHeight = 35;

        int spokeLen = 30;


        // 1. Draw the Body (Rectangle)

        g2d.setColor(Color.BLACK);

        g2d.drawOval(x - bodyWidth/2, y - bodyHeight/2, bodyWidth, bodyHeight);


        // 2. Draw Spokes and Rotors

        // Relative positions for the 4 corners

        int[][] offsets = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};

        

        for (int[] pos : offsets) {

            int endX = x + (pos[0] * spokeLen);

            int endY = y + (pos[1] * spokeLen);


            // Draw Spoke

            g2d.setColor(Color.GRAY);

            g2d.drawLine(x, y, endX, endY);


            // Draw Rotating Rotor

            drawRotor(g2d, endX, endY, angle);

        }

    }


    private void drawRotor(Graphics2D g2d, int cx, int cy, double angle) {

        AffineTransform old = g2d.getTransform();

        g2d.translate(cx, cy);

        g2d.rotate(angle);

        

        g2d.setColor(Color.RED);

        // Draw the rotor circle

        g2d.drawOval(-15, -15, 30, 30);

        // Draw a line across the circle to show rotation

        g2d.drawLine(-15, 0, 15, 0);

        

        g2d.setTransform(old);

    }


    @Override

    public void actionPerformed(ActionEvent e) {

        angle += 0.3; // Spin the rotors

        repaint();

    }


    @Override

    public void keyPressed(KeyEvent e) {

        int key = e.getKeyCode();

        if (key == KeyEvent.VK_W) y -= speed;

        if (key == KeyEvent.VK_S) y += speed;

        if (key == KeyEvent.VK_A) x -= speed;

        if (key == KeyEvent.VK_D) x += speed;

    }


    @Override public void keyReleased(KeyEvent e) {}

    @Override public void keyTyped(KeyEvent e) {}


    public static void main(String[] args) {

        JFrame frame = new JFrame("Quadcopter GUI Control");

        frame.add(new QuadcopterSim());

        frame.setSize(600, 600);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setVisible(true);

    }

}

JAVA - Quadcopter Game - Bonus Code

 



/*

 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license

 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template

 */

package quadcopteranimation4;

import javax.swing.*;

import java.awt.*;

import java.awt.geom.*;

import java.util.Random;


public class QuadcopterAnimation4 extends JPanel {

    // Quadcopter position and movement

    private double x = 100, y = 100;

    private double dx = 2, dy = 2; // Velocity

    private double rotationAngle = 0; // Rotor rotation

    

    private final int BODY_WIDTH = 60;

    private final int BODY_HEIGHT = 50;

    private final int ROTOR_SIZE = 30;

    private final Random rand = new Random();


    public QuadcopterAnimation4() {

        // Animation Timer: ~60 FPS (16ms delay)

        Timer timer = new Timer(16, e -> {

            updatePosition();

            rotationAngle += 0.5; // Speed of rotor spin

            repaint();

        });

        timer.start();

    }


    private void updatePosition() {

        x += dx;

        y += dy;


        // Bounce off walls and pick a random new direction

        if (x < 0 || x > getWidth() - BODY_WIDTH - ROTOR_SIZE) {

            dx = -dx + (rand.nextDouble() - 0.5); 

            x = Math.max(0, Math.min(x, getWidth() - BODY_WIDTH));

        }

        if (y < 0 || y > getHeight() - BODY_HEIGHT - ROTOR_SIZE) {

            dy = -dy + (rand.nextDouble() - 0.5);

            y = Math.max(0, Math.min(y, getHeight() - BODY_HEIGHT));

        }

    }


    @Override

    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


        // 1. Draw Body

        g2d.setColor(Color.ORANGE);

        g2d.fillRect((int)x, (int)y, BODY_WIDTH, BODY_HEIGHT);


        // 2. Draw 4 Rotors (Corners)

        drawRotor(g2d, x, y); // Top Left

        drawRotor(g2d, x + BODY_WIDTH, y); // Top Right

        drawRotor(g2d, x, y + BODY_HEIGHT); // Bottom Left

        drawRotor(g2d, x + BODY_WIDTH, y + BODY_HEIGHT); // Bottom Right

    }


    private void drawRotor(Graphics2D g2d, double cx, double cy) {

        g2d.setColor(Color.BLACK);

        // Draw the outer circle

        Ellipse2D circle = new Ellipse2D.Double(cx - ROTOR_SIZE/2.0, cy - ROTOR_SIZE/2.0, ROTOR_SIZE, ROTOR_SIZE);

        g2d.draw(circle);


        // Draw 4 Rotating Spokes

        for (int i = 0; i < 4; i++) {

            double angle = rotationAngle + (i * Math.PI / 2);

            int x2 = (int) (cx + Math.cos(angle) * (ROTOR_SIZE / 2.0));

            int y2 = (int) (cy + Math.sin(angle) * (ROTOR_SIZE / 2.0));

            g2d.drawLine((int)cx, (int)cy, x2, y2);

        }

    }


    public static void main(String[] args) {

        JFrame frame = new JFrame("Quadcopter Random Flight");

        frame.add(new QuadcopterAnimation4());

        frame.setSize(800, 600);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }

}



JAVA - Quadcopter Game 4

 



/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template
 */
package quadcoptergame5;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.Timer;

public class QuadcopterGame5 extends JPanel implements ActionListener, KeyListener {
    Timer timer;
    int quadX = 400, quadY = 300;
    int score = 0;
    boolean gameOver = false;
    double angle = 0; // untuk rotasi baling-baling

    ArrayList<Rectangle> enemies = new ArrayList<>();
    ArrayList<Rectangle> missiles = new ArrayList<>();
    ArrayList<Rectangle> enemyMissiles = new ArrayList<>();
    Random rand = new Random();

    public QuadcopterGame5() {
        setPreferredSize(new Dimension(800, 600));
        setBackground(Color.BLACK);
        timer = new Timer(30, this);
        timer.start();
        addKeyListener(this);
        setFocusable(true);

        // Buat 20 musuh acak
        for (int i = 0; i < 20; i++) {
            enemies.add(new Rectangle(rand.nextInt(700), rand.nextInt(500), 20, 20));
        }

        // Timer untuk musuh menembak setiap 1 detik
        new Timer(1000, e -> {
            if (!enemies.isEmpty()) {
                Rectangle enemy = enemies.get(rand.nextInt(enemies.size()));
                enemyMissiles.add(new Rectangle(enemy.x, enemy.y, 5, 10));
            }
        }).start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (gameOver) {
            g.setColor(Color.RED);
            g.setFont(new Font("Arial", Font.BOLD, 40));
            g.drawString("GAME OVER", 300, 300);
            return;
        }

        // Gambar quadcopter (badan + 4 baling-baling berputar)
        g.setColor(Color.CYAN);
        g.drawOval(quadX, quadY, 30, 30);

        int cx = quadX + 15, cy = quadY + 15;
        int radius = 40;
        for (int i = 0; i < 4; i++) {
            double theta = angle + i * Math.PI / 2;
            int x = (int)(cx + radius * Math.cos(theta));
            int y = (int)(cy + radius * Math.sin(theta));
            //g.drawLine(cx, cy, x, y);
            g.drawOval(x-10, y-10, 20, 20);
        }

        // Gambar musuh
        g.setColor(Color.GREEN);
        for (Rectangle enemy : enemies) {
            g.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
        }

        // Gambar misil quadcopter
        g.setColor(Color.YELLOW);
        for (Rectangle m : missiles) {
            g.fillRect(m.x, m.y, m.width, m.height);
        }

        // Gambar misil musuh
        g.setColor(Color.RED);
        for (Rectangle em : enemyMissiles) {
            g.fillRect(em.x, em.y, em.width, em.height);
        }

        // Skor
        g.setColor(Color.WHITE);
        g.drawString("Score: " + score, 10, 20);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        angle += 0.1; // rotasi baling-baling

        // Update posisi misil quadcopter
        for (Rectangle m : missiles) {
            m.y -= 10;
        }
        missiles.removeIf(m -> m.y < 0);

        // Update posisi musuh (bergerak acak halus)
        for (Rectangle enemy : enemies) {
            enemy.x += rand.nextInt(3) - 1;
            enemy.y += rand.nextInt(3) - 1;
            if (enemy.x < 0) enemy.x = 0;
            if (enemy.y < 0) enemy.y = 0;
            if (enemy.x > 780) enemy.x = 780;
            if (enemy.y > 580) enemy.y = 580;
        }

        // Update misil musuh
        for (Rectangle em : enemyMissiles) {
            em.y += 5;
            if (em.intersects(new Rectangle(quadX, quadY, 30, 30))) {
                gameOver = true;
            }
        }

        // Cek tabrakan misil dengan musuh
        Iterator<Rectangle> itM = missiles.iterator();
        while (itM.hasNext()) {
            Rectangle m = itM.next();
            Iterator<Rectangle> itE = enemies.iterator();
            while (itE.hasNext()) {
                Rectangle enemy = itE.next();
                if (m.intersects(enemy)) {
                    itM.remove();
                    itE.remove();
                    score++;
                    break;
                }
            }
        }

        repaint();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (gameOver) return;
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_W) quadY -= 10;
        if (key == KeyEvent.VK_S) quadY += 10;
        if (key == KeyEvent.VK_A) quadX -= 10;
        if (key == KeyEvent.VK_D) quadX += 10;
        if (key == KeyEvent.VK_SPACE) {
            missiles.add(new Rectangle(quadX+10, quadY, 5, 10));
        }
    }

    @Override public void keyReleased(KeyEvent e) {}
    @Override public void keyTyped(KeyEvent e) {}

    public static void main(String[] args) {
        JFrame frame = new JFrame("Quadcopter Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new QuadcopterGame5());
        frame.pack();
        frame.setVisible(true);
    }
}




JAVA - Quadcopter Game 3

 





/*

 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license

 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template

 */

package quadcoptergame4;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.ArrayList;

import java.util.Random;


public class QuadcopterGame4 extends JPanel implements ActionListener, KeyListener {

    // Game Constants

    private final int WIDTH = 800;

    private final int HEIGHT = 600;

    private Timer timer;

    private int score = 0;

    private boolean gameOver = false;


    // Player Properties

    private double playerX = 400, playerY = 300;

    private double playerSpeed = 5;

    private double rotorAngle = 0;

    

    // Game Entities

    private ArrayList<Point2D.Double> playerMissiles = new ArrayList<>();

    private ArrayList<Enemy> enemies = new ArrayList<>();

    private ArrayList<Point2D.Double> enemyMissiles = new ArrayList<>();

    private Random rand = new Random();


    public QuadcopterGame4() {

        setPreferredSize(new Dimension(WIDTH, HEIGHT));

        setBackground(Color.BLACK);

        setFocusable(true);

        addKeyListener(this);


        // Initialize 20 enemies

        for (int i = 0; i < 20; i++) {

            enemies.add(new Enemy(rand.nextInt(WIDTH), rand.nextInt(HEIGHT)));

        }


        // Game Loop (approx 60 FPS)

        timer = new Timer(16, this);

        timer.start();


        // Enemy firing timer (every 2 seconds)

        Timer fireTimer = new Timer(2000, e -> {

            if (!enemies.isEmpty() && !gameOver) {

                Enemy shooter = enemies.get(rand.nextInt(enemies.size()));

                enemyMissiles.add(new Point2D.Double(shooter.x, shooter.y));

            }

        });

        fireTimer.start();

    }


    @Override

    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


        if (gameOver) {

            g2.setColor(Color.RED);

            g2.setFont(new Font("Arial", Font.BOLD, 50));

            g2.drawString("GAME OVER", WIDTH/2 - 150, HEIGHT/2);

            g2.setFont(new Font("Arial", Font.PLAIN, 20));

            g2.drawString("Final Score: " + score, WIDTH/2 - 60, HEIGHT/2 + 40);

            return;

        }


        // Draw Score

        g2.setColor(Color.WHITE);

        g2.drawString("Score: " + score, 20, 30);


        // Draw Player (Quadcopter)

        drawQuadcopter(g2, playerX, playerY);


        // Draw Player Missiles

        g2.setColor(Color.YELLOW);

        for (Point2D.Double m : playerMissiles) g2.fill(new Ellipse2D.Double(m.x, m.y, 5, 5));


        // Draw Enemies

        g2.setColor(Color.RED);

        for (Enemy e : enemies) g2.fill(new Rectangle2D.Double(e.x, e.y, 20, 20));


        // Draw Enemy Missiles

        g2.setColor(Color.ORANGE);

        for (Point2D.Double m : enemyMissiles) g2.fill(new Ellipse2D.Double(m.x, m.y, 8, 8));

    }


    private void drawQuadcopter(Graphics2D g2, double x, double y) {

        g2.setColor(Color.CYAN);

        rotorAngle += 0.5; // Spin speed


        // Draw 4 Spokes and Rotors

        int[][] offsets = {{-20,-20}, {20,-20}, {-20,20}, {20,20}};

        for (int[] offset : offsets) {

            double rx = x + offset[0];

            double ry = y + offset[1];

            g2.draw(new Line2D.Double(x, y, rx, ry));

            

            // Spinning rotor effect

            AffineTransform old = g2.getTransform();

            g2.translate(rx, ry);

            g2.rotate(rotorAngle);

            g2.draw(new Ellipse2D.Double(-10, -10, 20, 20));

            g2.draw(new Line2D.Double(-10, 0, 10, 0)); // Spoke inside rotor

            g2.setTransform(old);

        }

        g2.fill(new Ellipse2D.Double(x-10, y-10, 20, 20)); // Body

    }


    @Override

    public void actionPerformed(ActionEvent e) {

        if (gameOver) return;


        // Move Player Missiles

        for (int i = 0; i < playerMissiles.size(); i++) {

            playerMissiles.get(i).y -= 10;

            if (playerMissiles.get(i).y < 0) playerMissiles.remove(i);

        }


        // Move Enemy Missiles

        for (int i = 0; i < enemyMissiles.size(); i++) {

            enemyMissiles.get(i).y += 5;

            // Check Collision with Player

            if (enemyMissiles.get(i).distance(playerX, playerY) < 20) gameOver = true;

            if (enemyMissiles.get(i).y > HEIGHT) enemyMissiles.remove(i);

        }


        // Move Enemies and Check Collision

        for (int i = 0; i < enemies.size(); i++) {

            Enemy en = enemies.get(i);

            en.update();


            // Check Player Missile hit Enemy

            for (int j = 0; j < playerMissiles.size(); j++) {

                if (playerMissiles.get(j).distance(en.x, en.y) < 20) {

                    enemies.remove(i);

                    playerMissiles.remove(j);

                    score += 10;

                    break;

                }

            }

        }

        repaint();

    }


    // Controls

    @Override

    public void keyPressed(KeyEvent e) {

        int key = e.getKeyCode();

        if (key == KeyEvent.VK_W) playerY -= playerSpeed;

        if (key == KeyEvent.VK_S) playerY += playerSpeed;

        if (key == KeyEvent.VK_A) playerX -= playerSpeed;

        if (key == KeyEvent.VK_D) playerX += playerSpeed;

        if (key == KeyEvent.VK_SPACE) playerMissiles.add(new Point2D.Double(playerX, playerY));

    }


    // Inner class for Enemy behavior

    class Enemy {

        double x, y, dx, dy;

        Enemy(double x, double y) {

            this.x = x; this.y = y;

            this.dx = (rand.nextDouble() - 0.5) * 4;

            this.dy = (rand.nextDouble() - 0.5) * 4;

        }

        void update() {

            x += dx; y += dy;

            if (x < 0 || x > WIDTH) dx *= -1;

            if (y < 0 || y > HEIGHT) dy *= -1;

        }

    }


    // Boilers

    @Override public void keyReleased(KeyEvent e) {}

    @Override public void keyTyped(KeyEvent e) {}


    public static void main(String[] args) {

        JFrame frame = new JFrame("Quadcopter Combat");

        QuadcopterGame4 game = new QuadcopterGame4();

        frame.add(game);

        frame.pack();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }

}

JAVA - Quadcopter Game 2

 




/*

 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license

 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template

 */

package quadcoptergame;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.Set;


public class QuadcopterGame extends JPanel implements ActionListener {

    // Positioning and Physics

    private double x = 300, y = 300;

    private double angle = 0;

    private final double speed = 4.0;

    private final double rotationSpeed = 0.15;

    

    // Missile Management

    private class Missile {

        double mx, my;

        Missile(double x, double y) { this.mx = x; this.my = y; }

        void update() { my -= 10; } // Move upward

    }

    private ArrayList<Missile> missiles = new ArrayList<>();

    

    // Key Handling

    private final Set<Integer> activeKeys = new HashSet<>();

    private Timer timer;


    public QuadcopterGame() {

        setFocusable(true);

        // Standard Timer for 60 FPS (approx 16ms delay)

        timer = new Timer(16, this);

        timer.start();


        addKeyListener(new KeyAdapter() {

            @Override

            public void keyPressed(KeyEvent e) { activeKeys.add(e.getKeyCode()); }

            @Override

            public void keyReleased(KeyEvent e) { activeKeys.remove(e.getKeyCode()); }

        });

    }


    private void updateLogic() {

        if (activeKeys.contains(KeyEvent.VK_W)) y -= speed;

        if (activeKeys.contains(KeyEvent.VK_S)) y += speed;

        if (activeKeys.contains(KeyEvent.VK_A)) x -= speed;

        if (activeKeys.contains(KeyEvent.VK_D)) x += speed;

        

        if (activeKeys.contains(KeyEvent.VK_SPACE)) {

            missiles.add(new Missile(x + 20, y));

            activeKeys.remove(KeyEvent.VK_SPACE); // Fire once per press

        }


        // Update spokes rotation and missiles

        angle += rotationSpeed;

        missiles.forEach(Missile::update);

        missiles.removeIf(m -> m.my < 0); // Clean up off-screen missiles

    }


    @Override

    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


        // Draw Missiles

        g2d.setColor(Color.RED);

        for (Missile m : missiles) g2d.fillRect((int)m.mx, (int)m.my, 5, 15);


        // Draw Quadcopter Body

        g2d.setColor(Color.ORANGE);

        g2d.fillRect((int)x, (int)y, 40, 40);


        // Draw 4 Rotating Spokes

        g2d.setColor(Color.BLACK);

        drawRotor(g2d, x, y);           // Top Left

        drawRotor(g2d, x + 40, y);      // Top Right

        drawRotor(g2d, x, y + 40);      // Bottom Left

        drawRotor(g2d, x + 40, y + 40); // Bottom Right

    }


    private void drawRotor(Graphics2D g2d, double rx, double ry) {

        AffineTransform old = g2d.getTransform();

        g2d.translate(rx, ry);

        g2d.rotate(angle);

        g2d.draw(new Line2D.Double(-15, 0, 15, 0));

        g2d.draw(new Line2D.Double(0, -15, 0, 15));

        g2d.drawOval(-15, -15, 30, 30);

        g2d.setTransform(old);

    }


    @Override

    public void actionPerformed(ActionEvent e) {

        updateLogic();

        repaint();

    }


    public static void main(String[] args) {

        JFrame frame = new JFrame("Java Quadcopter Sim");

        frame.add(new QuadcopterGame());

        frame.setSize(800, 600);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }

}

JAVA - Quadcopter Game 1






/*

 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license

 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template

 */

package quadcoptergui;

import javax.swing.*;

import java.awt.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

 

public class QuadcopterAnimation extends JPanel implements ActionListener {

 

    private double rotationAngle = 0;

    private final int ROTOR_RADIUS = 30;

    private final int BODY_WIDTH = 100;

    private final int BODY_HEIGHT = 100;

 

    public QuadcopterAnimation() {

        // Timer fires every 20ms (~50 FPS)

        Timer timer = new Timer(20, this);

        timer.start();

    }

 

    @Override

    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

       

        // Enable Antialiasing for smooth lines

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

 

        int centerX = getWidth() / 2;

        int centerY = getHeight() / 2;

 

        // 1. Draw Main Body (Rectangle)

        g2d.setColor(Color.ORANGE);

        g2d.fillRect(centerX - BODY_WIDTH / 2, centerY - BODY_HEIGHT / 2, BODY_WIDTH, BODY_HEIGHT);

 

        // 2. Draw 4 Rotors

        drawRotor(g2d, centerX - 50, centerY - 50); // Top Left

        drawRotor(g2d, centerX + 50, centerY - 50); // Top Right

        drawRotor(g2d, centerX - 50, centerY + 50); // Bottom Left

        drawRotor(g2d, centerX + 50, centerY + 50); // Bottom Right

    }

 

    private void drawRotor(Graphics2D g2d, int x, int y) {

        g2d.setColor(Color.BLACK);

        // Draw the outer circle

        g2d.drawOval(x - ROTOR_RADIUS, y - ROTOR_RADIUS, ROTOR_RADIUS * 2, ROTOR_RADIUS * 2);

 

        // Draw 4 Spokes

        for (int i = 0; i < 4; i++) {

            // Space spokes 90 degrees apart (PI/2 radians)

            double currentSpokeAngle = rotationAngle + (i * Math.PI / 2);

           

            int endX = (int) (x + Math.cos(currentSpokeAngle) * ROTOR_RADIUS);

            int endY = (int) (y + Math.sin(currentSpokeAngle) * ROTOR_RADIUS);

           

            g2d.drawLine(x, y, endX, endY);

        }

    }

 

    @Override

    public void actionPerformed(ActionEvent e) {

        // Increase angle for rotation

        rotationAngle += 0.15;

        repaint(); // Redraw the panel

    }

 

    public static void main(String[] args) {

        JFrame frame = new JFrame("Quadcopter GUI Animation");

        QuadcopterAnimation panel = new QuadcopterAnimation();

       

        frame.add(panel);

        frame.setSize(400, 400);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }