有没有一种方法可以在Java Swing中绘制非矩形的边界?

huangapple go评论78阅读模式
英文:

Is there a way to draw boundaries that aren't rectangles in java swing?

问题

我正在尝试为我在一个JFrame上移动的角色绘制边界。我知道如何绘制矩形来建立边界,但如果我想要绘制边界的区域不是矩形,我该如何做呢?


举个例子,假设我想要在正方形中移动绿色圆圈,但蓝色菱形表示边界,圆圈不能超出这些边界。我该如何做呢?

英文:

I'm trying to draw boundaries for a character that I'm moving around on a JFrame. I know how to draw rectangles to establish boundaries, but how could I do this if the area that I want to draw bounds for isn't a rectangle?


Say for example I want to move the green circle around in the square, but the blue diamond represents the boundaries, and the circle cannot go past those bounds. How could I do this?

有没有一种方法可以在Java Swing中绘制非矩形的边界?

答案1

得分: 1

这是我用于线段/点碰撞的类型:

http://www.jeffreythompson.org/collision-detection/line-circle.php

它的数学性质相当复杂,但它运行得很好,没有bug。

英文:

This is the kind of thing I use for this is line/point collision:

http://www.jeffreythompson.org/collision-detection/line-circle.php

it's pretty mathy but it works nicely and isn't buggy

答案2

得分: 0

只需将您的圆视为矩形,并使用Rectanglecontains方法验证圆是否位于菱形内部(查看文档)。小片段代码如下:

private Rectangle rect = new Rectangle(25, 25, 450, 450);
private Rectangle circle = new Rectangle(250, 250, 50, 50);

if(rect.contains(tmp)) {
   // 如果圆不接触任何正方形边线,则为True
}

完整代码示例:

package circlemoving;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.*;
import javax.swing.*;

public class CircleMoving {

    public static void main(String[] args) {
        MainPanel mp = new MainPanel();
        JFrame jFrame = new JFrame();
        jFrame.add(mp);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setVisible(true);
        jFrame.pack();

        jFrame.addKeyListener(new KeyListener() {
            @Override public void keyTyped(KeyEvent e) {}
            @Override public void keyReleased(KeyEvent e) {}

            @Override
            public void keyPressed(KeyEvent e) {
                mp.update(e.getKeyCode());
            }            
        });
    }

    private static class MainPanel extends JPanel {
        private Rectangle rect = new Rectangle(25, 25, 450, 450);
        private Rectangle circle = new Rectangle(250, 250, 50, 50);

        public MainPanel() {
            setPreferredSize(new Dimension(500, 500));
            repaint();
        }

        @Override
        public void paintComponent(Graphics grahpics) {
            super.paintComponent(grahpics);

            Graphics2D g2d = (Graphics2D) grahpics;

            g2d.setStroke(new BasicStroke(1));
            g2d.setColor(Color.BLUE);
            g2d.drawRect(rect.x, rect.y, rect.width, rect.height);

            g2d.setStroke(new BasicStroke(1));
            g2d.setColor(Color.RED);
            g2d.drawOval(circle.x, circle.y, circle.width, circle.width);
        }

        public void update(int keyCode) {
            int tmpX = circle.x;
            int tmpY = circle.y;

            switch (keyCode) {
                case 39:
                    tmpX = circle.x + 3;
                    break;
                case 37:
                    tmpX = circle.x - 3;
                    break;
                case 38:
                    tmpY = circle.y - 3;
                    break;
                case 40:
                    tmpY = circle.y + 3;
                    break;
                default:
                    break;
            }

            Rectangle tmp = new Rectangle(tmpX, tmpY, circle.width, circle.height);

            if(rect.contains(tmp)) {
                circle.x = tmpX;
                circle.y = tmpY;

                repaint();
            }
        }
    }
}

结果:
有没有一种方法可以在Java Swing中绘制非矩形的边界?

英文:

Just treat your circle as a rectangle and validate if the circle is inside your diamond with the contains method of Rectangle (See docs). Small snipped:

private Rectangle rect = new Rectangle(25, 25, 450, 450);
private Rectangle circle = new Rectangle(250, 250, 50, 50);
if(rect.contains(tmp)) {
// True, if the circle does not touch any square-line
}

A full example of the code:

