Skip to main content

Java Pong Game

Postingan kali ini membahas sebuah game bernama Pong. Game Pong merupakan salah satu permainan tenis meja yang ditampilkan dalam bentuk grafik dua dimensi. Gameplaynya cukup sederhana, di mana terdapat dua paddle dan satu bola yang tujuannya untuk mengalahkan lawan. Seorang pemain mendapat satu poin saat mencetak gol.

Kali ini, game pong ini dibuat dengan menggunakan bahasa pemrograman Java dan menggunakan BlueJ IDE. Game Pong ini terdiri dari kelas-kelas berikut:

  • Ball.java
  • Paddle.java
  • Pong.java
  • Renderer.java

Berikut ini adalah gambar diagram kelas dari Pong Game.


The Ball Class

Kelas Ball adalah kelas untuk mengatur bola dalam permainan Pong ini. Di kelas ini, ukuran bola, kecepatan bola, warna bola, dan sebagainya bisa disesuaikan.

Implementation of The Ball Class

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

/**
 * Kelas Ball adalah kelas untuk mengatur bola dalam permainan Pong ini. Di
 * kelas ini, ukuran bola, kecepatan bola, warna bola, dan sebagainya bisa
 * disesuaikan.
 *
 * @author Ramadhan Arif Hardijansyah
 * @version 0.1 January 6, 2021
 */
public class Ball
{
    // instance variables
    public int x, y, width = 75, height = 75;
    // prev 25
    public int motionX, motionY;
    public Random random;
    private Pong pong;
    public int amountOfHits;

    /**
     * Constructor for objects of class Ball
     */
    public Ball(Pong pong)
    {
    this.pong = pong;

    this.random = new Random();

    spawn();
    }

    public void update(Paddle paddle1, Paddle paddle2)
    {
        int speed = 1;
        // prev 5
    
        this.x += motionX * speed;
        this.y += motionY * speed;
    
        if (this.y + height - motionY > pong.height || this.y + motionY < 0)
        {
            if (this.motionY < 0)
            {
                this.y = 0;
                this.motionY = random.nextInt(4);
    
                if (motionY == 0)
                {
                    motionY = 1;
                }
            }
            else
            {
                this.motionY = -random.nextInt(4);
                this.y = pong.height - height;
    
                if (motionY == 0)
                {
                    motionY = -1;
                }
            }
        }
    
        if (checkCollision(paddle1) == 1)
        {
            this.motionX = 1 + (amountOfHits / 5);
            this.motionY = -2 + random.nextInt(4);
    
            if (motionY == 0)
            {
                motionY = 1;
            }
    
            amountOfHits++;
        }
        else if (checkCollision(paddle2) == 1)
        {
            this.motionX = -1 - (amountOfHits / 5);
            this.motionY = -2 + random.nextInt(4);
    
            if (motionY == 0)
            {
                motionY = 1;
            }
    
            amountOfHits++;
        }
    
        if (checkCollision(paddle1) == 2)
        {
            paddle2.score++;
            spawn();
        }
        else if (checkCollision(paddle2) == 2)
        {
            paddle1.score++;
            spawn();
        }
    }
    
    public void spawn()
    {
        this.amountOfHits = 0;
        this.x = pong.width / 2 - this.width / 2;
        this.y = pong.height / 2 - this.height / 2;
    
        this.motionY = -2 + random.nextInt(4);
    
        if (motionY == 0)
        {
            motionY = 1;
        }
    
        if (random.nextBoolean())
        {
            motionX = 1;
        }
        else
        {
            motionX = -1;
        }
    }
    
    public int checkCollision(Paddle paddle)
    {
        if (this.x < paddle.x + paddle.width && this.x + width > paddle.x && this.y < paddle.y + paddle.height && this.y + height > paddle.y)
        {
            return 1; //bounce
        }
        else if ((paddle.x > x && paddle.paddleNumber == 1) || (paddle.x < x - width && paddle.paddleNumber == 2))
        {
            return 2; //score
        }
    
        return 0; //nothing
    }
    
