Rayhan Aurelia Pramana Rijal-EAS PBO A

 Nama : Rayhan Aurelia Pramana Rijal

 NRP   : 5025231237

Kelas   : PBO A

1. Apa yang dimaksud dengan Package Library dalam Java. Jelaskan kegunaan dan contoh penggunaannya dalam pemrograman?

Package Library (Pustaka Paket) adalah suatu mekanisme untuk mengorganisasi dan mengelompokkan kelas-kelas dan antarmuka terkait ke dalam sebuah namespace atau direktori tertentu. 

Package Library dalam Java adalah:

  • Kumpulan kelas-kelas dan antarmuka yang saling terkait
  • Cara untuk mengatur dan menstrukturkan kode program
  • Mekanisme untuk menghindari konflik nama pada kelas
  • Alat untuk membuat kode lebih terorganisir dan mudah dikelola

Kegunaan Package Library

  1. Pengorganisasian Kode
    • Membantu mengelompokkan kelas-kelas yang memiliki fungsi serupa
    • Membuat struktur proyek menjadi lebih sistematis dan teratur
    • Memudahkan pengembang dalam menemukan dan menggunakan kelas
  2. Kontrol Akses
    • Memungkinkan pembatasan akses antara kelas
    • Mengatur visibilitas method dan variabel
    • Melindungi kode dari akses yang tidak diinginkan
  3. Menghindari Konflik Nama
    • Dua kelas dengan nama sama dapat ada dalam package berbeda
    • Mencegah tabrakan nama antar kelas dari library yang berbeda
Contoh Penggunaan pada kode final project: 

javax.swing Package
  • Digunakan untuk membuat antarmuka grafis (GUI)
  • Contoh dalam kode:
    import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer;
  • JFrame: Digunakan untuk membuat jendela utama game
  • JPanel: Digunakan untuk membuat papan permainan (Board)
  • Timer: Digunakan untuk mengatur siklus permainan dan pembaruan berkala
java.awt.event Package
  • Menyediakan antarmuka dan kelas untuk menangani event
  • Contoh dalam kode:
    import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent;
  • ActionListener dan ActionEvent: Untuk menangani event timer
  • KeyAdapter dan KeyEvent: Untuk menangani input keyboard

2. Buatlah Rancangan Aplikasi yang diambil dalam Final Project !

Arsitektur Aplikasi Breakout Game    

Struktur Kelas Utama

  1. Main Class: Breakout
    • Kelas utama yang menginisialisasi jendela permainan
    • Mengatur pengaturan dasar JFrame
    • Memulai aplikasi
  2. Board (Papan Permainan)
    • Mengatur logika permainan utama
    • Mengelola siklus permainan
    • Mengatur collision detection
    • Menggambar objek-objek permainan
    • Mengatur state permainan (score, nyawa, dll)

Komponen Sprite

  1. Sprite (Abstract Class)
    • Kelas dasar untuk semua objek dalam permainan
    • Menyediakan properti dasar: posisi, ukuran, warna
    • Metode abstrak untuk menggambar
  2. Ball (Extends Sprite)
    • Mengatur pergerakan bola
    • Menghitung pantulan dan kecepatan
    • Mengatur ulang posisi bola
  3. Paddle (Extends Sprite)
    • Mengatur pergerakan paddle
    • Menangani input keyboard
    • Membatasi pergerakan dalam window
  4. Brick (Extends Sprite)
    • Menyimpan informasi brick (warna, kekuatan)
    • Mengatur skor dan kerusakan brick

Antarmuka Pendukung

  1. Commons (Interface)
    • Menyimpan konstanta umum
    • Pengaturan dimensi
    • Warna default
    • Pengaturan awal
stateDiagram-v2
    [*] --> Inisialisasi : Konstruktor Breakout
    Inisialisasi --> PapanPermainan : Buat Board
    PapanPermainan --> InisialisasiObjek : Buat Ball, Paddle, Bricks
    InisialisasiObjek --> SiklusPermainan : Mulai Timer
    SiklusPermainan --> Gerak : Pindahkan Bola dan Paddle
    Gerak --> DeteksiTabrakan : Periksa Collision
    DeteksiTabrakan --> UpdateSkor : Jika Brick Hancur
    DeteksiTabrakan --> KurangiNyawa : Jika Bola Jatuh
    KurangiNyawa --> CekNyawa : Periksa Sisa Nyawa
    CekNyawa --> GameOver : Nyawa Habis
    CekNyawa --> SiklusPermainan : Lanjutkan
    UpdateSkor --> SiklusPermainan
    GameOver --> [*]