package circlemoving;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.*;
import javax.swing.*;
public class CircleMoving {
public static void main(String[] args) {
MainPanel mp = new MainPanel();
JFrame jFrame = new JFrame();
jFrame.add(mp);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
jFrame.pack();
jFrame.addKeyListener(new KeyListener() {
@Override public void keyTyped(KeyEvent e) {}
@Override public void keyReleased(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
mp.update(e.getKeyCode());
}            
});
}
private static class MainPanel extends JPanel {
private Rectangle rect = new Rectangle(25, 25, 450, 450);
private Rectangle circle = new Rectangle(250, 250, 50, 50);
public MainPanel() {
setPreferredSize(new Dimension(500, 500));
repaint();
}
@Override
public void paintComponent(Graphics grahpics) {
super.paintComponent(grahpics);
Graphics2D g2d = (Graphics2D) grahpics;
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.BLUE);
g2d.drawRect(rect.x, rect.y, rect.width, rect.height);
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.RED);
g2d.drawOval(circle.x, circle.y, circle.width, circle.width);
}
public void update(int keyCode) {
int tmpX = circle.x;
int tmpY = circle.y;
switch (keyCode) {
case 39:
tmpX = circle.x + 3;
break;
case 37:
tmpX = circle.x - 3;
break;
case 38:
tmpY = circle.y - 3;
break;
case 40:
tmpY = circle.y + 3;
break;
default:
break;
}
Rectangle tmp = new Rectangle(tmpX, tmpY, circle.width, circle.height);
if(rect.contains(tmp)) {
circle.x = tmpX;
circle.y = tmpY;
repaint();
}
}
}
}

Result:
有没有一种方法可以在Java Swing中绘制非矩形的边界?

答案3

得分: 0

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

public class PolygonBoundary implements Runnable {

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

    private Boundary boundary;

    private Dimension dpSize;

    private Player player;

    public PolygonBoundary() {
        this.dpSize = new Dimension(400, 400);

        Polygon polygon = new Polygon();
        polygon.addPoint(200, 0);
        polygon.addPoint(0, 200);
        polygon.addPoint(200, 400);
        polygon.addPoint(400, 200);
        this.boundary = new Boundary(polygon, Color.BLUE);

        this.player = new Player(200, 200, 24, Color.GREEN);
    }

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

        DrawingPanel drawingPanel = new DrawingPanel(dpSize, boundary, player);

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

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private Boundary boundary;

        private Player player;

        public DrawingPanel(Dimension size, Boundary boundary, Player player) {
            this.boundary = boundary;
            this.player = player;
            this.setPreferredSize(size);
            Border border = BorderFactory.createLineBorder(Color.BLACK, 4);
            this.setBorder(border);
            PlayerMotion playerMotion = new PlayerMotion(this, boundary, player);
            this.addMouseListener(playerMotion);
        }

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

            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(boundary.getColor());
            g2d.setStroke(new BasicStroke(4f));
            g2d.drawPolygon(boundary.getPolygon());

            g2d.setColor(player.getColor());
            Point center = player.getCenter();
            int radius = player.getRadius();
            int diameter = radius + radius;
            g2d.drawOval(center.x - radius, center.y - radius, diameter, diameter);
        }
    }

    public class PlayerMotion implements MouseListener {

        private Boundary boundary;

        private JPanel panel;

        private Player player;

        private Point originalPoint;

        public PlayerMotion(JPanel panel, Boundary boundary, Player player) {
            this.panel = panel;
            this.boundary = boundary;
            this.player = player;
        }

        @Override
        public void mouseClicked(MouseEvent event) {

        }

        @Override
        public void mousePressed(MouseEvent event) {
            Point center = player.getCenter();
            int radius = player.getRadius();
            Rectangle2D r2d = createRectangle(center, radius);
            if (r2d.contains(event.getPoint())) {
                originalPoint = event.getPoint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent event) {
            if (originalPoint == null) {
                return;
            }

            Point endPoint = event.getPoint();

            Point center = player.getCenter();
            int radius = player.getRadius();
            int newX = center.x - originalPoint.x + endPoint.x;
            int newY = center.y - originalPoint.y + endPoint.y;
            Point newPoint = new Point(newX, newY);
            Rectangle2D r2d = createRectangle(newPoint, radius);

            Polygon polygon = boundary.getPolygon();

            if (polygon.contains(r2d)) {
                player.setCenter(newPoint);
                panel.repaint();
            }

            originalPoint = null;
        }

        private Rectangle2D createRectangle(Point center, int radius) {
            double dx = center.x - radius;
            double dy = center.y - radius;
            double d = radius + radius;
            Rectangle2D r2d = new Rectangle2D.Double(dx, dy, d, d);
            return r2d;
        }

        @Override
        public void mouseEntered(MouseEvent event) {

        }

        @Override
        public void mouseExited(MouseEvent event) {

        }

    }

    public class Boundary {

        private final Color color;

        private final Polygon polygon;

        public Boundary(Polygon polygon, Color color) {
            this.polygon = polygon;
            this.color = color;
        }

        public Polygon getPolygon() {
            return polygon;
        }

        public Color getColor() {
            return color;
        }

    }

    public class Player {

        private final int radius;

        private final Color color;

        private Point center;

        public Player(int x, int y, int radius, Color color) {
            this.center = new Point(x, y);
            this.radius = radius;
            this.color = color;
        }

        public int getRadius() {
            return radius;
        }

        public Point getCenter() {
            return center;
        }

        public void setCenter(Point center) {
            this.center = center;
        }

        public Color getColor() {
            return color;
        }

    }

}
英文:

