簡體   English   中英

如何為我的 java 游戲添加流暢的移動?

[英]How to add smooth movement to my java game?

我的目標:在乒乓球之類的比賽中,按鍵控制應該平穩地移動球棒。

期望:希望球棒通過按鍵平穩地上下移動。 實際結果:蝙蝠的移動就像滯后或速度變化一樣。

我嘗試將速度變量與可能的 lerp 一起使用,但它們滯后。 我嘗試增加和減少 y 值,但它滯后更糟。 我搜索了,但找不到解決方案。

我稱矩形蝙蝠和圓形乒乓球。 另外,這是我第一天在這里發帖

游戲截圖

這是panal代碼:

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JPanel;
import javax.swing.Timer;

public class gamePanel extends JPanel implements ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = 6350159535293799269L;
    static final int SCREEN_WIDTH = 840;
    static final int SCREEN_HEIGHT = 610;
    static final int PONG_SPAWN_FRAME = 50;
    static final int padding = 30;

    
    
    static final int pongSize = 30;
    static final int batHeight = SCREEN_HEIGHT / 4;
    static final int batWidth = SCREEN_WIDTH / 32;
    static final int batSpeed = 4;
    static final int pongSpeed = 3;
    static final int scoreTextSize = 45;
    
    boolean running = false;
    
    int redX = padding;
    int redY = SCREEN_HEIGHT / 2;
    int redVelocity = 0;

    int blueX = SCREEN_WIDTH - padding;
    int blueY = SCREEN_HEIGHT / 2;
    int blueVelocity = 0;

    int redPoints = 0;
    int bluePoints = 0;

    int pongX = SCREEN_WIDTH / 4 - pongSize / 2;
    int pongY = 0;

    int pongVelocityX = pongSpeed;
    int pongVelocityY = pongSpeed;

    final int DELAY = 6;
    Timer timer;

    Random random;

    gamePanel() {
        random = new Random();
        pongY = random.nextInt((int) (SCREEN_HEIGHT - PONG_SPAWN_FRAME) + PONG_SPAWN_FRAME);
        if (pongVelocityY == 0) {
            if (pongY > SCREEN_HEIGHT / 2 + pongSize) {
                pongVelocityY = -pongSpeed;
            } else {
                pongVelocityY = pongSpeed;
            }
        }
        this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
        this.setBackground(Color.DARK_GRAY);
        this.setFocusable(true);
        this.addKeyListener(new myKeyAdapter());
        startGame();
    }

    void startGame() {
        running = true;
        timer = new Timer(DELAY, this);
        timer.start();

    }

    void restart() {
        redX = padding;
        redY = SCREEN_HEIGHT / 2;
        redVelocity = 0;

        blueX = SCREEN_WIDTH - padding;
        blueY = SCREEN_HEIGHT / 2;
        blueVelocity = 0;

        pongX = SCREEN_WIDTH / 4 - pongSize / 2;
        pongY = 0;

        pongVelocityX = pongSpeed;
        pongVelocityY = pongSpeed;

        spawnPong();

    }

    void spawnPong() {
        pongY = random.nextInt((int) (SCREEN_HEIGHT - PONG_SPAWN_FRAME * 2)) + PONG_SPAWN_FRAME;
        if (pongVelocityY == 0) {
            if (pongY > SCREEN_HEIGHT / 2 + pongSize) {
                pongVelocityY = -pongSpeed;
            } else {
                pongVelocityY = pongSpeed;
            }
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }

    void draw(Graphics g) {
        g.setColor(Color.LIGHT_GRAY);
        g.fillOval(pongX, pongY, pongSize, pongSize);
        g.setColor(Color.red);
        g.fillRect(redX - batWidth / 2, redY - batHeight / 2, batWidth, batHeight);
        g.setColor(Color.blue);
        g.fillRect(blueX - batWidth / 2, blueY - batHeight / 2, batWidth, batHeight);
        g.setColor(Color.white);
        g.setFont(new Font("Roman New Times", Font.PLAIN, scoreTextSize));
        g.drawString(String.valueOf(redPoints), SCREEN_WIDTH / 4, scoreTextSize);
        g.drawString(String.valueOf(bluePoints), SCREEN_WIDTH / 4 * 3, scoreTextSize);
    }

    void pongMove() {
        pongX += pongVelocityX;
        pongY += pongVelocityY;
    }

    void batMove() {
        if (redY > batHeight / 2 && redVelocity < 0) {
            redY += redVelocity * batSpeed;
        }
        if (redY < SCREEN_HEIGHT - batHeight / 2 && redVelocity > 0) {
            redY += redVelocity * batSpeed;
        }

        blueY = pongY;
        /*
         * if (blueY>batHeight/2 && blueVelocity < 0) { blueY += blueVelocity *
         * pongSpeed; } if (blueY<SCREEN_HEIGHT-batHeight/2 && blueVelocity > 0) { blueY
         * += blueVelocity * pongSpeed; }
         */
    }

    void batLerp() {
        redVelocity *= 0.5f;
        blueVelocity *= 0.5f; 
    }

    void checkCollision() {
        if ((pongX > blueX - pongSize - batWidth / 2 && pongX < blueX - pongSize + batWidth / 2)
                && (pongY > blueY - batHeight / 2 && pongY < blueY + batHeight / 2)) {
            pongVelocityX *= -1;
        }
        if (pongX < redX + batWidth / 2 && (pongY > redY - batHeight / 2 && pongY < redY + batHeight / 2)) {
            pongVelocityX *= -1;
        }
        if (pongY < 0) {
            pongVelocityY *= -1;
        }
        if (pongY > SCREEN_HEIGHT - pongSize) {
            pongVelocityY *= -1;
        }
        if (pongX < -pongSize) {
            bluePoints += 1;
            restart();
        }
        if (pongX > SCREEN_WIDTH) {
            redPoints += 1;
            restart();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (running) {
            checkCollision();
            batMove();
            batLerp();
            pongMove();
        }
        repaint();

    }

    public class myKeyAdapter extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
            case KeyEvent.VK_W:
                redVelocity = -1;
                break;
            case KeyEvent.VK_S:
                redVelocity = 1;
                break;
            case KeyEvent.VK_UP:
                blueVelocity = -1;
                break;
            case KeyEvent.VK_DOWN:
                blueVelocity = 1;
                break;
            }
        }
    }
}

