1

我在尝试用 Java 制作的游戏时遇到问题。我正在尝试将 MouseListener 附加到我的画布上,但是,当我单击画布时,什么也没有发生。我想我可能将 MouseListener 附加到错误的东西上,但我不知道将它附加到什么。我尝试将它附加到 JFrame 和画布上。这是我的代码:

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.Random;

public class Gravity extends Canvas {

    public static final int screenw = 1024;
    public static final int screenh = 768;

    public static Random gen = new Random();

    public static Boolean started = false;

    public static int[] starx = new int[100];
    public static int[] stary = new int[100];
    public static Color[] starc = new Color[100];

    public static JFrame frame;
    public static Gravity canvas;
    public static Image buffer;
    public static Graphics bg;

    public static int[] xh = new int[1000];
    public static int[] yh = new int[1000];

    public static int i = 0;

    public static Image title;

    public static ArrayList<Integer> ptx = new ArrayList<Integer>();
    public static ArrayList<Integer> pty = new ArrayList<Integer>();
    double x = 100;
    double y = 100;

    public Gravity(){
    }

    public void paint (Graphics g) {
        frame.addMouseListener(new MouseListener(){
            public void mouseClicked(MouseEvent e){
                started = true;
                System.out.println("Mouse was clicked");
            }

            public void mouseEntered(MouseEvent arg0) {}
            public void mouseExited(MouseEvent arg0) {}
            public void mousePressed(MouseEvent arg0) {}
            public void mouseReleased(MouseEvent arg0) {}
        });


        buffer = createImage(screenw, screenh);
        bg = buffer.getGraphics();

        int w = getWidth();
        int h = getHeight();

        double px = getWidth()/2; 
        double py = getHeight()/2;

        bg.setColor(Color.BLACK);
        bg.fillRect(0, 0, w, h); //black background

        for (int j=0; j < 100; j++){ //make stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
            bg.setColor(starc[j]);
            bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
            bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
        }

        try {
            title = ImageIO.read(new ByteArrayInputStream(Base64.decode(""))); //I have omitted the Base64 code for the image for my title screen
        } catch (IOException e) {
            e.printStackTrace();
        }

        bg.drawImage(title, 100, 100, null);
        g.drawImage(buffer, 0, 0, null);

        while (!started){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }

        double xvel = -15;
        double yvel = 10;

        for (int j=0; j < 100; j++){ //store stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
        }

        Image test = createImage(200,200);
        Graphics testg = test.getGraphics();
        testg.drawLine(50,50,150,150);

        while(true){
            g.drawImage(buffer, 0,0, null);
            try {
                Thread.sleep(33);
            } catch (Exception e) {
                e.printStackTrace();
            }

            bg.setColor(Color.BLACK);
            bg.fillRect(0, 0, w, h); //black background


            for (int j=0; j < 100; j++){ //draw stars
                bg.setColor(starc[j]);
                bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
                bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
            }

            bg.setColor(Color.BLUE);

            if (i > 0){
                for (int z=0; z < i-1; z++){
                    bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1));
                }
            }

            bg.setColor(Color.CYAN);
            bg.fillOval((int)px, (int)py, 25, 25); //planet

            bg.setColor(Color.RED);
            bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship

            double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2));

            double m = (y-py)/(x-px);
            double ms = Math.sqrt(Math.abs(m));
            if (m < 0) ms = -ms;

            double xchg = fg;
            double ychg = fg*ms;

            if (x > px){
                xchg = -xchg;
                ychg = -ychg;
            }

            xvel += xchg;
            yvel += ychg;

            x += xvel;
            y += yvel;

            ptx.add((int)x);
            pty.add((int)y);

            i++;
        }
    }

    public static void main(String[] args){

        canvas = new Gravity();
        frame = new JFrame();
        frame.setSize(screenw, screenh);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas);

        frame.setVisible(true);
    }


    public static double dist(double x1, double y1, double x2, double y2){
        double x = x2-x1;
        double y = y2-y1;
        return Math.sqrt((x*x)+(y*y));
    }
}
4