I created a simple GUI to demonstrate how to use a polygon boundary in a Swing GUI. Here's the GUI.

有没有一种方法可以在Java Swing中绘制非矩形的边界?

You can't see in the picture, but you can grab the green circle (the player) with the mouse and drag it anywhere inside the blue diamond (the boundary). The code will not let you drag the player outside the boundary.

Here's what I did.

  1. I created two model classes. One for the boundary, and one for the player. I used this logical model to draw in the view and do calculations in the mouse listener. This is an application of the model / view / controller pattern.

  2. I created a simple Swing GUI with a drawing panel. I calculated where the start of the oval would be so I could keep the center point and radius in the model.

  3. I created a mouse listener class to listen for the mouse press and mouse release.

And here's the code. Hopefully, there's not much to explain. The Polygon class has a method, contains, that checks if a rectangle is completely inside the polygon. I converted the circle to a rectangle in the listener so I could use this method.

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class PolygonBoundary implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new PolygonBoundary());
}
private Boundary boundary;
private Dimension dpSize;
private Player player;
public PolygonBoundary() {
this.dpSize = new Dimension(400, 400);
Polygon polygon = new Polygon();
polygon.addPoint(200, 0);
polygon.addPoint(0, 200);
polygon.addPoint(200, 400);
polygon.addPoint(400, 200);
this.boundary = new Boundary(polygon, Color.BLUE);
this.player = new Player(200, 200, 24, Color.GREEN);
}
@Override
public void run() {
JFrame frame = new JFrame("Polygon Boundary");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = 
new DrawingPanel(dpSize, boundary, player);
frame.add(drawingPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Boundary boundary;
private Player player;
public DrawingPanel(Dimension size, Boundary boundary, 
Player player) {
this.boundary = boundary;
this.player = player;
this.setPreferredSize(size);
Border border = BorderFactory.createLineBorder(
Color.BLACK, 4);
this.setBorder(border);
PlayerMotion playerMotion = 
new PlayerMotion(this, boundary, player);
this.addMouseListener(playerMotion);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(boundary.getColor());
g2d.setStroke(new BasicStroke(4f));
g2d.drawPolygon(boundary.getPolygon());
g2d.setColor(player.getColor());
Point center = player.getCenter();
int radius = player.getRadius();
int diameter = radius + radius;
g2d.drawOval(center.x - radius, center.y - radius, 
diameter, diameter);
}
}
public class PlayerMotion implements MouseListener {
private Boundary boundary;
private JPanel panel;
private Player player;
private Point originalPoint;
public PlayerMotion(JPanel panel, Boundary boundary, 
Player player) {
this.panel = panel;
this.boundary = boundary;
this.player = player;
}
@Override
public void mouseClicked(MouseEvent event) {
}
@Override
public void mousePressed(MouseEvent event) {
Point center = player.getCenter();
int radius = player.getRadius();
Rectangle2D r2d = createRectangle(center, radius);
if (r2d.contains(event.getPoint())) {
originalPoint = event.getPoint();
}
}
@Override
public void mouseReleased(MouseEvent event) {
if (originalPoint == null) {
return;
}
Point endPoint = event.getPoint();
Point center = player.getCenter();
int radius = player.getRadius();
int newX = center.x - originalPoint.x + endPoint.x;
int newY = center.y - originalPoint.y + endPoint.y;
Point newPoint = new Point(newX, newY);
Rectangle2D r2d = createRectangle(newPoint, radius);
Polygon polygon = boundary.getPolygon();
if (polygon.contains(r2d)) {
player.setCenter(newPoint);
panel.repaint();
}
originalPoint = null;
}
private Rectangle2D createRectangle(Point center, int radius) {
double dx = center.x - radius;
double dy = center.y - radius;
double d = radius + radius;
Rectangle2D r2d = new Rectangle2D.Double(dx, dy, d, d);
return r2d;
}
@Override
public void mouseEntered(MouseEvent event) {
}
@Override
public void mouseExited(MouseEvent event) {
}
}
public class Boundary {
private final Color color;
private final Polygon polygon;
public Boundary(Polygon polygon, Color color) {
this.polygon = polygon;
this.color = color;
}
public Polygon getPolygon() {
return polygon;
}
public Color getColor() {
return color;
}
}
public class Player {
private final int radius;
private final Color color;
private Point center;
public Player(int x, int y, int radius, Color color) {
this.center = new Point(x, y);
this.radius = radius;
this.color = color;
}
public int getRadius() {
return radius;
}
public Point getCenter() {
return center;
}
public void setCenter(Point center) {
this.center = center;
}
public Color getColor() {
return color;
}
}
}

huangapple
  • 本文由 发表于 2020年4月7日 02:56:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/61066999.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定