【Java】多角形クラスと矩形との当たり判定
本稿はJavaのPolygonクラスについて紹介します。
Polygonクラスは多角形を表すオブジェクトで、それに関連するいろいろなメソッドを利用できます。
オブジェクトの作成
オブジェクトの作成は
new Polygon(x座標配列,y座標配列,点の数)
で定義します。
各x座標とy座標は配列の添え字番号で一致しています。
例えば、x座標配列が[100,50,3000]でy座標配列が[200,400,600]とした場合は点(100,200)と点(50,400)と点(3000,600)を直線で結んだ図形が作成されます。
drawPolygonメソッドと同じ要領ですね。
import java.awt.Polygon;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Polygon po = new Polygon(new int[] {100,150,200}, new int[] {150,100,150}, 3);
System.out.println(Arrays.toString(po.xpoints));
System.out.println(Arrays.toString(po.ypoints));
}
}
[100, 150, 200]
[150, 100, 150]
translateメソッド
現在の座標から指定した座標分移動させることができます。
import java.awt.Polygon;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Polygon po = new Polygon(new int[] {100,150,200}, new int[] {150,100,150}, 3);
po.translate(50, 50);
System.out.println(Arrays.toString(po.xpoints));
System.out.println(Arrays.toString(po.ypoints));
}
}
[150, 200, 250]
[200, 150, 200]
containsメソッド
多角形内に指定された座標が含まれているかを判定します。
contains(x座標,y座標)と定義しましょう。
点と多角形の当たり判定で利用できます。
import java.awt.Polygon;
public class Test {
public static void main(String[] args) {
Polygon po = new Polygon(new int[] {100,150,200}, new int[] {150,100,150}, 3);
System.out.println(po.contains(150, 130));
}
}
true
intersectsメソッド
intersectsメソッドを利用することで、多角形と矩形の当たり判定が実装できます。
Polygonオブジェクト.intesects(Rectangleオブジェクト)と定義しましょう。
それではサンプルをご覧ください。
import java.awt.Polygon;
import java.awt.Rectangle;
public class Test {
public static void main(String[] args) {
Polygon r1 = new Polygon(new int[] {100,150,200}, new int[] {150,100,150}, 3);
Rectangle r2 = new Rectangle(100, 100, 50, 50);
System.out.println(r1.intersects(r2));
}
}
true
多角形と矩形をアニメーションさせながら判定できているか確かめる
実際にアニメーションサンプルを実装して判定できているか確かめてみます。
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Polygon;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
TestWindow tw = new TestWindow("テスト", 400, 300);
tw.change(new DrawCanvas());
tw.setVisible(true);
tw.startGameLoop();
}
}
//ウィンドウクラス
class TestWindow extends JFrame implements Runnable{
private Thread th = null;
private double sleepAddTime;
private int fps=60;
public TestWindow(String title, int width, int height) {
super(title);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(width,height);
setLocationRelativeTo(null);
setLayout(null);
setResizable(false);
setFps(fps);
}
public synchronized void change(JPanel p) {
getContentPane().removeAll();
Insets inset = getInsets();
p.setBounds(-inset.left,-inset.top,getWidth(),getHeight());
add(p);
validate();
repaint();
}
public synchronized void startGameLoop(){
if ( th == null ) {
th = new Thread(this);
th.start();
}
}
public synchronized void stopGameLoop(){
if ( th != null ) {
th = null;
}
}
public void run(){
double nextTime = System.currentTimeMillis() + sleepAddTime;
while(th != null){
try{
long res = (long)nextTime - System.currentTimeMillis();
if ( res < 0 ) res = 0;
Thread.sleep(res);
repaint();
nextTime += sleepAddTime;
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void setFps(int fps){
if ( fps < 10 || fps > 60 ) {
throw new IllegalArgumentException("fpsの設定は10~60の間で指定してください。");
}
this.fps = fps;
sleepAddTime = 1000.0 / fps;
}
}
//移動アニメーション用クラス
class VertexMove2D{
private double x;
private double y;
private final int[] xpoints;
private final int[] ypoints;
private final int npoints;
private boolean isInvert;
private int currentPoint;
private int nextPoint;
private int speed;
private double mx;
private double my;
private double checkValue;
public VertexMove2D(int[] xpoints, int[] ypoints, int npoints, int speed, int initPoint) {
this.xpoints = xpoints;
this.ypoints = ypoints;
this.npoints = npoints;
this.speed = Math.abs(speed);
this.isInvert = speed < 0;
this.currentPoint = isInvert ? initPoint + 1 : initPoint - 1;
prepareNext();
}
private void prepareNext() {
if ( isInvert ) {
int currentPoint = this.currentPoint - 1;
if ( currentPoint < 0 ) currentPoint = npoints - 1;
this.currentPoint = currentPoint;
int nextPoint = currentPoint - 1;
this.nextPoint = nextPoint < 0 ? npoints - 1 : nextPoint;
} else {
int currentPoint = this.currentPoint + 1;
if ( currentPoint >= npoints ) currentPoint = 0;
this.currentPoint = currentPoint;
this.nextPoint = (currentPoint + 1) % npoints;
}
int sx = xpoints[currentPoint];
int sy = ypoints[currentPoint];
int ex = xpoints[nextPoint];
int ey = ypoints[nextPoint];
int vx = ex - sx;
int vy = ey - sy;
double rad = Math.atan2(vy, vx);
mx = Math.cos(rad) * speed;
my = Math.sin(rad) * speed;
checkValue = vx * vx + vy * vy;
x = sx;
y = sy;
}
public void draw(Graphics g) {
g.drawPolygon(xpoints, ypoints, npoints);
}
public void fill(Graphics g) {
g.fillPolygon(xpoints, ypoints, npoints);
}
public void move() {
double xx = x + mx;
double yy = y + my;
int sx = xpoints[currentPoint];
int sy = ypoints[currentPoint];
double vx = sx - xx;
double vy = sy - yy;
if ( checkValue <= vx * vx + vy * vy ) {
prepareNext();
} else {
x = xx;
y = yy;
}
}
public void invert() {
isInvert = !isInvert;
}
public boolean isInvert() {
return isInvert;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
if ( speed < 0 ) {
invert();
speed = -speed;
}
this.speed = speed;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
class DrawCanvas extends JPanel{
int[] x = {60,150,280,340,270,160,90,70};
int[] y = {80,200,90,120,150,250,240,260};
//図形の頂点を移動するオブジェクト。
VertexMove2D m1 = new VertexMove2D(
x
,y
,8//頂点の数
,2//移動速度
,0//配列の0番を開始地点に
);
//もう一つの図形の頂点を移動するオブジェクト。
VertexMove2D m2 = new VertexMove2D(
x
,y
,8//頂点の数
,-3//移動速度
,4//配列の4番を開始地点に
);
Polygon r1 = new Polygon(new int[] {100,150,200}, new int[] {150,100,150}, 3);
Rectangle r2 = new Rectangle(100, 100, 50, 50);
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D)g;
g.setColor(Color.RED);
g2.draw(r1);
g.setColor(Color.BLUE);
g2.draw(r2);
g.setColor(Color.GREEN);
m1.draw(g2);
m1.move();
Rectangle r1_rect = r1.getBounds();
r1.translate((int)(m1.getX()-r1_rect.getCenterX()), (int)(m1.getY()-r1_rect.getCenterY()));
m2.move();
r2.x = (int) (m2.getX()-r2.width / 2);
r2.y = (int) (m2.getY()-r2.height / 2);
g.setFont(new Font(Font.MONOSPACED,Font.BOLD,20));
if ( r1.intersects(r2) ) {
g.setColor(Color.RED);
g.drawString("当たっています", 50,50);
} else {
g.setColor(Color.BLUE);
g.drawString("当たってません", 50,50);
}
}
}
これでちゃんと当たり判定ができていることが確認できました。









ディスカッション
コメント一覧
まだ、コメントがありません