原始答案

我修改了撥片的移動方式,使撥片僅在您按住鍵時移動。 為了測試,我不得不放慢游戲速度。

我在遵循您的代碼時遇到了麻煩。 您的JPanel class 工作量太大,難以理解。 我會從普通的 Java getter / setter 類創建一個Ball class 和一個Paddle class 來保存球和槳的字段。

這是完整的可運行代碼。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ClassicPongGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ClassicPongGUI());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Pong");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new GamePanel());

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public class GamePanel extends JPanel implements ActionListener {

        private static final long serialVersionUID = 6350159535293799269L;

        static final int SCREEN_WIDTH = 840;
        static final int SCREEN_HEIGHT = 610;
        static final int PONG_SPAWN_FRAME = 50;
        static final int padding = 30;

        static final int pongSize = 30;
        static final int batHeight = SCREEN_HEIGHT / 4;
        static final int batWidth = SCREEN_WIDTH / 32;
        static final int batSpeed = 20;
        static final int pongSpeed = 1;
        static final int scoreTextSize = 45;

        boolean running = false;

        int redX = padding;
        int redY = SCREEN_HEIGHT / 2;
        int redVelocity = 0;

        int blueX = SCREEN_WIDTH - padding;
        int blueY = SCREEN_HEIGHT / 2;
        int blueVelocity = 0;

        int redPoints = 0;
        int bluePoints = 0;

        int pongX = SCREEN_WIDTH / 4 - pongSize / 2;
        int pongY = 0;

        int pongVelocityX = pongSpeed;
        int pongVelocityY = pongSpeed;

        final int DELAY = 6;
        Timer timer;

        Random random;

        public GamePanel() {
            random = new Random();
            pongY = random.nextInt((int) (SCREEN_HEIGHT - PONG_SPAWN_FRAME) + PONG_SPAWN_FRAME);
            if (pongVelocityY == 0) {
                if (pongY > SCREEN_HEIGHT / 2 + pongSize) {
                    pongVelocityY = -pongSpeed;
                } else {
                    pongVelocityY = pongSpeed;
                }
            }
            this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
            this.setBackground(Color.DARK_GRAY);
            this.setFocusable(true);
            this.addKeyListener(new myKeyAdapter());
            startGame();
        }

        void startGame() {
            running = true;
            timer = new Timer(DELAY, this);
            timer.start();

            redX = padding;
            redY = SCREEN_HEIGHT / 2;
            redVelocity = 0;
        }

        void restart() {
            blueX = SCREEN_WIDTH - padding;
            blueY = SCREEN_HEIGHT / 2;
            blueVelocity = 0;

            pongX = SCREEN_WIDTH / 4 - pongSize / 2;
            pongY = 0;

            pongVelocityX = pongSpeed;
            pongVelocityY = pongSpeed;

            spawnPong();

        }

        void spawnPong() {
            pongY = random.nextInt((int) (SCREEN_HEIGHT - PONG_SPAWN_FRAME * 2)) + PONG_SPAWN_FRAME;
            if (pongVelocityY == 0) {
                if (pongY > SCREEN_HEIGHT / 2 + pongSize) {
                    pongVelocityY = -pongSpeed;
                } else {
                    pongVelocityY = pongSpeed;
                }
            }
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            draw(g);
        }

        void draw(Graphics g) {
            g.setColor(Color.LIGHT_GRAY);
            g.fillOval(pongX, pongY, pongSize, pongSize);
            g.setColor(Color.red);
            g.fillRect(redX - batWidth / 2, redY - batHeight / 2, batWidth, batHeight);
            g.setColor(Color.blue);
            g.fillRect(blueX - batWidth / 2, blueY - batHeight / 2, batWidth, batHeight);
            g.setColor(Color.white);
            g.setFont(new Font("Times New Roman", Font.PLAIN, scoreTextSize));
            g.drawString(String.valueOf(redPoints), SCREEN_WIDTH / 4, scoreTextSize);
            g.drawString(String.valueOf(bluePoints), SCREEN_WIDTH / 4 * 3, scoreTextSize);
        }

        void pongMove() {
            pongX += pongVelocityX;
            pongY += pongVelocityY;
        }

        void batMove() {
            if (redY > batHeight / 2 && redVelocity < 0) {
                redY += redVelocity * batSpeed;
            }
            if (redY < SCREEN_HEIGHT - batHeight / 2 && redVelocity > 0) {
                redY += redVelocity * batSpeed;
            }

            blueY = pongY;
            /*
             * if (blueY>batHeight/2 && blueVelocity < 0) { blueY += blueVelocity *
             * pongSpeed; } if (blueY<SCREEN_HEIGHT-batHeight/2 && blueVelocity > 0) { blueY
             * += blueVelocity * pongSpeed; }
             */
        }

        void batLerp() {
            redVelocity = 0;
            blueVelocity = 0;
        }

        void checkCollision() {
            if ((pongX > blueX - pongSize - batWidth / 2 
                    && pongX < blueX - pongSize + batWidth / 2)
                    && (pongY > blueY - batHeight / 2 
                    && pongY < blueY + batHeight / 2)) {
                pongVelocityX *= -1;
            }
            if (pongX < redX + batWidth / 2 && (pongY > redY - batHeight / 2 
                    && pongY < redY + batHeight / 2)) {
                pongVelocityX *= -1;
            }
            if (pongY < 0) {
                pongVelocityY *= -1;
            }
            if (pongY > SCREEN_HEIGHT - pongSize) {
                pongVelocityY *= -1;
            }
            if (pongX < -pongSize) {
                bluePoints += 1;
                restart();
            }
            if (pongX > SCREEN_WIDTH) {
                redPoints += 1;
                restart();
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (running) {
                checkCollision();
                batMove();
                batLerp();
                pongMove();
            }
            repaint();

        }

        public class myKeyAdapter extends KeyAdapter {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                case KeyEvent.VK_W:
                    redVelocity = -1;
                    break;
                case KeyEvent.VK_S:
                    redVelocity = 1;
                    break;
                case KeyEvent.VK_UP:
                    redVelocity = -1;
                    break;
                case KeyEvent.VK_DOWN:
                    redVelocity = 1;
                    break;
                }
            }
        }
        
    }

}

