Java 如何使由两个不同图形对象绘制的两个对象相交?

Java 如何使由两个不同图形对象绘制的两个对象相交?,java,swing,graphics,awt,java-2d,Java,Swing,Graphics,Awt,Java 2d,我正在尝试创建一个游戏。在这个游戏中,UI显示了多条路径(JPanel),其中障碍物(某种JComponent)沿着路径移动。用户(玩家)必须左右移动或切换路径以避开障碍物。这个游戏类似于谷歌小马快车 目前,由于我处于发展阶段,我只有一条道路。 我有一个Player类,它扩展了JComponent,重写了paint Component方法并绘制了一个蓝色正方形。我有一个障碍组件类,它还扩展了JComponent,覆盖了paint Component方法,并画了一个黑圈 在我的Board类中,我

我正在尝试创建一个游戏。在这个游戏中,UI显示了多条路径(JPanel),其中障碍物(某种JComponent)沿着路径移动。用户(玩家)必须左右移动或切换路径以避开障碍物。这个游戏类似于谷歌小马快车

目前,由于我处于发展阶段,我只有一条道路。 我有一个Player类,它扩展了JComponent,重写了paint Component方法并绘制了一个蓝色正方形。我有一个障碍组件类,它还扩展了JComponent,覆盖了paint Component方法,并画了一个黑圈

在我的Board类中,我创建了一个名为theGame的JPanel,并将一条路径和路径内部、一个障碍组件和一个玩家放在其中。这个JPanel被放入一个JFrame中

玩家可以使用按键侦听器自由移动。我将把障碍组件放在一个地方,使调试更容易。这不是主要问题。问题是我想在玩家越过障碍物时结束游戏。我创建类似于构件主体的骨架矩形。例如,蓝色正方形的矩形就是正方形,而圆形的矩形覆盖了它内部的大部分区域。所以我在两个矩形上调用intersects方法,如果为真,我就结束游戏。 但是,intersect方法不起作用。即使玩家和障碍物没有明显接触,intersects方法也会返回true。(不,不存在错误的刷新或类似问题)。我如何使这两个对象相交? 如果回答者需要,将提供代码

观察:我不确定,但我相信用于绘制玩家和障碍物的图形对象是不同的。为了验证这个假设,我在每个paintComponent方法中画了一个绿色正方形,如下所示:

public void paintComponent(Graphics g)
{
    //code to create the blue square
    g2 = (Graphics2D) g;
    rect = new Rectangle(x,y,w,h);
    g2.setColor(Color.BLUE);
    g2.fill(rect);
    g2.draw(rect);

    //code to see the green rectangle
    Rectangle bill = new Rectangle(100,100,w,h);
    g2.setColor(Color.GREEN);
    g2.fill(bill);
    g2.draw(bill);
}
理由是,如果我使用player和barrier的图形对象绘制一个具有相同坐标的绿色矩形,它们应该在JPanel上的相同位置结束。相反,绿色矩形对象显示在两个不同的位置。这让我相信图形对象使用不同的坐标系。如果是,如何为多个图形对象使用一个通用坐标系