3. Deskripsikan kegunaan dan ruang lingkup aplikasi

Ruang Lingkup Aplikasi

1. Target Pengguna

  • Anak-anak dan remaja (usia 8-16 tahun)
  • Pecinta game retro dan arcade
  • Pemain yang menyukai game refleks dan strategi sederhana
  • Pendidik yang ingin menggunakan game untuk mengembangkan koordinasi mata-tangan

2. Tujuan Aplikasi

  • Hiburan interaktif
  • Pengembangan refleks dan koordinasi
  • Melatih konsentrasi dan kecepatan reaksi
  • Memberikan tantangan bertingkat melalui mekanisme permainan

Fitur Utama

Mekanika Permainan

  • Kontrol paddle menggunakan tombol kiri/kanan
  • Memantulkan bola untuk menghancurkan brick
  • Sistem nyawa dengan 3 kesempatan
  • Peningkatan kesulitan melalui:
    • Kecepatan bola yang meningkat
    • Pola brick yang berubah secara acak
    • Variasi warna dan kekuatan brick

Fitur Unik

  • Randomisasi pola brick setiap 20 detik
  • Empat pola brick berbeda:
    1. Warna acak
    2. Papan catur
    3. Celah acak
    4. Pola gelombang
  • Sistem skor berbasis kekuatan brick
  • Efek visual gradien pada brick

Arsitektur Teknis

  • Berbasis Java Swing
  • Menggunakan konsep Object-Oriented Programming
  • Arsitektur modular dengan pemisahan tanggung jawab kelas
  • Performa tinggi dengan render grafis efisien
4. Implementasikan Aplikasi yang telah didesain dengan menggunakan Pemrograman Berbasis Obyek Java !

Ball.java = 
import java.awt.Color;
import java.awt.Graphics2D;
// Di wariskan dari Sprite --> abstrak
// dasar yang mendefinisikan properti (warna, widh, height, posisi(x,y))
public class Ball extends Sprite {
    private double dx;
    private double dy;
    private static final double INITIAL_SPEED = 3.0;
    private static final double MAX_SPEED = 7.0;
    private static final Color BALL_COLOR = Color.WHITE;
   
    public Ball() {
        super(Commons.INIT_BALL_X, Commons.INIT_BALL_Y,
              Commons.BALL_SIZE, Commons.BALL_SIZE, BALL_COLOR);
        initBall(); // metode khusus untuk mengatur kecepatan bola
    } // memanggil konstraktor superclass () untuk (inisialisasi properti dasar posisi, weight, height, x, y)
   
    private void initBall() {
        double angle = Math.toRadians(45 + Math.random() * 90); // Random angle between 45 and 135 degrees
        dx = INITIAL_SPEED * Math.cos(angle); // menggunakan rumus segitiga untuk menghitung kecepatan bola
        dy = -INITIAL_SPEED * Math.sin(angle);
    }
   
    public void move() {
        x += dx;
        y += dy; // jika bola berpantul ke kiri dan kanan makan akan dipantulkan balik
       
        // Wall collisions
        if (x <= 0 || x >= Commons.WIDTH - width) {
            dx = -dx;
        }
       
        if (y <= 0) {
            dy = -dy; // jika bola berpantul ke atas makan akan dipantulkan balik
        }
    }
   
    public void reverseY() {
        dy = -dy;
        increaseSpeed();
    }
     // Membalik arah bola pada sumbu y atau x, biasanya saat bertabrakan dengan objek seperti paddle atau brick.
    public void reverseX() {
        dx = -dx;
        increaseSpeed(); // menambah kecepatan bola
    }
   
    private void increaseSpeed() {
        double speed = Math.sqrt(dx * dx + dy * dy);
        if (speed < MAX_SPEED) {
            dx *= 1.05;
            dy *= 1.05; // menambah kecepatan bola
        }
    }
   
    @Override
    public void draw(Graphics2D g2d) {
        g2d.setColor(color); // berguna untuk menggambar bola dengan x,y , weigth, height
        g2d.fillOval(x, y, width, height);
    }
   
