【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); } } }
これでちゃんと当たり判定ができていることが確認できました。
ディスカッション
コメント一覧
まだ、コメントがありません