    public void render(Graphics g)
    {
        g.setColor(Color.WHITE);
        // prev WHITE
        g.fillOval(x, y, width, height);
    }
}

The Paddle Class

Kelas Paddle adalah kelas untuk mengatur paddle dalam permainan Pong ini. Paddle adalah semacam raket yang digunakan oleh pemain untuk memukul bola. Di kelas ini, ukuran paddle, kecepatan paddle, warna paddle, dan sebagainya bisa disesuaikan.

Implementation of The Paddle Class

import java.awt.Color;
import java.awt.Graphics;

/**
 * Kelas Paddle adalah kelas untuk mengatur paddle dalam permainan Pong ini.
 * Paddle adalah semacam raket yang digunakan oleh pemain untuk memukul bola.
 * Di kelas ini, ukuran paddle, kecepatan paddle, warna paddle, dan
 * sebagainya bisa disesuaikan.
 *
 * @author Ramadhan Arif Hardijansyah
 * @version 0.1 January 6, 2021
 */
public class Paddle
{
    // instance variables - replace the example below with your own
    public int paddleNumber;
    public int x, y, width = 30, height = 150;
    // prev 50, 250
    public int score;

    /**
     * Constructor for objects of class Paddle
     */
    public Paddle(Pong pong, int paddleNumber)
    {
        this.paddleNumber = paddleNumber;
    
        if (paddleNumber == 1)
        {
            this.x = 0;
        }
    
        if (paddleNumber == 2)
        {
            this.x = pong.width - width;
        }
    
        this.y = pong.height / 2 - this.height / 2;
    }

    public void render(Graphics g)
    {
        g.setColor(Color.WHITE);
        g.fillRect(x, y, width, height);
    }

    public void move(boolean up)
    {
        int speed = 20;
        // prev 15
    
        if (up)
        {
            if (y - speed > 0)
            {
                y -= speed;
            }
            else
            {
                y = 0;
            }
        }
        else
        {
            if (y + height + speed < Pong.pong.height)
            {
                y += speed;
            }
            else
            {
                y = Pong.pong.height - height;
            }
        }
    }
}

The Pong Class

Kelas Pong adalah kelas utama dari permainan Pong ini. Kelas ini membangun dan menampilkan GUI game dan menginisialisasi semua komponen lainnya. Di kelas ini ukuran jendela permainan, batas skor, serta font dan ukuran font dapat disesuaikan.

Implementation of The Pong Class

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.Timer;

/**
 * Kelas Pong adalah kelas utama dari permainan Pong ini. Kelas ini
 * membangun dan menampilkan GUI game dan menginisialisasi semua komponen
 * lainnya. Di kelas ini ukuran jendela permainan, batas skor, serta font
 * dan ukuran font dapat disesuaikan.
 * 
 * @author Ramadhan Arif Hardijansyah
 * @version 0.1 January 6, 2021
 */

public class Pong implements ActionListener, KeyListener
{
    // instance variables
    public static Pong pong;
    public int width = 1366, height = 711;
    // prev 700 700
    public Renderer renderer;
    public Paddle player1;
    public Paddle player2;
    public Ball ball;
    public boolean bot = false, selectingDifficulty;
    public boolean w, s, up, down;
    public int gameStatus = 0, scoreLimit = 7, playerWon; //0 = Menu, 1 = Paused, 2 = Playing, 3 = Over
    public int botDifficulty, botMoves, botCooldown = 0;
    public Random random;
    public JFrame jframe;

    /**
     * Constructor for objects of class Pong
     */
    public Pong()
    {
        Timer timer = new Timer(20, this);
        random = new Random();
    
        jframe = new JFrame("Pong");
    
        renderer = new Renderer();
    
        jframe.setSize(width + 15, height + 35);
        jframe.setVisible(true);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.add(renderer);
        jframe.addKeyListener(this);
    
        timer.start();
    }

