情報学部 菅沼ホーム Java 目次 基礎技術目次 索引

衝突判定

  1. オブジェクト同士

      二つの物体の衝突判定を行う一つの方法は,Graphics2D クラスhit メソッドを使用する方法です.この例に示すように,矩形と Shape インタフェースオブジェクトの衝突判定を簡単に実行できます.この例では,116 行目において,矩形 rec が cir の内部と交叉するか否かを調べています.なお,hit メソッド,
    hit(Rectangle rect, Shape s, boolean onStroke)			
    は,指定された Shape が指定された Rectangle と交差するかどうかを判定します.onStroke が false の場合,指定された Shape の内部が指定された Rectangle と交差するかどうかを調べ,true の場合は,指定された Shape の輪郭の Stroke が指定された Rectangle と交差するかどうかを調べます.
    001	import java.awt.*;
    002	import java.awt.event.*;
    003	import java.awt.geom.*;
    004	import javax.swing.*;
    005	
    006	public class Test {
    007		public static void main (String[] args)
    008		{
    009			Win win = new Win("オブジェクト同士の衝突判定1");
    010		}
    011	}
    012	
    013	class Win extends JFrame
    014	{
    015		/******************/
    016		/* コンストラクタ */
    017		/******************/
    018		Win(String name)
    019		{
    020						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    021			super(name);
    022						// Windowの大きさ
    023			setSize(640, 470);   // +40, +70
    024						// ContentPane の取得と MainPanel の追加
    025			Dimension d  = getSize();   // Windowの大きさ
    026			d.width     -= 40;
    027			d.height    -= 70;
    028			MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    029			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    030						// ウィンドウを表示
    031			setVisible(true);
    032						// イベントアダプタ
    033			addWindowListener(new WinEnd());
    034		}
    035	
    036		/******************************/
    037		/* 上,左,下,右の余白の設定 */
    038		/******************************/
    039		public Insets getInsets()
    040		{
    041			return new Insets(50, 20, 20, 20);
    042		}
    043	
    044		/************/
    045		/* 終了処理 */
    046		/************/
    047		class WinEnd extends WindowAdapter
    048		{
    049			public void windowClosing(WindowEvent e) {
    050				System.exit(0);
    051			}
    052		}
    053	}
    054	
    055	class MainPanel extends JPanel implements Runnable
    056	{
    057		boolean state = true;
    058		double x1, x2, y1, y2, t = 0.0, v = 20.0;
    059		Dimension d;
    060		Thread th;
    061		Rectangle rec;
    062		Ellipse2D.Double cir;
    063		boolean hit = false;
    064	
    065		MainPanel(Dimension d1)
    066		{
    067			d = d1;
    068			x1 = 0.0;
    069			x2 = d.width - 80;
    070			y1 = d.height / 2 - 40;
    071			y2 = d.height / 2 - 80;
    072			setBackground(new Color(238, 255, 238));   // 背景色の設定
    073			th = new Thread(this);   // スレッドの生成とスタート
    074			th.start();
    075		}
    076						// 他ページへ移動の際,一時的にスレッドを停止
    077		public void stop()
    078		{
    079			state = false;
    080		}
    081						// スレッドの実行
    082		public void run()
    083		{
    084			while (state) {
    085				try {
    086					th.sleep(33);
    087				}
    088				catch (InterruptedException e) {}
    089	
    090				if (hit)
    091					state = false;
    092				else {
    093					t += 0.1;
    094					x1 = v * t;
    095					x2 = d.width - 80 - v * t;
    096				}
    097	
    098				repaint();
    099			}
    100		}
    101						// 描画
    102		public void paintComponent(Graphics g)
    103		{
    104			super.paintComponent(g);   // 親クラスの描画
    105								// Graphics2Dの取得
    106			Graphics2D g2 = (Graphics2D)g;
    107								// 塗りつぶした矩形
    108			g2.setColor(Color.green);
    109			rec = new Rectangle((int)x1, (int)y1, 80, 80);
    110			g2.fill(rec);
    111								// 塗りつぶした円
    112			g2.setColor(Color.red);
    113			cir = new Ellipse2D.Double(x2, y2, 80, 80);
    114			g2.fill(cir);
    115								// 衝突判定
    116			hit = g2.hit(rec, cir, false);
    117		}
    118	}
    			
      上の例では,矩形と円との衝突判定でしたが,この例では,矩形三角形との衝突判定を行っています.なお,三角形は,Polygon クラスのオブジェクトとして,069 行目~ 071 行目で定義されています.
    001	import java.awt.*;
    002	import java.awt.event.*;
    003	import javax.swing.*;
    004	
    005	public class Test {
    006		public static void main (String[] args)
    007		{
    008			Win win = new Win("オブジェクト同士の衝突判定2");
    009		}
    010	}
    011	
    012	class Win extends JFrame
    013	{
    014		/******************/
    015		/* コンストラクタ */
    016		/******************/
    017		Win(String name)
    018		{
    019						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    020			super(name);
    021						// Windowの大きさ
    022			setSize(640, 470);   // +40, +70
    023						// ContentPane の取得と MainPanel の追加
    024			Dimension d  = getSize();   // Windowの大きさ
    025			d.width     -= 40;
    026			d.height    -= 70;
    027			MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    028			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    029						// ウィンドウを表示
    030			setVisible(true);
    031						// イベントアダプタ
    032			addWindowListener(new WinEnd());
    033		}
    034	
    035		/******************************/
    036		/* 上,左,下,右の余白の設定 */
    037		/******************************/
    038		public Insets getInsets()
    039		{
    040			return new Insets(50, 20, 20, 20);
    041		}
    042	
    043		/************/
    044		/* 終了処理 */
    045		/************/
    046		class WinEnd extends WindowAdapter
    047		{
    048			public void windowClosing(WindowEvent e) {
    049				System.exit(0);
    050			}
    051		}
    052	}
    053	
    054	class MainPanel extends JPanel implements Runnable
    055	{
    056		boolean state = true;
    057		double x1, y1, t = 0.0, v = 20.0;
    058		Dimension d;
    059		Thread th;
    060		Rectangle rec;
    061		Polygon tr;
    062		boolean hit = false;
    063	
    064		MainPanel(Dimension d1)
    065		{
    066			d = d1;
    067			x1 = 0.0;
    068			y1 = d.height / 2 - 40;
    069			int x[] = {d.width-80, d.width, d.width-40};
    070			int y[] = {d.height/2-80, d.height/2-80, d.height/2};
    071			tr = new Polygon(x, y, 3);
    072			setBackground(new Color(238, 255, 238));   // 背景色の設定
    073			th = new Thread(this);   // スレッドの生成とスタート
    074			th.start();
    075		}
    076						// 他ページへ移動の際,一時的にスレッドを停止
    077		public void stop()
    078		{
    079			state = false;
    080		}
    081						// スレッドの実行
    082		public void run()
    083		{
    084			while (state) {
    085				try {
    086					th.sleep(33);
    087				}
    088				catch (InterruptedException e) {}
    089	
    090				if (hit)
    091					state = false;
    092				else {
    093					t += 0.1;
    094					x1 = v * t;
    095					tr.translate(-2, 0);   // 左へ 2 ピクセルだけ平行移動
    096				}
    097	
    098				repaint();
    099			}
    100		}
    101						// 描画
    102		public void paintComponent(Graphics g)
    103		{
    104			super.paintComponent(g);   // 親クラスの描画
    105								// Graphics2Dの取得
    106			Graphics2D g2 = (Graphics2D)g;
    107								// 塗りつぶした矩形
    108			g2.setColor(Color.green);
    109			rec = new Rectangle((int)x1, (int)y1, 80, 80);
    110			g2.fill(rec);
    111								// 塗りつぶした三角形
    112			g2.setColor(Color.red);
    113			g2.fill(tr);
    114								// 衝突判定
    115			hit = g2.hit(rec, tr, false);
    116		}
    117	}
    			
      同様の判定を,Shape インタフェースintersects メソッドを使用しても可能です.この例では,上の例と同じ判定を intersects メソッドを使用して行っています.なお,intersects メソッド,
    intersects(double x, double y, double w, double h)			
    Shape の内部領域が,指定された矩形領域の内部領域と交差するかどうかを判定します.
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class Test {
    	public static void main (String[] args)
    	{
    		Win win = new Win("オブジェクト同士の衝突判定3");
    	}
    }
    
    class Win extends JFrame
    {
    	/******************/
    	/* コンストラクタ */
    	/******************/
    	Win(String name)
    	{
    					// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    		super(name);
    					// Windowの大きさ
    		setSize(640, 470);   // +40, +70
    					// ContentPane の取得と MainPanel の追加
    		Dimension d  = getSize();   // Windowの大きさ
    		d.width     -= 40;
    		d.height    -= 70;
    		MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    		getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    					// ウィンドウを表示
    		setVisible(true);
    					// イベントアダプタ
    		addWindowListener(new WinEnd());
    	}
    
    	/******************************/
    	/* 上,左,下,右の余白の設定 */
    	/******************************/
    	public Insets getInsets()
    	{
    		return new Insets(50, 20, 20, 20);
    	}
    
    	/************/
    	/* 終了処理 */
    	/************/
    	class WinEnd extends WindowAdapter
    	{
    		public void windowClosing(WindowEvent e) {
    			System.exit(0);
    		}
    	}
    }
    
    class MainPanel extends JPanel implements Runnable
    {
    	boolean state = true;
    	double x1, y1, t = 0.0, v = 20.0;
    	Dimension d;
    	Thread th;
    	Rectangle rec;
    	Polygon tr;
    	boolean hit = false;
    
    	MainPanel(Dimension d1)
    	{
    		d = d1;
    		x1 = 0.0;
    		y1 = d.height / 2 - 40;
    		int x[] = {d.width-80, d.width, d.width-40};
    		int y[] = {d.height/2-80, d.height/2-80, d.height/2};
    		tr = new Polygon(x, y, 3);
    		setBackground(new Color(238, 255, 238));   // 背景色の設定
    		th = new Thread(this);   // スレッドの生成とスタート
    		th.start();
    	}
    					// 他ページへ移動の際,一時的にスレッドを停止
    	public void stop()
    	{
    		state = false;
    	}
    					// スレッドの実行
    	public void run()
    	{
    		while (state) {
    			try {
    				th.sleep(33);
    			}
    			catch (InterruptedException e) {}
    							// 衝突判定
    			hit = tr.intersects(x1, y1, 80, 80);
    
    			if (hit)
    				state = false;
    			else {
    				t += 0.1;
    				x1 = v * t;
    				tr.translate(-2, 0);   // 左へ 2 ピクセルだけ平行移動
    			}
    
    			repaint();
    		}
    	}
    					// 描画
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);   // 親クラスの描画
    							// Graphics2Dの取得
    		Graphics2D g2 = (Graphics2D)g;
    							// 塗りつぶした矩形
    		g2.setColor(Color.green);
    		rec = new Rectangle((int)x1, (int)y1, 80, 80);
    		g2.fill(rec);
    							// 塗りつぶした三角形
    		g2.setColor(Color.red);
    		g2.fill(tr);
    	}
    }
    			

  2. オブジェクトと点

      この例では,楕円と円との衝突判定を行っています.このような場合,上で述べた方法を直接使用することはできません.なぜなら,いずれの方法においても,片方の図形は矩形である必要があるからです.図形を内包する矩形を求め,その矩形との衝突判定を行うのであれば上で述べた方法を適用できますが,図形によっては多少不正確になってしまいます.ここでは,右図に示すように,円周上に 12 個の点を設定し,それらの点が楕円内に入るか否かの判定を,Shape インタフェースcontains メソッドを使用して行っています.多くの点を設定すれば,それだけ正確な衝突判定が可能になりますし,また,この考え方は任意の図形に対して適用可能です.
    001	import java.awt.*;
    002	import java.awt.event.*;
    003	import java.awt.geom.*;
    004	import javax.swing.*;
    005	
    006	public class Test {
    007		public static void main (String[] args)
    008		{
    009			Win win = new Win("オブジェクトと点との衝突判定");
    010		}
    011	}
    012	
    013	class Win extends JFrame
    014	{
    015		/******************/
    016		/* コンストラクタ */
    017		/******************/
    018		Win(String name)
    019		{
    020						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    021			super(name);
    022						// Windowの大きさ
    023			setSize(640, 470);   // +40, +70
    024						// ContentPane の取得と MainPanel の追加
    025			Dimension d  = getSize();   // Windowの大きさ
    026			d.width     -= 40;
    027			d.height    -= 70;
    028			MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    029			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    030						// ウィンドウを表示
    031			setVisible(true);
    032						// イベントアダプタ
    033			addWindowListener(new WinEnd());
    034		}
    035	
    036		/******************************/
    037		/* 上,左,下,右の余白の設定 */
    038		/******************************/
    039		public Insets getInsets()
    040		{
    041			return new Insets(50, 20, 20, 20);
    042		}
    043	
    044		/************/
    045		/* 終了処理 */
    046		/************/
    047		class WinEnd extends WindowAdapter
    048		{
    049			public void windowClosing(WindowEvent e) {
    050				System.exit(0);
    051			}
    052		}
    053	}
    054	
    055	class MainPanel extends JPanel implements Runnable
    056	{
    057		boolean state = true;
    058		double x1, x2, y1, y2, t = 0.0, v = 20.0;
    059		double x[] = {40, 40*Math.cos(Math.PI/6), 40*Math.cos(Math.PI/3), 0, 40*Math.cos(2*Math.PI/3), 40*Math.cos(5*Math.PI/6), -40, 40*Math.cos(7*Math.PI/6), 40*Math.cos(4*Math.PI/3), 0, 40*Math.cos(5*Math.PI/3), 40*Math.cos(11*Math.PI/6)};
    060		double y[] = {0, 40*Math.sin(Math.PI/6), 40*Math.sin(Math.PI/3), 40, 40*Math.sin(2*Math.PI/3), 40*Math.sin(5*Math.PI/6), 0, 40*Math.sin(7*Math.PI/6), 40*Math.sin(4*Math.PI/3), -40, 40*Math.sin(5*Math.PI/3), 40*Math.sin(11*Math.PI/6)};
    061		Dimension d;
    062		Thread th;
    063		Ellipse2D.Double cir1, cir2;
    064		boolean hit = false;
    065	
    066		MainPanel(Dimension d1)
    067		{
    068			d = d1;
    069			x1 = 0.0;
    070			x2 = d.width - 80;
    071			y1 = d.height / 2 - 50;
    072			y2 = d.height / 2 - 80;
    073			cir1 = new Ellipse2D.Double(x1, y1, 80, 100);
    074			cir2 = new Ellipse2D.Double(x2, y2, 80, 80);
    075			setBackground(new Color(238, 255, 238));   // 背景色の設定
    076			th = new Thread(this);   // スレッドの生成とスタート
    077			th.start();
    078		}
    079						// 他ページへ移動の際,一時的にスレッドを停止
    080		public void stop()
    081		{
    082			state = false;
    083		}
    084						// スレッドの実行
    085		public void run()
    086		{
    087			while (state) {
    088				try {
    089					th.sleep(33);
    090				}
    091				catch (InterruptedException e) {}
    092								// 衝突判定
    093				for (int i1 = 0; i1 < 12; i1++) {
    094					hit = cir1.contains(x2+40+x[i1], y2+40+y[i1]);
    095					if (hit)
    096						break;
    097				}
    098								// 移動
    099				if (hit)
    100					state = false;
    101				else {
    102					t += 0.1;
    103					x1 = v * t;
    104					x2 = d.width - 80 - v * t;
    105				}
    106				repaint();
    107			}
    108		}
    109						// 描画
    110		public void paintComponent(Graphics g)
    111		{
    112			super.paintComponent(g);   // 親クラスの描画
    113								// Graphics2Dの取得
    114			Graphics2D g2 = (Graphics2D)g;
    115								// 塗りつぶした楕円
    116			g2.setColor(Color.green);
    117			cir1 = new Ellipse2D.Double(x1, y1, 80, 100);
    118			g2.fill(cir1);
    119								// 塗りつぶした円
    120			g2.setColor(Color.red);
    121			cir2 = new Ellipse2D.Double(x2, y2, 80, 80);
    122			g2.fill(cir2);
    123		}
    124	}
    			
    059 行目~ 060 行目

      配列の初期設定を利用して,12 個の点の座標を設定しています.

    093 行目~ 097 行目

      楕円と 12 個の各点との衝突判定を行っています.なお,096 行目の break 文が実行されると,break 文が入っている最も内側のループの外に出て(ループの処理を中止して),そのループの次の文が実行されます.

  3. 距離

      最後に示す方法は,2 つのオブジェクト間の距離を計算し,その距離によって衝突を判定する方法です.この例(以下に示すのが,そのソースプログラム Test.java の内容)に示すように,2 つのオブジェクトが円や点の場合は問題ありませんが,他の図形の場合は,オブジェクトの端点間の距離の最小値が,オブジェクトやその向きによって異なるため,簡単に衝突判定ができるとは限りません.
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class Test {
    	public static void main (String[] args)
    	{
    		Win win = new Win("距離による衝突判定");
    	}
    }
    
    class Win extends JFrame
    {
    	/******************/
    	/* コンストラクタ */
    	/******************/
    	Win(String name)
    	{
    					// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    		super(name);
    					// Windowの大きさ
    		setSize(640, 470);   // +40, +70
    					// ContentPane の取得と MainPanel の追加
    		Dimension d  = getSize();   // Windowの大きさ
    		d.width     -= 40;
    		d.height    -= 70;
    		MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    		getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    					// ウィンドウを表示
    		setVisible(true);
    					// イベントアダプタ
    		addWindowListener(new WinEnd());
    	}
    
    	/******************************/
    	/* 上,左,下,右の余白の設定 */
    	/******************************/
    	public Insets getInsets()
    	{
    		return new Insets(50, 20, 20, 20);
    	}
    
    	/************/
    	/* 終了処理 */
    	/************/
    	class WinEnd extends WindowAdapter
    	{
    		public void windowClosing(WindowEvent e) {
    			System.exit(0);
    		}
    	}
    }
    
    class MainPanel extends JPanel implements Runnable
    {
    	boolean state = true;
    	double x1, x2, y1, y2, t = 0.0, v = 20.0;
    	Dimension d;
    	Thread th;
    	boolean hit = false;
    
    	MainPanel(Dimension d1)
    	{
    		d = d1;
    		x1 = 0.0;
    		x2 = d.width - 80;
    		y1 = d.height / 2 - 40;
    		y2 = d.height / 2 - 80;
    		setBackground(new Color(238, 255, 238));   // 背景色の設定
    		th = new Thread(this);   // スレッドの生成とスタート
    		th.start();
    	}
    					// 他ページへ移動の際,一時的にスレッドを停止
    	public void stop()
    	{
    		state = false;
    	}
    					// スレッドの実行
    	public void run()
    	{
    		while (state) {
    			try {
    				th.sleep(33);
    			}
    			catch (InterruptedException e) {}
    							// 衝突判定
    			double x = x1 - x2;
    			double y = y1 - y2;
    			if (Math.sqrt(x*x+y*y) <= 80)
    				hit = true;
    							// 移動
    			if (hit)
    				state = false;
    			else {
    				t += 0.1;
    				x1 = v * t;
    				x2 = d.width - 80 - v * t;
    			}
    
    			repaint();
    		}
    	}
    					// 描画
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);   // 親クラスの描画
    							// 塗りつぶした円
    		g.setColor(Color.green);
    		g.fillOval((int)x1, (int)y1, 80, 80);
    							// 塗りつぶした円
    		g.setColor(Color.red);
    		g.fillOval((int)x2, (int)y2, 80, 80);
    	}
    }
    			

  4. もう一つの例
      この例では,四方のランダムな位置からが出現し,中央の三角形に向かって進みます.三角形と衝突後,しばらくすると,次の円が別の位置から出現します.
    001	import java.awt.*;
    002	import java.awt.event.*;
    003	import javax.swing.*;
    004	import java.util.Random;
    005	import java.awt.geom.*;
    006	
    007	public class Test {
    008		public static void main (String[] args)
    009		{
    010			Win win = new Win("円と三角形の衝突判定");
    011		}
    012	}
    013	
    014	class Win extends JFrame
    015	{
    016		/******************/
    017		/* コンストラクタ */
    018		/******************/
    019		Win(String name)
    020		{
    021						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    022			super(name);
    023						// Windowの大きさ
    024			setSize(640, 470);   // +40, +70
    025						// ContentPane の取得と MainPanel の追加
    026			Dimension d  = getSize();   // Windowの大きさ
    027			d.width     -= 40;
    028			d.height    -= 70;
    029			MainPanel pn = new MainPanel(d);   // MainPanel オブジェクトの生成
    030			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    031						// ウィンドウを表示
    032			setVisible(true);
    033						// イベントアダプタ
    034			addWindowListener(new WinEnd());
    035		}
    036	
    037		/******************************/
    038		/* 上,左,下,右の余白の設定 */
    039		/******************************/
    040		public Insets getInsets()
    041		{
    042			return new Insets(50, 20, 20, 20);
    043		}
    044	
    045		/************/
    046		/* 終了処理 */
    047		/************/
    048		class WinEnd extends WindowAdapter
    049		{
    050			public void windowClosing(WindowEvent e) {
    051				System.exit(0);
    052			}
    053		}
    054	}
    055	
    056	class MainPanel extends JPanel implements Runnable
    057	{
    058		boolean state = true;
    059		double x;   // 物体の位置(x)
    060		double y;   // 物体の位置(y)
    061		double vx;   // 物体の速度(x)
    062		double vy;   // 物体の速度(y)
    063		double v = 20;   // 初期速度
    064		double dt = 0.1;   // 時間刻み幅
    065		int r = 20;   // 物体の半径
    066		Polygon tr;   // 三角形
    067		Ellipse2D.Double cir;   // 円
    068		Dimension d;   // パネルの幅と高さ
    069		double px[] = new double [15];   // 衝突判定位置(x)
    070		double py[] = new double [15];   // 衝突判定位置(y)
    071		Random rn;
    072		Thread th;
    073		boolean hit = false;
    074		int count = 0;
    075	
    076		MainPanel(Dimension d1)
    077		{
    078			d = d1;
    079			rn = new Random();
    080						// 初期設定
    081			ini_set();
    082			cir = new Ellipse2D.Double(x-r, y-r, 40, 40);
    083	
    084			double ang = Math.atan2(y-d.height/2, d.width/2-x);
    085			vx = v * Math.cos(ang);
    086			vy = -v * Math.sin(ang);
    087						// 三角形
    088			double cx = d.width / 2.0;
    089			double cy = d.height / 2.0;
    090			double x1 = cx;
    091			double y1 = cy - 50.0 / Math.cos(Math.PI/6);
    092			double x2 = cx - 50.0;
    093			double y2 = cy + 50.0 * Math.tan(Math.PI/6);
    094			double x3 = cx + 50.0;
    095			double y3 = cy + 50.0 * Math.tan(Math.PI/6);
    096			int xx[] = {(int)cx, (int)cx-50, (int)cx+50};
    097			int yy[] = {(int)y1, (int)y2, (int)y3};
    098			tr = new Polygon(xx, yy, 3);
    099						// 衝突判定位置
    100			int k = 0;
    101			px[k] = x1;
    102			py[k] = y1;
    103			k++;
    104			double sx = (x2 - x1) / 5;
    105			double sy = (y2 - y1) / 5;
    106			for (int i1 = 1; i1 < 5; i1++) {
    107				px[k] = x1 + i1 * sx;
    108				py[k] = y1 + i1 * sy;
    109				k++;
    110			}
    111			px[k] = x2;
    112			py[k] = y2;
    113			k++;
    114			sx = (x3 - x2) / 5;
    115			sy = (y3 - y2) / 5;
    116			for (int i1 = 1; i1 < 5; i1++) {
    117				px[k] = x2 + i1 * sx;
    118				py[k] = y2 + i1 * sy;
    119				k++;
    120			}
    121			px[k] = x3;
    122			py[k] = y3;
    123			k++;
    124			sx = (x1 - x3) / 5;
    125			sy = (y1 - y3) / 5;
    126			for (int i1 = 1; i1 < 5; i1++) {
    127				px[k] = x3 + i1 * sx;
    128				py[k] = y3 + i1 * sy;
    129				k++;
    130			}
    131	
    132			setBackground(new Color(238, 255, 238));   // 背景色の設定
    133			th = new Thread(this);   // スレッドの生成とスタート
    134			th.start();
    135		}
    136						// 初期設定
    137		void ini_set()
    138		{
    139			double p = rn.nextDouble() * 2 * (d.width + d.height);
    140			if (p < d.width) {   // 上
    141				x = r + rn.nextDouble() * (d.width - 2 * r);
    142				y = r;
    143			}
    144			else if (p < d.width + d.height) {   // 右
    145				x = d.width - r;
    146				y = r + rn.nextDouble() * (d.height - 2 * r);
    147			}
    148			else if (p < 2 * d.width + d.height) {   // 下
    149				x = r + rn.nextDouble() * (d.width - 2 * r);
    150				y = d.height - r;
    151			}
    152			else {   // 左
    153				x = r;
    154				y = r + rn.nextDouble() * (d.height - 2 * r);
    155			}
    156		}
    157						// 他ページへ移動の際,一時的にスレッドを停止
    158		public void stop()
    159		{
    160			state = false;
    161		}
    162						// スレッドの実行
    163		public void run()
    164		{
    165			while (state) {
    166	
    167				repaint();
    168	
    169				try {
    170					th.sleep(33);
    171				}
    172				catch (InterruptedException e) {}
    173	
    174				if (count == 0) {
    175					for (int i1 = 0; i1 < 15; i1++) {
    176						hit = cir.contains(px[i1], py[i1]);
    177						if (hit)
    178							break;
    179					}
    180	
    181					if (hit)
    182						count = 1;
    183					else {
    184						x += (vx * dt);
    185						y += (vy * dt);
    186					}
    187				}
    188				else {
    189					count++;
    190					if (count == 30) {
    191						count = 0;
    192						ini_set();
    193						double ang = Math.atan2(y-d.height/2, d.width/2-x);
    194						vx = v * Math.cos(ang);
    195						vy = -v * Math.sin(ang);
    196					}
    197				}
    198			}
    199		}
    200						// 描画
    201		public void paintComponent(Graphics g)
    202		{
    203			super.paintComponent(g);   // 親クラスの描画
    204								// Graphics2Dの取得
    205			Graphics2D g2 = (Graphics2D)g;
    206								// 塗りつぶした円
    207			g2.setColor(Color.green);
    208			cir = new Ellipse2D.Double(x-r, y-r, 40, 40);
    209			g2.fill(cir);
    210								// 塗りつぶした三角形
    211			g2.setColor(Color.red);
    212			g2.fill(tr);
    213		}
    214	}
    			
    088 行目~ 098 行目

      三角形を定義しています.

    100 行目~ 130 行目

      三角形上の衝突判定を行う点の座標を計算し,配列 px 及び py に設定しています.

    137 行目~ 156 行目

      初期設定を行うメソッドであり,出現位置をランダムに設定しています.

    174 行目

      この if 文によって,衝突していない場合は( count が 0 の場合は),175 行目~ 186 行目を実行します.175 行目~ 179 行目の衝突判定によって,衝突が判明した場合は変数 count を 1 に設定し,さもなければ,円の移動を続行します( 184,185 行目).

    188 行目

      count が 0 でない場合は,189 行目~ 196 行目を実行します.count を 1 だけ増加させ,その値が 30 になった場合は,count を 0 に設定し,初期設定を行うメソッド ini_set によって,新しい円の出現位置を決めます.193 行目~ 195 行目において,円の進行方向を決めています.atan2 は,Math クラスのメソッドであり,逆正接の計算,つまり,atan2(y, x) は,tan(a) = y/x となるような角度 a をラジアン単位で返します.従って,ここの計算により,すべての円は,画面の中心に向かって移動することになります.count が 30 になるまでは何も行いませんので,ほぼ 1 秒間( 33×30,170 行目),衝突した状態が表示されます.

情報学部 菅沼ホーム Java 目次 基礎技術目次 索引