    public void reset() {
        x = Commons.INIT_BALL_X;
        y = Commons.INIT_BALL_Y; // mengembalikan bola ke posisi awal , dan kecepatan diatur ulang
        initBall();
    }
    public void setX(int x) {
        this.x = x;
    }
// mengatur bola secara langsung
    public void setY(int y) {
        this.y = y;
    }
   
}


Board.java =
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
public class Board extends JPanel {
    private Timer timer;
    private Timer randomizeTimer;
    private Ball ball;
    private Paddle paddle;
    private Brick[][] bricks;
    private boolean inGame = true;
    private int score = 0;
    private int lives = 3;
    private Random random = new Random();
    private static final int RANDOMIZE_DELAY = 20000; // 20 seconds
    private static final Color[] BRICK_PATTERNS = {
        new Color(255, 0, 0),    // Red
        new Color(0, 255, 0),    // Green
        new Color(0, 0, 255),    // Blue
        new Color(255, 255, 0),  // Yellow
        new Color(255, 0, 255),  // Magenta
        new Color(0, 255, 255),  // Cyan
        new Color(255, 165, 0),  // Orange
        new Color(128, 0, 128)   // Purple
    };
   
    public Board() {
        initBoard();
        setupRandomizeTimer();
    }
   
    private void initBoard() {
        setBackground(Color.BLACK);
        setFocusable(true);
        setPreferredSize(new Dimension(Commons.WIDTH, Commons.HEIGHT));
        addKeyListener(new TAdapter());
        gameInit();
    }
    private void setupRandomizeTimer() {
        randomizeTimer = new Timer(RANDOMIZE_DELAY, e -> {
            if (inGame) {
                randomizeCurrentBricks();
            }
        });
        randomizeTimer.start();
    }
   
    private void gameInit() {
        bricks = new Brick[Commons.N_OF_ROWS][Commons.N_OF_BRICKS_PER_ROW];
        ball = new Ball();
        paddle = new Paddle();
        initBricks();
       
        timer = new Timer(Commons.PERIOD, new GameCycle());
        timer.start();
    }
   