修訂答案

我認為這將是一個有趣的項目,所以我重新編寫了代碼。 下面是 GUI 的顯示方式。

乒桂

W 和向上箭頭鍵將藍色槳向上移動。 S 和向下箭頭鍵將藍色槳向下移動。 必須按住這些鍵才能繼續運動。 釋放鍵停止槳運動,

空格鍵重新開始游戲。

當我創建 Swing GUI 時,我使用model / view / controller (MVC) 模式。 這種模式使我能夠分離我的關注點並一次專注於應用程序的一小部分。

對於 Swing GUI,MVC 模式定義為:

  1. 該視圖從 model 讀取信息。
  2. 該視圖不會更新 model。
  3. controller 更新 model 並重新繪制/重新驗證視圖。

一個 Swing GUI 可以有許多 controller 類。 我為這個乒乓球游戲創建了三個 controller 類。

我創建了 8 個不同的類。 三個類組成應用程序 model,兩個類定義視圖,三個 controller 類管理應用程序。

Model

我創建了一個Ball class 來保存創建球所需的字段並在屏幕上移動球。 我使用Point來保存中心點,使用int來保存球的半徑。

Ball class 不是典型的 getter / setter class。 moveBall方法使用極坐標計算球的新 position。 將極坐標轉換為笛卡爾坐標以在繪圖 JPanel 上繪制球。