MCVE:我不能使类更小,因为如果我这样做,代码就不能工作。 球员级别:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.event.*;
public class Player extends JComponent
{
private int x;
private int y;
private int h = 20;
private int w = 20;
private Rectangle rect;
private int dx=5; 
private int dy=5;
private Graphics2D g2;
public Player(int x, int y)
{
    this.x = x;
    this.y = y;
    rect= new Rectangle(x,y,w,h);
}

public void assignGraphics(Graphics g)
{
    g2 = (Graphics2D)g;
}

public Player()
{
    x=0;
    y=0;
}

public void paintComponent(Graphics g)
{

    g2 = (Graphics2D) g;
    rect = new Rectangle(x,y,w,h);
    g2.setColor(Color.BLUE);
    g2.fill(rect);
    g2.draw(rect);


    Rectangle test = new Rectangle(100,100,w,h);
    g2.setColor(Color.GREEN);
    g2.fill(test);
    g2.draw(test);
}

public Rectangle getRectComp()
{
    return rect;
}

public void setMove(int a, int b)
{
    x=x+a; 
    y=y+b;
    repaint();
}

public int getX()
{
    return x;
}

public int getY()
{
    return y;
}

}
障碍物组件:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import java.io.IOException;
public class ObstacleComponent extends JComponent
{
private int x;
private int y;
public Ellipse2D.Double elli;
private int dx=5; 
private int dy=5;
private int h;
private int w;
private Graphics2D g2;
public ObstacleComponent(int x, int y, int h, int w)
{
    this.x = x;
    this.y = y;
    this.h = h;
    this.w = w;
}

public void assignGraphics(Graphics g)
{
    g2 = (Graphics2D)g;
}

public ObstacleComponent()
{
    x=0;
    y=0;
}

public void paintComponent(Graphics g) // method declaration- a method which overrides the paintComponent method from the JComponent class. 
// This method takes in an explicit parameter of a Graphics object
{
    g2 = (Graphics2D) g;
    elli = new Ellipse2D.Double(x,y,w,h);
    g2.setColor(Color.BLACK);
    g2.fill(elli);
    g2.draw(elli);
    Rectangle test= new Rectangle(0,0,w,h);
    g2.setColor(Color.GREEN);
    g2.fill(test);
    g2.draw(test);
}

public void setMove(int a, int b)
{
    x=x+a; // sets the dx variable to the value of parameter variable a
    y=y+b;
    repaint();
}

public int getX()
{
    return x;
}

public int getY()
{
    return y;
}

public Rectangle getRectComp()
{
    return new Rectangle(x,y,20,20);
}
}
路径:


坐标是相对于组件的。因此,传递到
paintComponent
的图形的
0,0
是正在绘制的组件的左上角。“这让我相信图形对象使用不同的坐标系。”是的,我认为你的想法是正确的。如何修复你的程序,我不太清楚。考虑发布A来回答这个问题。另外,请看一个没有组件的动画示例。请尝试打印两个组件的位置。您可以执行
System.out.println(“Component1:+Component1.getBounds())和第二个组件的类似wise。最有可能的情况是,您没有将两个组件完全层叠在一起,因此,是的,图形对象将被设置为不同的坐标根。“不知何故,您必须将此要求写入“图形坐标空间项”,无论它是如何、何时或由谁实现的。因此,我建议您需要定义另一组只与“游戏状态”相关的(!)类。这些类不“做”任何事情。他们不“画”任何东西,等等。相反:*他们是目前“游戏状态”的主人。他们是“权威”。那些“画东西”和“处理用户输入”的类仅仅是这些主人类的仆人。为了进一步澄清上述内容:“所有‘画东西’的各种类……只有在主人(通过回调等)的时候才‘画东西’。”同样地,“所有处理用户输入的不同类”。。。只需通知大师们这些事件已经发生。(而且,为了避开任何类型的计时问题,他们可能会“向队列发送消息”。)作为(唯一)游戏状态的真正仲裁者,大师们因此能够意识到“两个对象相交”,并向其下属发出适当的命令。为了更快地获得更好的帮助,发布一个(最小的完整可验证示例)或(简短、独立、正确的示例)。
import javax.swing.*;
import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 
import java.util.*;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableColumn;
import java.awt.event.*;
import javax.swing.border.EtchedBorder;
public class Path extends JPanel implements ActionListener
{
public ArrayList <ObstacleComponent> badGuys;
private int interval;
private int xDimension = 1000;
private int yDimension = 600;
private Graphics2D pen;
public Path(int rate)
{
    badGuys = new ArrayList<ObstacleComponent>();
    setPreferredSize(new Dimension(xDimension, yDimension));
    setBorder(new EtchedBorder());
    setLayout(new GridLayout(1,1));
}

public Graphics2D getG()
{
    return pen;
}

public void actionPerformed(ActionEvent av)
{
    if(interval%10==0)
    {  
        badGuys.add(new ObstacleComponent(200,10,20,20));
        add(badGuys.get(badGuys.size()-1));
        badGuys.get(badGuys.size()-1).assignGraphics(pen);
    }
    for(int b = 0;b<badGuys.size();b++)
    {

        badGuys.get(b).setMove(-5,0);

    }

    removeObstaclesOffTheScreen();
    repaint();
    interval++;
}

public void removeObstaclesOffTheScreen()
{
    for(int b = 0;b<badGuys.size();b++)
    {
        if(badGuys.get(b).getX()<0)
        {
            remove(badGuys.remove(b));
        }
    }
}

}
import javax.swing.*;
import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 
import java.util.*;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableColumn;
import java.awt.event.*;
import javax.swing.border.EtchedBorder;
public class Board  implements ActionListener {