    private void initBricks() {
        int patternType = random.nextInt(4);
       
        switch (patternType) {
            case 0:
                createRandomColorPattern();
                break;
            case 1:
                createCheckerboardPattern();
                break;
            case 2:
                createRandomGapsPattern();
                break;
            case 3:
                createWavePattern();
                break;
        }
    }
    private void createRandomColorPattern() {
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                Color randomColor = BRICK_PATTERNS[random.nextInt(BRICK_PATTERNS.length)];
                int x = j * (Commons.BRICK_WIDTH + 1) + 30;
                int y = i * (Commons.BRICK_HEIGHT + 1) + 50;
                bricks[i][j] = new Brick(x, y, randomColor, random.nextInt(3) + 1);
            }
        }
    }
    private void createCheckerboardPattern() {
        Color color1 = BRICK_PATTERNS[random.nextInt(BRICK_PATTERNS.length)];
        Color color2 = BRICK_PATTERNS[random.nextInt(BRICK_PATTERNS.length)];
       
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                int x = j * (Commons.BRICK_WIDTH + 1) + 30;
                int y = i * (Commons.BRICK_HEIGHT + 1) + 50;
                if ((i + j) % 2 == 0) {
                    bricks[i][j] = new Brick(x, y, color1, 1);
                } else {
                    bricks[i][j] = new Brick(x, y, color2, 2);
                }
            }
        }
    }
    private void createRandomGapsPattern() {
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                int x = j * (Commons.BRICK_WIDTH + 1) + 30;
                int y = i * (Commons.BRICK_HEIGHT + 1) + 50;
                if (random.nextFloat() < 0.8f) {
                    Color randomColor = BRICK_PATTERNS[random.nextInt(BRICK_PATTERNS.length)];
                    bricks[i][j] = new Brick(x, y, randomColor, 1);
                } else {
                    bricks[i][j] = new Brick(x, y, Color.BLACK, 0);
                    bricks[i][j].setDestroyed(true);
                }
            }
        }
    }
    private void createWavePattern() {
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                double wave = Math.sin(j * 0.5) * 20;
                int x = j * (Commons.BRICK_WIDTH + 1) + 30;
                int y = i * (Commons.BRICK_HEIGHT + 1) + 50 + (int)wave;
               
                int colorIndex = (i + (int)(wave / 20)) % BRICK_PATTERNS.length;
                if (colorIndex < 0) colorIndex += BRICK_PATTERNS.length;
               
                bricks[i][j] = new Brick(x, y, BRICK_PATTERNS[colorIndex],
                              Math.abs((int)(wave / 10)) + 1);
            }
        }
    }
    private void randomizeCurrentBricks() {
        int remainingBricks = 0;
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                if (!bricks[i][j].isDestroyed()) {
                    remainingBricks++;
                }
            }
        }
        if (remainingBricks > 0) {
            initBricks();
            int bricksToDestroy = (Commons.N_OF_ROWS * Commons.N_OF_BRICKS_PER_ROW) - remainingBricks;
            while (bricksToDestroy > 0) {
                int i = random.nextInt(Commons.N_OF_ROWS);
                int j = random.nextInt(Commons.N_OF_BRICKS_PER_ROW);
                if (!bricks[i][j].isDestroyed()) {
                    bricks[i][j].setDestroyed(true);
                    bricksToDestroy--;
                }
            }
        }
    }
   
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
       
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
       
        if (inGame) {
            drawObjects(g2d);
        } else {
            gameFinished(g2d);
        }
    }
   
    private void drawObjects(Graphics2D g2d) {
        ball.draw(g2d);
        paddle.draw(g2d);
       
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                if (!bricks[i][j].isDestroyed()) {
                    bricks[i][j].draw(g2d);
                }
            }
        }
       
        drawScore(g2d);
        drawLives(g2d);
    }
   
    private void drawScore(Graphics2D g2d) {
        String scoreText = "Score: " + score;
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("Verdana", Font.BOLD, 16));
        g2d.drawString(scoreText, 10, 20);
    }
   
    private void drawLives(Graphics2D g2d) {
        String livesText = "Lives: " + lives;
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("Verdana", Font.BOLD, 16));
        g2d.drawString(livesText, Commons.WIDTH - 100, 20);
    }
   
    private void gameFinished(Graphics2D g2d) {
        String message = "Game Over - Score: " + score;
        if (victory()) {
            message = "Victory! Score: " + score;
        }
       
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("Verdana", Font.BOLD, 24));
        FontMetrics fm = g2d.getFontMetrics();
        int msgWidth = fm.stringWidth(message);
        g2d.drawString(message, (Commons.WIDTH - msgWidth) / 2, Commons.HEIGHT / 2);
       
        String restartMsg = "Press SPACE to play again";
        g2d.setFont(new Font("Verdana", Font.PLAIN, 18));
        fm = g2d.getFontMetrics();
        msgWidth = fm.stringWidth(restartMsg);
        g2d.drawString(restartMsg, (Commons.WIDTH - msgWidth) / 2, Commons.HEIGHT / 2 + 30);
    }
   
    private boolean victory() {
        for (int i = 0; i < Commons.N_OF_ROWS; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW; j++) {
                if (!bricks[i][j].isDestroyed()) {
                    return false;
                }
            }
        }
        return true;
    }
   
    private class TAdapter extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            paddle.keyPressed(e);
           
            if (!inGame && e.getKeyCode() == KeyEvent.VK_SPACE) {
                restartGame();
            }
        }
       
        @Override
        public void keyReleased(KeyEvent e) {
            paddle.keyReleased(e);
        }
    }
   
    private class GameCycle implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            doGameCycle();
        }
    }
   
    private void doGameCycle() {
        ball.move();
        paddle.move();
        checkCollision();
        repaint();
    }
   
    private void checkCollision() {
        if (ball.getY() > Commons.BOTTOM_EDGE) {
            lives--;
            if (lives <= 0) {
                stopGame();
            } else {
                ball.reset();
                paddle.reset();
                initBricks();
                randomizeTimer.restart();
            }
            return;
        }
       
        // Paddle collision
        if (ball.getBounds().intersects(paddle.getBounds())) {
            // Ensure the ball doesn't get stuck in the paddle
            ball.setY(paddle.getY() - ball.getHeight());
           
            // Calculate angle based on where ball hits the paddle
            double relativeIntersectX = (paddle.getX() + (paddle.getWidth() / 2.0)) -
                                      (ball.getX() + (ball.getWidth() / 2.0));
            double normalizedRelativeIntersectionX = relativeIntersectX / (paddle.getWidth() / 2.0);
           
            ball.reverseY();
        }
       
        // Brick collision
        boolean collisionDetected = false;
       
        for (int i = 0; i < Commons.N_OF_ROWS && !collisionDetected; i++) {
            for (int j = 0; j < Commons.N_OF_BRICKS_PER_ROW && !collisionDetected; j++) {
                if (!bricks[i][j].isDestroyed() && ball.getBounds().intersects(bricks[i][j].getBounds())) {
                    // Get the collision bounds
                    int ballLeft = ball.getX();
                    int ballRight = ballLeft + ball.getWidth();
                    int ballTop = ball.getY();
                    int ballBottom = ballTop + ball.getHeight();
                   
                    int brickLeft = bricks[i][j].getX();
                    int brickRight = brickLeft + bricks[i][j].getWidth();
                    int brickTop = bricks[i][j].getY();
                    int brickBottom = brickTop + bricks[i][j].getHeight();
                   
                    // Calculate overlap on each side
                    int overlapLeft = ballRight - brickLeft;
                    int overlapRight = brickRight - ballLeft;
                    int overlapTop = ballBottom - brickTop;
                    int overlapBottom = brickBottom - ballTop;
                   
                    // Find the smallest overlap
                    int minOverlap = Math.min(Math.min(overlapLeft, overlapRight),
                                            Math.min(overlapTop, overlapBottom));
                   
                    // Adjust ball position and direction based on collision side
                    if (minOverlap == overlapLeft || minOverlap == overlapRight) {
                        ball.reverseX();
                        // Adjust x position to prevent sticking
                        if (minOverlap == overlapLeft) {
                            ball.setX(brickLeft - ball.getWidth());
                        } else {
                            ball.setX(brickRight);
                        }
                    } else {
                        ball.reverseY();
                        // Adjust y position to prevent sticking
                        if (minOverlap == overlapTop) {
                            ball.setY(brickTop - ball.getHeight());
                        } else {
                            ball.setY(brickBottom);
                        }
                    }
                   
                    // Handle brick hit
                    if (bricks[i][j].hit()) {
                        score += bricks[i][j].getScore();
                    }
                   
                    collisionDetected = true;
                    break;
                }
            }
        }
    }
   
    private void stopGame() {
        inGame = false;
        timer.stop();
        randomizeTimer.stop();
    }
   
    private void restartGame() {
        score = 0;
        lives = 3;
        inGame = true;
       
        ball.reset();
        paddle.reset();
        initBricks();
       
        timer.start();
        randomizeTimer.restart();
        requestFocus();
    }
}