3 回答 3

3

一般提示,以点的形式:

  1. 不要将 AWT(例如Canvas)与 Swing(例如JFrame)组件混合使用。代替 Canvas,使用 aJPanel和 overridepaintComponent(Graphics)而不是paint(Graphics).
  2. 不要打电话Thread.sleep(n)给美国东部时间。而是使用基于 Swing 的Timer调用repaint()
  3. 不要对paint方法执行长时间运行的操作,尤其是启动一个无限循环!甚至缓冲区图像的创建也应该只在屏幕尺寸发生变化的情况下进行。(左为“待办事项”-BNI)
  4. 在构造函数或方法中添加MouseListener一次,init()而不是每次调用paint。
  5. 强烈推荐 Nate 的所有笔记编号列表。

试试这段代码,并仔细比较原始代码以查看更改。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.ArrayList;

import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.Random;

public class Gravity extends JPanel {

    public static final int screenw = 800;
    public static final int screenh = 600;

    public static Random gen = new Random();

    public static int[] starx = new int[100];
    public static int[] stary = new int[100];
    public static Color[] starc = new Color[100];

    public static Image buffer;
    public static Graphics bg;

    public static int[] xh = new int[1000];
    public static int[] yh = new int[1000];

    public static int i = 0;

    public static ArrayList<Integer> ptx = new ArrayList<Integer>();
    public static ArrayList<Integer> pty = new ArrayList<Integer>();
    double x = 100;
    double y = 100;

    Timer timer;

    public Gravity(){
        // set thre PREFERRED size!
        setPreferredSize(new Dimension(screenw, screenh));
        addMouseListener(new MouseListener(){
                    public void mouseClicked(MouseEvent e){
                        System.out.println("Mouse was clicked");
                        timer.start();
                    }

                    public void mouseEntered(MouseEvent arg0) {}
                    public void mouseExited(MouseEvent arg0) {}
                    public void mousePressed(MouseEvent arg0) {}
                    public void mouseReleased(MouseEvent arg0) {}
        });
        ActionListener animation = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                repaint();
            }
        };
        timer = new Timer(50, animation);
    }

    @Override
    public void paintComponent(Graphics g) {
        buffer = createImage(screenw, screenh);
        bg = buffer.getGraphics();

        int w = getWidth();
        int h = getHeight();

        double px = getWidth()/2;
        double py = getHeight()/2;

        bg.setColor(Color.BLACK);
        bg.fillRect(0, 0, w, h); //black background

        for (int j=0; j < 100; j++){ //make stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
            bg.setColor(starc[j]);
            bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
            bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
        }

        g.drawImage(buffer, 0, 0, null);

        double xvel = -15;
        double yvel = 10;

        for (int j=0; j < 100; j++){ //store stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
        }

        Image test = createImage(200,200);
        Graphics testg = test.getGraphics();
        testg.drawLine(50,50,150,150);

        g.drawImage(buffer, 0,0, null);
        try {
            Thread.sleep(33);
        } catch (Exception e) {
            e.printStackTrace();
        }

        bg.setColor(Color.BLACK);
        bg.fillRect(0, 0, w, h); //black background


        for (int j=0; j < 100; j++){ //draw stars
            bg.setColor(starc[j]);
            bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
            bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
        }

        bg.setColor(Color.BLUE);

        if (i > 0){
            for (int z=0; z < i-1; z++){
                bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1));
            }
        }

        bg.setColor(Color.CYAN);
        bg.fillOval((int)px, (int)py, 25, 25); //planet

        bg.setColor(Color.RED);
        bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship

        double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2));

        double m = (y-py)/(x-px);
        double ms = Math.sqrt(Math.abs(m));
        if (m < 0) ms = -ms;

        double xchg = fg;
        double ychg = fg*ms;

        if (x > px){
            xchg = -xchg;
            ychg = -ychg;
        }

        xvel += xchg;
        yvel += ychg;

        x += xvel;
        y += yvel;

        ptx.add((int)x);
        pty.add((int)y);

        i++;
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(new Gravity());
                frame.setResizable(false);
                frame.pack();

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


    public static double dist(double x1, double y1, double x2, double y2){
        double x = x2-x1;
        double y = y2-y1;
        return Math.sqrt((x*x)+(y*y));
    }
}
于 2012-05-11T18:38:43.613 回答
1

由于永远不会退出的 while (!started) 循环,您的 paint() 方法正在占用处理鼠标单击事件的线程。started 永远不会为真,因为永远不会调用 MouseListener 的 mouseClicked(),因为 paint() 方法正在等待 started 为真!如果删除该循环,while (true) 循环将产生类似的效果。在paint() 运行时发生的任何鼠标事件都将排队,直到paint() 返回。

于 2012-05-11T18:21:44.780 回答
1

使用 JComponent 而不是 Canvas。您需要将鼠标侦听器添加到该对象。您还需要在构造函数中设置鼠标侦听器,而不是 paint() 方法。

编辑:正如@AndrewThompson 指出的那样,您在 paint() 方法中做了很多工作。

public Gravity() {
    addMouseListener(new MouseListener() {

        @Override
        public void mouseClicked(MouseEvent e) {
            System.out.println("Mouse was clicked");
        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
        }

        @Override
        public void mouseExited(MouseEvent arg0) {
        }

        @Override
        public void mousePressed(MouseEvent arg0) {
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
        }
    });
}

@Override
public void paint(Graphics g) {

    buffer = createImage(screenw, screenh);
    bg = buffer.getGraphics();

    ...

    bg.setColor(Color.BLACK);
    bg.fillRect(0, 0, w, h); // black background

    for (int j = 0; j < 100; j++) { // make stars
        ...
    }

    bg.drawImage(title, 100, 100, null);
    g.drawImage(buffer, 0, 0, null);

    double xvel = -15;
    double yvel = 10;

    for (int j = 0; j < 100; j++) { // store stars
        ...
    }

    Image test = createImage(200, 200);
    Graphics testg = test.getGraphics();
    testg.drawLine(50, 50, 150, 150);

    g.drawImage(buffer, 0, 0, null);
    bg.setColor(Color.BLACK);
    bg.fillRect(0, 0, w, h); // black background

    for (int j = 0; j < 100; j++) { // draw stars
        ...
    }

    bg.setColor(Color.BLUE);

    if (i > 0) {
        for (int z = 0; z < i - 1; z++) {
            bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z + 1), pty.get(z + 1));
        }
    }

    bg.setColor(Color.CYAN);
    bg.fillOval((int) px, (int) py, 25, 25); // planet

    bg.setColor(Color.RED);
    bg.fillRect((int) (x - 5), (int) (y - 5), 10, 10); // ship

    ....

    ptx.add((int) x);
    pty.add((int) y);
}

public static void main(String[] args) {
    ...

    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    ...
}

关于您的代码的注释:

  1. 避免制作字段public static。99.9% 的情况下这是不必要的,而且通常会在以后导致麻烦。
  2. 绘画代码似乎不必要地使用了缓冲区——test目前根本没有使用图像!
  3. 我删除了while(true)循环,但注意到您正在绘制图像,修改图像,然后再次绘制图像。您可能可以一口气做到这一点。
  4. 您应该能够Image完全避免使用缓冲区,因为每次paint()调用时都会创建一个新缓冲区,并在开始时将其清除。只需将图形直接绘制到g.
  5. 避免在paint()方法内执行 I/O。在构建期间或在后台线程中加载图像。
于 2012-05-11T18:26:43.333 回答