    // instance variables - replace the example below with your own
    private ArrayList<Path> paths; 
    public JPanel theGame;
    private  int interval;
    private int currentPlayerPath;
    public Player player;
    private int pathNumber = 1;//4;
    private int levelTime;
    private int levelRate;
    private boolean notGameOver;
    private int removeThisCounter=0;
    private int timeToChangeRate;
    private Random gen;
    private int levelRange = 20;
    public Board()
    {
        theGame = new JPanel();
        setLayout(pathNumber);
        player = new Player();
        levelRate = 0;
        paths =  new ArrayList<Path>();  
        gen = new Random();
        for(int a = 0;a<pathNumber;a++)
        {
            paths.add(new Path(getRandomRate()));
        }
        for(int a = 0;a<pathNumber;a++)
        {
            theGame.add(paths.get(a));
        }
        currentPlayerPath=0;
        setCurrentPlayerPath();
    }

    public JPanel returnTheGamePanel()
    {
        return theGame;
    }


    public void setLayout(int paths)
    {
        theGame.setLayout(new GridLayout(pathNumber, paths));
    }


    public void setCurrentPlayerPath()
    {
        paths.get(currentPlayerPath).add(player);
        player.assignGraphics(paths.get(currentPlayerPath).getG());
    }

    public boolean hit()
    {
        Path currentPath = paths.get(currentPlayerPath);
        for(int a = 0;a<currentPath.badGuys.size();a++)
        {
            Object b = player.getRectComp();
            Object c = currentPath.badGuys.get(a).getRectComp();
            if (((Rectangle)b).intersects((Rectangle)c))
            {
                return true;
            }
            else
            {
                System.out.println("player: " + player.getX() + " " + player.getY());
                System.out.println("badguy: " + currentPath.badGuys.get(a).getX() + " " + currentPath.badGuys.get(a).getY());             
            } 
        }
        return false;
    }

    public void actionPerformed(ActionEvent av)
    {
        for(int a = 0;a<pathNumber;a++)
        {
            paths.get(a).actionPerformed(av);  
        }

        player.repaint();
        theGame.revalidate();
        theGame.repaint();
    }

    public void gameOver()
    {  
        notGameOver=!notGameOver;
    }

    public boolean isGameOver()
    {
        return notGameOver;
    }
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.sound.sampled.*;
import java.io.*;
import java.awt.geom.*;

public class Engine {

public static void main (String[] args) {        
    JOptionPane.showMessageDialog(null, "Press arrow key to move.");
    final JFrame display = new JFrame(); 
    display.setSize(1000, 600); 
    display.setTitle("Code does not work"); 
    display.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    final Board b = new Board();
    class TimedAction implements ActionListener
    {
        private int removeThisCounter=0;
        public void actionPerformed(ActionEvent av)
        {
            b.actionPerformed(av);
            if(b.hit())
            {
                System.out.println("HIT!!"+removeThisCounter);
                removeThisCounter++;
            }               

            display.revalidate();
            display.repaint();
        }

    }
    class PlayerAction implements KeyListener
    {
        public void keyPressed (KeyEvent e) { 
            int keyCode = e.getKeyCode(); 
            if(keyCode==KeyEvent.VK_LEFT)
            {
                b.player.setMove(-7, 0);

            }
            if(keyCode==KeyEvent.VK_RIGHT)
            {
                 b.player.setMove(7, 0);

            }
            if(keyCode==KeyEvent.VK_UP)
            {
                b.player.setMove(0,-7);

            }
            if(keyCode==KeyEvent.VK_DOWN)
            {
                 b.player.setMove(0,7);

            }
            else
            {
                b.player.setMove(0,0);

            }               
        }

        public void keyReleased(KeyEvent e) {} //method delcaration for empty methods needed to override the abstract methods of the KeyListener interface
        public void keyTyped(KeyEvent e) {}
    }
    Timer theTime = new Timer(1000, new TimedAction());
    theTime.start();
    JPanel masterPanel = new JPanel();
    display.addKeyListener(new PlayerAction()); 
    masterPanel.add(b.returnTheGamePanel());
    display.add(masterPanel);
    display.setVisible(true); 
}
}