Breakout.java =
import javax.swing.JFrame;
import java.awt.EventQueue;
public class Breakout extends JFrame {
    public Breakout() {
        initUI();
    }
    private void initUI() {
        add(new Board());
        setTitle("Breakout");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);
        pack();
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            var game = new Breakout();
            game.setVisible(true);
        });
    }
}


Brick.java =
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GradientPaint;
public class Brick extends Sprite {
    private int strength;
    private int score;
   
    public Brick(int x, int y, Color color, int strength) {
        super(x, y, Commons.BRICK_WIDTH, Commons.BRICK_HEIGHT, color);
        this.strength = strength;
        this.score = strength * 10; // Score based on brick strength
    }
   
    @Override
    public void draw(Graphics2D g2d) {
        if (!destroyed) {
            // Create gradient effect
            Color lighterColor = new Color(
                Math.min(color.getRed() + 50, 255),
                Math.min(color.getGreen() + 50, 255),
                Math.min(color.getBlue() + 50, 255)
            );
           
            // Create vertical gradient from lighter to normal color
            GradientPaint gradient = new GradientPaint(
                x, y, lighterColor,
                x, y + height, color
            );
           
            // Fill brick with gradient
            g2d.setPaint(gradient);
            g2d.fillRect(x, y, width, height);
           
            // Draw strength indicator for bricks with strength > 1
            if (strength > 1) {
                g2d.setColor(Color.WHITE);
                String str = String.valueOf(strength);
                // Center the text
                int stringWidth = g2d.getFontMetrics().stringWidth(str);
                g2d.drawString(str,
                             x + (width - stringWidth) / 2,
                             y + (height + 10) / 2);
            }
           
            // Add a darker border for definition
            g2d.setColor(color.darker());
            g2d.drawRect(x, y, width, height);
        }
    }
   
    public boolean hit() {
        strength--;
        if (strength <= 0) {
            destroyed = true;
            return true; // Returns true if brick is destroyed
        }
        return false;
    }
   
    public int getScore() {
        return score;
    }
   
    public int getStrength() {
        return strength;
    }
   