Paddle class 創建一個槳。 我將槳的形狀存儲在Rectangle中。 這是一個更典型的 Java getter / setter class,盡管有代碼限制槳葉在 Y 軸上移動的距離。

GameModel class 是應用程序 model。 這個 class 包含一個Ball實例和兩個Paddle實例,以及兩個得分ints和游戲運行的幀速率。 此 class 的實例通過視圖和 controller 類傳遞。

看法

我創建了一個JFrame和一個繪圖JPanel 繪圖JPanel繪制了球的當前 position、兩個槳和分數。 時期。 沒有其他的。

controller 類負責移動球和槳並重繪JPanel

我使用KeyBindings將鍵盤鍵設置為各種操作。 使用KeyBindings ,我不必擔心繪圖JPanel是否有焦點。

Controller

TimerListener class 為 Pong 游戲設置動畫。

MovePaddleAction class 向上或向下移動槳葉,具體取決於按下的鍵。 必須按住鍵才能繼續運動。

RestartAction class 重新啟動游戲。

代碼

這是完整的可運行代碼。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ClassicPongGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ClassicPongGUI());
    }
    
    private final Dimension panelSize;
    
    private GameModel gameModel;
    
    private GamePanel gamePanel;
    
    private Timer timer;
    
    public ClassicPongGUI() {
        this.panelSize = new Dimension(840, 610);
        this.gameModel = new GameModel(panelSize);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Pong");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.gamePanel = new GamePanel(this, gameModel);
        frame.add(gamePanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        setKeyBindings();
        startTimer();
    }
    
    private void setKeyBindings() {
        String moveUp = "moveUp";
        String moveDown = "moveDown";
        String restart = "restart";
        
        InputMap inputMap = gamePanel.getInputMap(
                JPanel.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = gamePanel.getActionMap();
        
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_W, 0), moveUp);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_UP, 0), moveUp);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_S, 0), moveDown);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_DOWN, 0), moveDown);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_SPACE, 0), restart);
        
        int increment = 15;
        actionMap.put(moveUp, new MovePaddleAction(
                this, gameModel, -increment));
        actionMap.put(moveDown, new MovePaddleAction(
                this, gameModel, increment));
        actionMap.put(restart, new RestartAction(
                this, gameModel));
    }
    
    public void startTimer() {
        int delay = 1000 / gameModel.getFrameRate();
        timer = new Timer(delay, new TimerListener(this, gameModel));
        timer.setInitialDelay(5000);
        timer.start();
    }
    
    public void stopTimer() {
        if (timer != null) {
            timer.stop();
        }
    }
    
    public Dimension getPanelSize() {
        return panelSize;
    }

    public void repaint() {
        gamePanel.repaint();
    }

    public class GamePanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private final GameModel model;
        
        public GamePanel(ClassicPongGUI frame, GameModel model) {
            this.model = model;
            
            this.setBackground(Color.DARK_GRAY);
            this.setPreferredSize(frame.getPanelSize());
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            drawBall(g);
            drawPaddles(g);
            drawScores(g);
        }

        private void drawBall(Graphics g) {
            Ball ball = model.getBall();
            g.setColor(ball.getColor());
            int radius = ball.getRadius();
            int diameter = radius + radius;
            Point point = ball.getCenterPoint();
            g.fillOval(point.x - radius, point.y - radius, 
                    diameter, diameter);
        }

        private void drawPaddles(Graphics g) {
            Paddle[] paddles = model.getPaddles();
            for (Paddle paddle : paddles) {
                g.setColor(paddle.getColor());
                Rectangle r = paddle.getPaddle();
                g.fillRect(r.x, r.y, r.width, r.height);
            }
        }

        private void drawScores(Graphics g) {
            int[] scores = model.getScore();
            int scoreTextSize = 45;
            g.setColor(Color.WHITE);
            g.setFont(new Font("Times New Roman", 
                    Font.PLAIN, scoreTextSize));
            g.drawString(String.valueOf(scores[0]), 
                    panelSize.width / 4, scoreTextSize);
            g.drawString(String.valueOf(scores[1]), 
                    panelSize.width * 3 / 4, scoreTextSize);
        }
        
    }
    
    public class TimerListener implements ActionListener {
        
        private final ClassicPongGUI frame;
        
        private final GameModel model;

        public TimerListener(ClassicPongGUI frame, GameModel model) {
            this.frame = frame;
            this.model = model;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            int frameRate = model.getFrameRate();
            model.getBall().moveBall(frameRate);
            
            Point point = model.getBall().getCenterPoint();
            Paddle[] paddles = model.getPaddles();
            for (int i = 0; i < paddles.length; i++) {
                Rectangle p = paddles[i].getPaddle();
                int y = point.y - p.height / 2;
                if (i == 0) {
                    paddles[i].setPaddle(y);
                }
                model.contactsPaddle();
            }
            
            if (point.x < 0) {
                model.incrementScore(1, 1);
                model.resetBall();
            }
            
            if (point.x > frame.getPanelSize().width) {
                model.incrementScore(0, 1);
                model.resetBall();
            }
            
            frame.repaint();
        }
        
    }
    
    public class MovePaddleAction extends AbstractAction {

        private static final long serialVersionUID = 1L;
        
        private final int increment;

        private final ClassicPongGUI frame;
        
        private final GameModel model;

        public MovePaddleAction(ClassicPongGUI frame, GameModel model, 
                int increment) {
            this.frame = frame;
            this.model = model;
            this.increment = increment;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            model.getPaddles()[1].movePaddle(increment);
            frame.repaint();
        }
        
    }
    
    public class RestartAction extends AbstractAction {

        private static final long serialVersionUID = 1L;

        private final ClassicPongGUI frame;
        
        private final GameModel model;

        public RestartAction(ClassicPongGUI frame, GameModel model) {
            this.frame = frame;
            this.model = model;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            frame.stopTimer();
            model.restartGame();
            frame.startTimer();
            frame.repaint();
        }
        
    }
        
    public class GameModel {

        private int[] score;
        
        /** frames per second **/
        private final int frameRate;

        private Ball ball;

        private final Dimension panelSize;

        private Paddle[] paddles;

        public GameModel(Dimension panelSize) {
            this.panelSize = panelSize;
            this.score = new int[2];
            this.paddles = new Paddle[2];
            this.frameRate = 50;

            int ballRadius = 15;
            Point centerPoint = new Point(panelSize.width / 2, 
                    panelSize.height / 2);
            this.ball = new Ball(centerPoint, ballRadius, 
                    panelSize, Color.LIGHT_GRAY);

            int batWidth = panelSize.width / 32;
            int batHeight = panelSize.height / 4;
            int padding = 30;
            int x = padding;
            int y = calculateCenterY(batHeight);
            Rectangle r = new Rectangle(x, y, batWidth, batHeight);
            this.paddles[0] = new Paddle(r, panelSize.height, Color.RED);

            x = panelSize.width - padding - batWidth;
            r = new Rectangle(x, y, batWidth, batHeight);
            this.paddles[1] = new Paddle(r, panelSize.height, Color.BLUE);

            resetScore();
        }
        
        public void restartGame() {
            int batHeight = panelSize.height / 4;
            resetBall();
            paddles[0].setPaddle(calculateCenterY(batHeight));
            paddles[1].setPaddle(calculateCenterY(batHeight));
            resetScore();
        }
        
        public void resetBall() {
            ball.setCenterPoint(new Point(panelSize.width / 2, 
                    panelSize.height / 2));
        }

        private int calculateCenterY(int batHeight) {
            return (panelSize.height - batHeight) / 2;
        }
        
        public void contactsPaddle() {
            int radius = ball.getRadius();
            int diameter = radius + radius;
            Point point = ball.getCenterPoint();
            Rectangle b = new Rectangle(point.x - radius, 
                    point.y - radius, diameter, diameter);
            for (Paddle paddle : paddles) {
                if (paddle.getPaddle().intersects(b)) {
                    ball.reverseXDirection(frameRate);
                }
            }
            
        }

        public void resetScore() {
            score[0] = 0;
            score[1] = 0;
        }

        public void incrementScore(int index, int increment) {
            score[index] += increment;
        }

        public int[] getScore() {
            return score;
        }

        public Ball getBall() {
            return ball;
        }

        public Paddle[] getPaddles() {
            return paddles;
        }

        public int getFrameRate() {
            return frameRate;
        }

    }

    public class Paddle {

        private final int upperBound;

        private final Color color;

        private Rectangle paddle;

        public Paddle(Rectangle paddle, int upperBound, Color color) {
            this.paddle = paddle;
            this.upperBound = upperBound;
            this.color = color;
        }

        public void movePaddle(int increment) {
            paddle.y += increment;
            limitMovement();
        }
        
        public void setPaddle(int y) {
            paddle.y = y;
            limitMovement();
        }

        private void limitMovement() {
            paddle.y = Math.max(paddle.y, 0);
            int height = paddle.y + paddle.height;
            height = Math.min(height, upperBound);
            paddle.y = height - paddle.height;
        }

        public Rectangle getPaddle() {
            return paddle;
        }

        public Color getColor() {
            return color;
        }

    }

    public class Ball {
        
        /** Pixels per second **/
        private final double velocity;

        private final int radius;
        private int angle;

        private final Color color;

        private final Dimension panelSize;

        private Point centerPoint;
        
        private Point2D.Double doubleCenterPoint;
        
        private Random random;

        public Ball(Point centerPoint, int radius, Dimension panelSize, 
                Color color) {
            this.centerPoint = centerPoint;
            setDoubleCenterPoint(centerPoint);
            this.radius = radius;
            this.panelSize = panelSize;
            this.color = color;
            this.velocity = 300.0;
            this.random = new Random();
            setRandomAngle();
        }
        
        public void reverseXDirection(int frameRate) {
            angle = bounceXAngle(angle);
            angle += (angle < 0) ? 360 : 0;
            moveBall(frameRate);
        }
        
        public void moveBall(int frameRate) {
            double theta = Math.toRadians(angle);
            double distance = velocity / frameRate;
            doubleCenterPoint.x = Math.cos(theta) * distance + 
                    doubleCenterPoint.x;
            doubleCenterPoint.y = Math.sin(theta) * distance + 
                    doubleCenterPoint.y;
            
            if (doubleCenterPoint.y < radius) {
                double adjustment = radius - doubleCenterPoint.y;
                doubleCenterPoint.y += adjustment;
                angle = bounceYAngle(angle);
            }
            
            if ((doubleCenterPoint.y + radius) > panelSize.height) {
                double adjustment = panelSize.height - 
                        doubleCenterPoint.y - radius;
                doubleCenterPoint.y += adjustment;
                angle = bounceYAngle(angle);
            }
            
            int x = (int) Math.round(doubleCenterPoint.x);
            int y = (int) Math.round(doubleCenterPoint.y);
            this.centerPoint = new Point(x, y);
        }
        
        private int bounceXAngle(int angle) {
            return 180 - angle;
        }

        
        private int bounceYAngle(int angle) {
            return 360 - angle;
        }
        
        public Point getCenterPoint() {
            return centerPoint;
        }

        public void setCenterPoint(Point centerPoint) {
            this.centerPoint = centerPoint;
            setRandomAngle();
            setDoubleCenterPoint(centerPoint);
        }

        private void setDoubleCenterPoint(Point centerPoint) {
            this.doubleCenterPoint = 
                    new Point2D.Double(centerPoint.x, centerPoint.y);
        }
        
        private void setRandomAngle() {
            int[] angles = {30, 150, 210, 330 };
            this.angle = angles[random.nextInt(angles.length)];
        }

        public int getRadius() {
            return radius;
        }

        public Color getColor() {
            return color;
        }

    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM