如何为我的 Java 游戏添加流畅的动作?

如何解决如何为我的 Java 游戏添加流畅的动作?

我的目标:在像乒乓球这样的游戏中,关键控制应该可以平稳地移动球棒。

期望:希望蝙蝠可以通过按键平滑地上下移动。 实际结果:蝙蝠像滞后或改变速度一样移动。

我尝试将速度变量与 lerp 一起使用,但它们滞后。 我尝试增加和减少 y 值,但效果更差。 我搜索过,但找不到解决方案。

我称之为矩形球棒和圆形乒乓球。 另外,这是我第一天在这里发帖

Screenshot from the game

这是通用代码:

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,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 类做的工作太多,太难理解了。我将从普通的 Java getter / setter 类创建一个 Ball 类和一个 Paddle 类来保存球和桨的字段。

这是完整的可运行代码。

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,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 的显示方式。

Pong GUI

W 和向上箭头键向上移动蓝色拨片。 S 和向下箭头键向下移动蓝色拨片。必须按住这些键才能继续运动。释放键停止桨运动,

空格键重新开始游戏。

当我创建 Swing GUI 时,我使用 model / view / controller (MVC) 模式。这种模式使我能够将关注点分开,一次专注于应用程序的一小部分。

对于 Swing GUI,MVC 模式定义为:

  1. 视图从模型中读取信息。
  2. 视图不会更新模型。
  3. 控制器更新模型并重新绘制/重新验证视图。

Swing GUI 可以有许多控制器类。我为此 Pong 游戏创建了三个控制器类。

我创建了 8 个不同的类。三个类构成应用程序模型,两个类定义视图,三个控制器类管理应用程序。

型号

我创建了一个 Ball 类来保存创建球和在屏幕上移动球所需的字段。我使用 Point 来保持中心点,使用 int 来保持球的半径。

Ball 类不是典型的 getter/setter 类。 moveBall 方法使用极坐标来计算球的新位置。将极坐标转换为笛卡尔坐标以在绘图 JPanel 上绘制球。

Paddle 类创建一个桨。我将桨的形状存储在 Rectangle 中。这是一个更典型的 Java getter/setter 类,尽管有代码来限制桨可以在 Y 轴上移动多远。

GameModel 类是应用程序模型。该类包含一个 Ball 实例和两个 Paddle 实例,以及两个分数 ints 和游戏运行的帧速率。此类的实例通过视图和控制器类传递。

查看

我创建了一个 JFrame 和一个绘图 JPanel。绘图 JPanel 绘制球的当前位置、两个球拍和得分。时期。没有别的。

控制器类负责移动球和桨并重新绘制 JPanel

我使用 KeyBindings 将键盘按键设置为各种操作。使用 KeyBindings,我不必担心绘图 JPanel 是否有焦点。

控制器

TimerListener 类为 Pong 游戏制作动画。

MovePaddleAction 类根据按下的键向上或向下移动拨片。必须按住该键才能继续运动。

RestartAction 类重新开始游戏。

代码

这是完整的可运行代码。

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,moveUp);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_S,moveDown);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_DOWN,moveDown);
        inputMap.put(KeyStroke.getKeyStroke(
                KeyEvent.VK_SPACE,restart);
        
        int increment = 15;
        actionMap.put(moveUp,new MovePaddleAction(
                this,gameModel,-increment));
        actionMap.put(moveDown,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",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,batHeight);
            this.paddles[0] = new Paddle(r,panelSize.height,Color.RED);

            x = panelSize.width - padding - batWidth;
            r = new Rectangle(x,batHeight);
            this.paddles[1] = new Paddle(r,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,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;
        }

    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res