    public void setStrength(int strength) {
        this.strength = strength;
        this.score = strength * 10;
    }
}



Commons.java =
public interface Commons { //antarmuka Java bernama Commons.
    // Window settings
    int WIDTH = 800;
    int HEIGHT = 600;
    int BOTTOM_EDGE = HEIGHT - 10;
   
    // Game settings
    int PERIOD = 10;  // Timer delay in milliseconds // refresh game.
    int N_OF_BRICKS_PER_ROW = 10; // Jumlah balok dalam satu baris (10 balok).
    int N_OF_ROWS = 5; //  Jumlah baris balok (5 baris).
    int N_OF_BRICKS = N_OF_BRICKS_PER_ROW * N_OF_ROWS;
   
    // Initial positions
    int INIT_PADDLE_X = WIDTH / 2 - 50; // Posisi horizontal awal papan adalah di tengah jendela (WIDTH / 2 - 50).
    int INIT_PADDLE_Y = BOTTOM_EDGE - 20; //Posisi vertikal papan adalah sedikit di atas bagian bawah jendela
    int INIT_BALL_X = WIDTH / 2 - 5;
    int INIT_BALL_Y = INIT_PADDLE_Y - 20;
   
    // Dimensions
    int BRICK_WIDTH = 70;
    int BRICK_HEIGHT = 20;
    int PADDLE_WIDTH = 100;
    int PADDLE_HEIGHT = 10;
    int BALL_SIZE = 10;
   
    // Colors (for fallback shapes)
    java.awt.Color[] BRICK_COLORS = {
        new java.awt.Color(200, 0, 0),    // Red
        new java.awt.Color(0, 200, 0),    // Green
        new java.awt.Color(0, 0, 200),    // Blue // warna untuk bricks
        new java.awt.Color(200, 200, 0),  // Yellow
        new java.awt.Color(200, 0, 200)   // Purple
    };
}


Paddle.java =
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
public class Paddle extends Sprite {
    private int dx;
    private static final int PADDLE_SPEED = 5;
    private static final Color PADDLE_COLOR = new Color(0, 150, 255);
   
    public Paddle() {
        super(Commons.INIT_PADDLE_X, Commons.INIT_PADDLE_Y,
              Commons.PADDLE_WIDTH, Commons.PADDLE_HEIGHT, PADDLE_COLOR);
    }
   
    public void move() {
        x += dx;
       
        if (x <= 0) {
            x = 0;
        }
       
        if (x >= Commons.WIDTH - width) {
            x = Commons.WIDTH - width;
        }
    }
   
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
       
        if (key == KeyEvent.VK_LEFT) {
        }
        // Kiri (KeyEvent.VK_LEFT): Kecepatan paddle diatur negatif sehingga bergerak ke kiri.
// Kanan (KeyEvent.VK_RIGHT): Kecepatan paddle diatur positif sehingga bergerak ke kanan.
        if (key == KeyEvent.VK_RIGHT) {
            dx = PADDLE_SPEED;
        }
    }
   
    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
       
        if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT) {
            dx = 0;
        } // kalo dilespats tomboolnya maka diatur ke 0
    }
   
    @Override
    public void draw(Graphics2D g2d) {
        g2d.setColor(color);
        g2d.fillRect(x, y, width, height);
       
        // Add highlight effect
        g2d.setColor(color.brighter());
        g2d.fillRect(x, y, width, 3);
    }
   
    public void reset() {
        x = Commons.INIT_PADDLE_X;
        y = Commons.INIT_PADDLE_Y; // reset
        dx = 0;
    }
}



Sprite.java =
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;

public abstract class Sprite {
    protected int x;
    protected int y;
    protected int width;
    protected int height;
    protected Image image;
    protected boolean destroyed;
    protected Color color;

    public Sprite(int x, int y, int width, int height, Color color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
        this.destroyed = false;
    }

    public abstract void draw(Graphics2D g2d);
   
    public Rectangle getBounds() {
        return new Rectangle(x, y, width, height);
    }

    public int getX() { return x; }
    public int getY() { return y; }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
    public boolean isDestroyed() { return destroyed; }
    public void setDestroyed(boolean destroyed) { this.destroyed = destroyed; }
}


Komentar

Postingan populer dari blog ini

Tugas Membuat Profil Diri

Ticket Machine

5025231327 - Rayhan Aurelia Pramana Rijal - EAS PWEB E