javax.swing.timer 在 Java 中实现 Flappy Bird 的副本时出现问题

Troubles with javax.swing.timer while implementing a replica of Flappy Bird in Java

我正在 Java 中编写 Flappy Bird 游戏的副本,但我在一些有关线程的内容上遇到了问题。 基本上,我的项目中有 4 个 classes,所以 far.I 有 Renderer class 这有助于我渲染游戏,看起来像这样:

import java.awt.Graphics;

import javax.swing.JPanel;

public class Renderer extends JPanel
{

    private static final long serialVersionUID = 1L;

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

        FlappyBird.flappyBird.repaint(g);
    }

}

我有 Database class 可以帮助我连接到本地托管数据库以保存分数,它看起来像这样:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;  
import java.sql.SQLException;
import java.sql.Statement;

public class Database  {

    private static Connection con;
    private String driverName = "com.mysql.jdbc.Driver";

    public Database(String host, String username, String password){
       try {

            con = DriverManager.getConnection( host, username, password );

           }

       catch (SQLException e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
       }

       try {
            Class.forName(driverName).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            System.err.println(e.getMessage() + "------Cannot Load Driver");

        }
   }

    public void insertRow (Row row)
   {
        try {         

            PreparedStatement stmt = con.prepareStatement("insert into Scores (Username, Score, CoinScore) VALUES (?, ?, ?);");
            stmt.setString(1, row.getUserName());
            stmt.setInt(2, row.getScore());
            stmt.setInt(3, row.getCoinScore());


            stmt.executeUpdate();
        } catch (SQLException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

我有一个 Row class 表示即将插入数据库的一行,它的文件如下所示:

public class Row {

    private String username;
    private int score;
    private int coinscore;

    public Row(String username, int score, int coinscore)
    {
        this.username = username;
        this.score = score;
        this.coinscore = coinscore;
    }

    public String getUserName()
    {
        return this.username;
    }

    public int getScore()
    {
        return this.score;
    }

    public int getCoinScore()
    {
        return this.coinscore;
    }
} 

我有一个名为 Flappy Bird 的主要 class,它是游戏本身,看起来像这样:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.*;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

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


public class FlappyBird implements ActionListener, MouseListener, KeyListener
{

    public static FlappyBird flappyBird;

    public final int WIDTH = 800, HEIGHT = 800;

    public Renderer renderer;

    public Rectangle bird;

    public ArrayList<Rectangle> columns,coins;

    public int ticks, yMotion, score, coinScore;

    public boolean gameOver, started;

    public Random rand;

    public Timer timer;

    public FlappyBird()
    {
        JFrame jframe = new JFrame();
        timer = new Timer(50, this);

        renderer = new Renderer();
        rand = new Random();

        jframe.add(renderer);
        jframe.setTitle("Flappy Bird");
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setSize(WIDTH, HEIGHT);
        jframe.addMouseListener(this);
        jframe.addKeyListener(this);
        jframe.setResizable(false);
        jframe.setVisible(true);

        bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
        columns = new ArrayList<Rectangle>();
        coins = new ArrayList<Rectangle>();

        addColumn(true);
        addColumn(true);
        addColumn(true);
        addColumn(true);

        timer.start();
    }

    public void addColumn(boolean start)
    {
        int space = 300;
        int width = 100;
        int height = 50 + rand.nextInt(300);

        if (start)
        {
            columns.add(new Rectangle(WIDTH + width + columns.size() * 300, HEIGHT - height - 120, width, height));
            coins.add(new Rectangle(WIDTH+10+columns.size()*300,HEIGHT-height-100,15,15));
            columns.add(new Rectangle(WIDTH + width + (columns.size() - 1) * 300, 0, width, HEIGHT - height - space));
        }
        else
        {
            columns.add(new Rectangle(columns.get(columns.size() - 1).x + 600, HEIGHT - height - 120, width, height));
            coins.add(new Rectangle(columns.get(columns.size()-1).x+rand.nextInt(600) + 100,HEIGHT -height - rand.nextInt(100),15,15));
            columns.add(new Rectangle(columns.get(columns.size() - 1).x, 0, width, HEIGHT - height - space));
        }
    }

    public void paintColumn(Graphics g, Rectangle column)
    {
        g.setColor(Color.green.darker());
        g.fillRect(column.x, column.y, column.width, column.height);
    }

    public void paintCoin(Graphics g, Rectangle coin)
    {
        g.setColor(Color.yellow.darker());
        g.fillRect(coin.x, coin.y, coin.width, coin.height);
    }

    public void paintCoinCyan(Graphics g, Rectangle coin)
    {
        g.setColor(Color.cyan);
        g.fillRect(coin.x, coin.y, coin.width, coin.height);
    }

    public void jump()
    {
        if (gameOver)
        {
            bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
            columns.clear();
            coins.clear();
            yMotion = 0;
            score = 0;
            coinScore = 0;

            addColumn(true);
            addColumn(true);
            addColumn(true);
            addColumn(true);
           Scanner in = new Scanner(System.in);
           Database myDB = new Database("jdbc:mysql://localhost:3306/Leaderboard","root","greenlantern10");
           System.out.println("Input your Username: ");
           String user = in.next();
           in.close();

           Row row = new Row(user,score,coinScore);
           myDB.insertRow(row);
            gameOver = false;


        }

        if (!started)
        {
            started = true;
        }
        else if (!gameOver)
        {
            if (yMotion > 0)
            {
                yMotion = 0;
            }

            yMotion -= 10;
        }
    }



    @Override
    public void actionPerformed(ActionEvent e)
    {
        int speed = 15;

        ticks++;

        if (started)
        {
            for (int i = 0; i < columns.size(); i++)
            {
                Rectangle column = columns.get(i);

                column.x -= speed;

            }

            for (int i = 0; i< coins.size();i++)
            {
                Rectangle coin = coins.get(i);

                coin.x -= speed;

            }

            if (ticks % 2 == 0 && yMotion < speed)
            {
                yMotion += 2;
            }

            for (int i = 0; i < columns.size(); i++)
            {
                Rectangle column = columns.get(i);

                if (column.x + column.width < 0)
                {
                    columns.remove(column);

                    if (column.y == 0)
                    {
                        addColumn(false);
                    }
                }
            }

            bird.y += yMotion;

            for (Rectangle column : columns)
            {
                if (column.y == 0 && bird.x + bird.width / 2 > column.x + column.width / 2 - 10 && bird.x + bird.width / 2 < column.x + column.width / 2 + 10)
                {
                    score++;
                }

                if (column.intersects(bird))
                {
                    gameOver = true;

                    if (bird.x <= column.x)
                    {
                        bird.x = column.x - bird.width;

                    }
                    else
                    {
                        if (column.y != 0)
                        {
                            bird.y = column.y - bird.height;
                        }
                        else if (bird.y < column.height)
                        {
                            bird.y = column.height;
                        }
                    }
                }
            }

            for (Rectangle coin : coins)
            {
                if (bird.intersects(coin))
                {
                  coinScore++;

                }
            }

            if (bird.y > HEIGHT - 120)
            {
                bird.y = HEIGHT - 120;
            }

            if (bird.y < 0)
            {
                gameOver = true;
            }

            if (bird.y + yMotion >= HEIGHT - 120)
            {
                bird.y = HEIGHT - 120 - bird.height;
                gameOver = true;
            }
        }

        renderer.repaint();
    }

    public void repaint(Graphics g)
    {
        g.setColor(Color.cyan);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(Color.orange);
        g.fillRect(0, HEIGHT - 120, WIDTH, 120);

        g.setColor(Color.green);
        g.fillRect(0, HEIGHT - 120, WIDTH, 20);

        g.setColor(Color.red);
        g.fillRect(bird.x, bird.y, bird.width, bird.height);

        for (Rectangle column : columns)
        {
            paintColumn(g, column);
        }

        for (Rectangle coin : coins)
        {
            paintCoin(g,coin);
        }

        g.setColor(Color.white);
        g.setFont(new Font("SANS_SERIF", 1, 100));

        if (!started)
        {
            g.drawString("Click or press SPACE to start!", 40, HEIGHT / 2 - 50);
        }

        if (gameOver)
        {
            g.drawString("Game Over!", 200, HEIGHT / 2 - 60);
        }

        if (!gameOver && started)
        {
            g.drawString("Score: "+String.valueOf(score), WIDTH / 2 - 400 , 150);
            g.drawString("Coin score: "+String.valueOf(coinScore),WIDTH / 2- 400, 50);
        }
    }

    public static void main(String[] args)
    {
        flappyBird = new FlappyBird();
    }

    @Override
    public void mouseClicked(MouseEvent e)
    {
        jump();
    }

    @Override
    public void keyReleased(KeyEvent e)
    {
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
            jump();
        }
    }

    @Override
    public void mousePressed(MouseEvent e)
    {
    }

    @Override
    public void mouseReleased(MouseEvent e)
    {
    }

    @Override
    public void mouseEntered(MouseEvent e)
    {
    }

    @Override
    public void mouseExited(MouseEvent e)
    {
    }

    @Override
    public void keyTyped(KeyEvent e)
    {

    }

    @Override
    public void keyPressed(KeyEvent e)
    {

    }

}

当我尝试在数据库中插入一个新行时出现问题(当设置 gameover 变量时,即 gameover = true)。 显然,应用程序正确地插入了数据库,但是当我尝试重玩游戏时,我收到了一些关于事件调度线程的异常,游戏不再继续。 到目前为止,我已经尝试在将数据插入数据库时​​停止计时器,然后重新启动它,但没有成功。 您有什么意见,我应该怎么做才能解决这个问题?

P.S:除了这个问题,游戏运行没有任何问题。

堆栈跟踪:

Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException
    at java.util.Scanner.throwFor(Unknown Source)
    at java.util.Scanner.next(Unknown Source)
    at flappyBird.FlappyBird.jump(FlappyBird.java:128)
    at flappyBird.FlappyBird.keyReleased(FlappyBird.java:322)
    at java.awt.Component.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Window.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access0(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

在跳转例程中,您放错了代码。它基本上尝试在跳跃中扫描玩家(名称)输入。

按照您的逻辑,您两次执行此例程,但第二次失败了。由于 System.in 在游戏之间收集的输入,它很可能会失败。

在查询之前刷新你的 System.in,或者更好的是,使用 Swing 库实际询问玩家名称 in-game。