    public void start()
    {
        gameStatus = 2;
        player1 = new Paddle(this, 1);
        player2 = new Paddle(this, 2);
        ball = new Ball(this);
    }

    public void update()
    {
        if (player1.score >= scoreLimit)
        {
            playerWon = 1;
            gameStatus = 3;
        }
    
        if (player2.score >= scoreLimit)
        {
            gameStatus = 3;
            playerWon = 2;
        }
    
        if (w)
        {
            player1.move(true);
        }
        if (s)
        {
            player1.move(false);
        }
    
        if (!bot)
        {
            if (up)
            {
                player2.move(true);
            }
            if (down)
            {
                player2.move(false);
            }
        }
        else
        {
            if (botCooldown > 0)
            {
                botCooldown--;
    
                if (botCooldown == 0)
                {
                    botMoves = 0;
                }
            }
    
            if (botMoves < 10)
            {
                if (player2.y + player2.height / 2 < ball.y)
                {
                    player2.move(false);
                    botMoves++;
                }
    
                if (player2.y + player2.height / 2 > ball.y)
                {
                    player2.move(true);
                    botMoves++;
                }
    
                if (botDifficulty == 0)
                {
                    botCooldown = 20;
                }
                if (botDifficulty == 1)
                {
                    botCooldown = 15;
                }
                if (botDifficulty == 2)
                {
                    botCooldown = 10;
                }
            }
        }
    
        ball.update(player1, player2);
    }
    
    public void render(Graphics2D g)
    {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, width, height);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
        if (gameStatus == 0)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
    
            g.drawString("PONG", width / 2 - 75, 50);
    
            if (!selectingDifficulty)
            {
                g.setFont(new Font("Arial", 1, 30));
    
                g.drawString("Press Space to Play", width / 2 - 150, height / 2 - 25);
                g.drawString("Press Shift to Play with Bot", width / 2 - 200, height / 2 + 25);
                g.drawString("<< Score Limit: " + scoreLimit + " >>", width / 2 - 150, height / 2 + 75);
            }
        }
    
        if (selectingDifficulty)
        {
            String string = botDifficulty == 0 ? "Easy" : (botDifficulty == 1 ? "Medium" : "Hard");
    
            g.setFont(new Font("Arial", 1, 30));
    
            g.drawString("<< Bot Difficulty: " + string + " >>", width / 2 - 180, height / 2 - 25);
            g.drawString("Press Space to Play", width / 2 - 150, height / 2 + 25);
        }
    
        if (gameStatus == 1)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
            g.drawString("PAUSED", width / 2 - 103, height / 2 - 25);
        }
    
        if (gameStatus == 1 || gameStatus == 2)
        {
            g.setColor(Color.WHITE);
    
            g.setStroke(new BasicStroke(5f));
    
            g.drawLine(width / 2, 0, width / 2, height);
    
            g.setStroke(new BasicStroke(2f));
    
            g.drawOval(width / 2 - 150, height / 2 - 150, 300, 300);
    
            g.setFont(new Font("Arial", 1, 50));
    
            g.drawString(String.valueOf(player1.score), width / 2 - 90, 50);
            g.drawString(String.valueOf(player2.score), width / 2 + 65, 50);
    
            player1.render(g);
            player2.render(g);
            ball.render(g);
        }
    
        if (gameStatus == 3)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
    
            g.drawString("PONG", width / 2 - 75, 50);
    
            if (bot && playerWon == 2)
            {
                g.drawString("The Bot Wins!", width / 2 - 170, 200);
            }
            else
            {
                g.drawString("Player " + playerWon + " Wins!", width / 2 - 165, 200);
            }
    
            g.setFont(new Font("Arial", 1, 30));
    
            g.drawString("Press Space to Play Again", width / 2 - 185, height / 2 - 25);
            g.drawString("Press ESC for Menu", width / 2 - 140, height / 2 + 25);
        }
    }
    
    @Override
    public void actionPerformed(ActionEvent e)
    {
        if (gameStatus == 2)
        {
            update();
        }
    
        renderer.repaint();
    }
    
    public static void main(String[] args)
    {
        pong = new Pong();
    }
    
    @Override
    public void keyPressed(KeyEvent e)
    {
        int id = e.getKeyCode();
    
        if (id == KeyEvent.VK_W)
        {
            w = true;
        }
        else if (id == KeyEvent.VK_S)
        {
            s = true;
        }
        else if (id == KeyEvent.VK_UP)
        {
            up = true;
        }
        else if (id == KeyEvent.VK_DOWN)
        {
            down = true;
        }
        else if (id == KeyEvent.VK_RIGHT)
        {
            if (selectingDifficulty)
            {
                if (botDifficulty < 2)
                {
                    botDifficulty++;
                }
                else
                {
                    botDifficulty = 0;
                }
            }
            else if (gameStatus == 0)
            {
                scoreLimit++;
            }
        }
        else if (id == KeyEvent.VK_LEFT)
        {
            if (selectingDifficulty)
            {
                if (botDifficulty > 0)
                {
                    botDifficulty--;
                }
                else
                {
                    botDifficulty = 2;
                }
            }
            else if (gameStatus == 0 && scoreLimit > 1)
            {
                scoreLimit--;
            }
        }
        else if (id == KeyEvent.VK_ESCAPE && (gameStatus == 2 || gameStatus == 3))
        {
            gameStatus = 0;
        }
        else if (id == KeyEvent.VK_SHIFT && gameStatus == 0)
        {
            bot = true;
            selectingDifficulty = true;
        }
        else if (id == KeyEvent.VK_SPACE)
        {
            if (gameStatus == 0 || gameStatus == 3)
            {
                if (!selectingDifficulty)
                {
                    bot = false;
                }
                else
                {
                    selectingDifficulty = false;
                }
    
                start();
            }
            else if (gameStatus == 1)
            {
                gameStatus = 2;
            }
            else if (gameStatus == 2)
            {
                gameStatus = 1;
            }
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e)
    {
        int id = e.getKeyCode();
    
        if (id == KeyEvent.VK_W)
        {
            w = false;
        }
        else if (id == KeyEvent.VK_S)
        {
            s = false;
        }
        else if (id == KeyEvent.VK_UP)
        {
            up = false;
        }
        else if (id == KeyEvent.VK_DOWN)
        {
            down = false;
        }
    }
    
    @Override
    public void keyTyped(KeyEvent e)
    {
    
    }
}

The Renderer Class

Kelas Renderer adalah kelas untuk me-render permainan. Rendering atau sintesis gambar adalah proses menghasilkan fotorealistik dari model 2D atau 3D melalui program. Dalam permainan ini digunakan grafik 2D.

Implementation of The Renderer Class

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JPanel;

/**
 * Kelas Renderer adalah kelas untuk me-render permainan. Rendering atau
 * sintesis gambar adalah proses menghasilkan fotorealistik dari model 2D
 * atau 3D melalui program. Dalam permainan ini digunakan grafik 2D.
 *
 * @author Ramadhan Arif Hardijansyah
 * @version 0.1 January 6, 2021
 */
public class Renderer extends JPanel
{
    private static final long serialVersionUID = 1L;
    
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    
        Pong.pong.render((Graphics2D) g);
    }
}

Berikut langkah-langkah untuk mencoba permainan Pong ini.

1. Klik kanan kelas Pong, dan panggil method main.

2. Sebuah jendela permainan pong muncul, disana ada tampilan menu utama dari permainan ini. Klik spasi untuk bermain dengan dua orang. Klik shift untuk bermain dengan bot. Klik tombol panah kanan dan kiri untuk mengubah batas skor.

3. Berikut ini adalah tampilan gameplay saat bermain dengan dua orang. Untuk menggerakkan paddle ke atas dan ke bawah, pemain pertama menggunakan tombol w dan s, sedangkan pemain kedua menggunakan tombol panah atas dan bawah.

4. Untuk kembali ke menu utama, tekan tombol Esc.

5. Untuk keluar dari permainan, cukup klik tombol silang di pojok kanan atas jendela.

Sekian post tentang Game Pong ini. Semoga bermanfaat.


Reference

Bustard, J. (n.d.). Jaryt/PongTutorial. Retrieved January 06, 2021, from https://github.com/Jaryt/PongTutorial

Comments

Popular posts from this blog

Website Pendaftaran Siswa Baru

Postingan berikut menjelaskan dokumentasi website Pendaftaran Siswa Baru. Website di-hosting di local PC menggunakan XAMPP serta menggunakan MySQL untuk menangani database dari para pendaftarnya. Halaman Utama Pendaftar dapat melakukan pendaftaran pada menu Daftar Baru atau melihat list pendaftar pada bagian Pendaftar. Formulir Pendaftaran Siswa Baru Disini, siswa dapat mengisikan formulir pendaftaran dan men-submit. Menu Pendaftar Menu Pendaftar isi menyajikan tabel yang berisi siswa yang telah mendaftar. Dapat dilakukan tindakan Edit atau Hapus pada setiap baris. Formulir Edit Siswa Formulir Edit Siswa menyajikan formulir untuk mengedit data siswa yang telah mendaftar. Setelah melakukan edit, dapat menekan tombol Simpan untuk menyimpan data siswa yang telah diperbarui. Source Code Untuk source code dari website Pendaftaran Siswa Baru ini adalah sebagai berikut. Link GitHub Gist:  https://gist.github.com/dani-ramadhan7/7838e42982a0488fc...

Java Exception Handling

Postingan ini membahas sebuah program tambahan tentang exception handling . Disini seolah-olah bertindak sebagai tester. Dan program yang akan dimodifikasi adalah program SimpleCalculator . Program SimpleCalculator adalah sebuah program kalkulator sederhana yang menggunakan switch..case dalam Java. Program bisa melakukan operasi pertambahan, pengurangan, perkalian, dan pembagian. Program SimpleCalculator ini dibuat menggunakan bahasa pemrograman Java dan bisa di-compile menggunakan IDE BlueJ. Dalam aplikasi ini, dicoba untuk ditambahkan catch exception untuk mengetes bagimana pembagian suatu angka dengan angka nol. Dicari modul kelas yang merupakan operasi pembagian dan dimodifikasi agar bisa mengetes operasi pembagian dengan penyebut angka nol. Exception Handling Exception Handling adalah sebuah proses menanggapi terjadinya exception, menangani runtime error seperti ClassNotFound, IO, SQL, Remote , dsb.  Exception adalah suatu kondisi tidak normal yang membutuhkan pemrosesan...

Java Classes and Objects: A Deeper Look

Pada post kali ini, kita ingin melihat lebih dalam pada pembuatan class , mengontrol akses kepada member dari sebuah class dan membuat constructors . Kita juga ingin mendiskusikan composition - sebuah kemampuan yang bisa membuat suatu kelas memiliki referensi kepada objek dari kelas-kelas lainnya sebagai member. 8.2 TIME CLASS CASE STUDY Time1 Class Declaration Contoh awal ini kita memiliki 2 kelas, Time1 dan Time1Test. Kelas Time1 merepresentasikan waktu hari ini. Kelas Time1Test adalah kelas aplikasi dimana main  membuat satu objek kelas Time1 dan memanggil method -nya. Fig. 8.1. Time1 class declaration maintains the time in a 24-hour format. /** * // Fig. 8.1: Time.java * // Time1 class declaratoin maintains the time in 24-hour format. * * @author Ramadhan Arif Hardijansyah * @version 0.1 10 October 2020 */ public class Time1 { private int hour; // 0 - 23 private int minute; // 0 - 59 private int second; // 0 - 59 /* set a new time value using univers...