// Copyright (C) 2000 by Toyohisa Nakada. All Rights Reserved. import java.awt.*; import java.awt.event.*; import java.applet.*; import java.net.*; import java.awt.image.*; import javax.swing.*; import java.util.*; /** * ボイドアプリケーションの主要パラメータを管理するクラス。
* 他のクラスから直接メンバ変数を参照する。但し、メンバ変数の書き込みは * 、他のクラスからは一切行わない。 * @author 中田豊久 */ class CParameters { /** 親クラスになるAppletクラスポインタ*/ Applet m_ap = null; /** nodeの数
初期値 20 */ int m_nNodeNum = 20; /** nodeの新しい位置を計算後に休憩する時間(ms)。全てのnodeの位置を * 計算してから、この時間だけsleepし、また同じ計算を繰り返す。 初 * 期値 15 */ int m_nSleep = 15; /** nodeの幅を指定する。但し、nodeに画像が割り当てられている時は、 * この値は使用しない。
初期値 4 */ int m_nWidth = 4; /** nodeの高さを指定する。但し、nodeに画像が割り当てられている時は * この値は使用しない。
初期値 4 */ int m_nHeight = 4; /** nodeのスピードの設定可能最大値。システム動作中に値は変更しない * 。
初期値 3.0 */ double m_dSpeedMax = 3.0; /** nodeのスピードの設定可能最小値。システム動作中に値は変更しない * 。
初期値 0.0 */ double m_dSpeedMin = 0.0; /** nodeのスピード。
初期値 1.5 */ double m_dSpeed = 1.5; /** nodeのランダムに変化する速度に対する、動きの度合いを数値で指定 * する。この値は、nodeが独自に速度を変化させる動作に適用され、他の * nodeに影響されて変化する速度の動作には影響しない。数値は-0.5以上 * 0.5未満のランダム値が生成されるので、その値に掛ける値がこの変数 * である。
初期値 0.2 */ double m_dEffectSpeed = 0.2; /** 他のnodeに影響されて速度を変化させる割合を指定する。他のnodeと * 自分のnodeの速度差にこの変数を掛けた値を自分の速度に加える。 初 * 期値 0.1 */ double m_dEffectRelateSpeed = 0.1; /** 一度の計算で変更可能な速度値の大きさ。これ以上の値に計算値がな * った場合、変化量はこの変数の値に抑えられる。
初期値 (m_dSpeed * Max-m_dSpeedMin)/20 */ double m_dChangeSpeedMax = (m_dSpeedMax-m_dSpeedMin)/20; /** 通常時の方向変更を発生する頻度を指定する。通常とは、異常時でな * い時で、異常時とは壁にぶつかった時である。0以上1以下の値を設定 * する。値が大きいほど方向変更が発生しやすく1を指定すると、毎回方 * 向変更が生じる。0の場合、方向変更は発生しない。
初期値 0.3 */ double m_dNormalOccor = 0.3; /** 異常時の方向変更を発生する頻度を指定する。詳しくは{@link #m_dNormalOccor} * を参照。
初期値 1.0 */ double m_dMoreOccor = 1.0; /** 通常時の方向変更の角度の割合を指定する。大きな値を指定すると、 * 変更される角度は小さくなる。通常は0.5から8程度の間で指定する。通 * 常とは、異常時でない時で、異常時とは壁にぶつかった時である。
* 初期値 6 */ double m_dNormalDiv = 6; /** 異常時のの方向変更の角度の割合を指定する。詳しくは{@link #m_dNormalDiv} * を参照。
初期値 0.8 */ double m_dMoreDiv = 0.8; /** 他のnodeから影響を受けていない時の色を指定する。nodeに画像が割 * り当てられている時は無視される。
初期値 Color.black */ Color m_NormalColor = Color.black; /** 他のnodeから影響を受けている時の色を指定する。nodeに画像が割り * 当てられている時は無視される。
初期値 Color.green */ Color m_NearColor = Color.green; /** 影響を受けるnodeの半径を指定する。この半径で描かれる円の中にあ * るnodeから影響を受ける。
初期値 50 */ double m_dCircle = 50; /** 変化する角度の割合を指定する。
初期値 0.1 */ double m_dEffectRelateRad = 0.1; /** Hatenodeとの角度差分において実際に変化する角度を割合で指定する * 。
初期値 0.1 */ double m_dEffectRelateHateRad = 0.1; /** 一度の計算で変更可能な角度の最大値を指定する。これ以上の値に計 * 算値がなった場合、変化量はこの変数の値に抑えられる。
初期値 M * ath.PI/4 */ double m_dChangeRadMax = Math.PI/4; /** 背景の画像を保持する変数。
初期値 null */ Image m_background=null; /** 背景画像の getDocumentBase() からの相対パス。
初期値 images/background.gif */ String m_backgroundPath="images/background.gif"; /** nodeの画像を報じする変数。
初期値 null */ Image m_imageCNodeMove[]=null; /** nodeの画像が何枚のイメージで構成されているかを指定する変数。
初期値 0 */ int m_nImageCNodeMoveCount=0; /** コントロールパネルを表示しない場合、true。
初期値 false */ boolean m_bNoviewControlPanel=false; /** カウンタを表示しない場合、ture。
初期値 false */ boolean m_bNoviewTime=false; /** ノード数を表示しない場合、true。
初期値 false */ boolean m_bNoViewNodeNum=false; /** 寿命の最大数({link CNode#IsLifeOK}がコールできる回数)
初期値 * 2000 */ int m_nSpanOfLifeMax=2000; /** 寿命の最小数({link CNode#IsLifeOK}がコールできる回数)
初期値 * 100 */ int m_nSpanOfLifeMin=100; /** * アプレットの起動時にコールされ、HTMLによって指定された初期値をロ * ードする。HTMLにより指定可能なパラメータは{@link ComplexApplet#getParameterInfo} * を参照。 * @param ap アプレットクラスを指定。Applet.getParameterの使用と、m *_ap変数への保存のため。 */ void setDefault(Applet ap){ m_ap = ap; String backgroundString = m_backgroundPath; /* JAR ファイルにしてアプレットで動かすとエラーが発生して動かない String cl = ap.getParameter("sleep"); if(cl != null){ try{ m_nSleep = Integer.parseInt(cl); m_txSleep.setText(cl); }catch(NumberFormatException e){ } } cl = ap.getParameter("nodenum"); if(cl != null){ try{ m_nNodeNum = Integer.parseInt(cl); m_txNodeNum.setText(cl); }catch(NumberFormatException e){ } } cl = ap.getParameter("nodesize"); if(cl != null){ try{ m_nWidth = m_nHeight = Integer.parseInt(cl); m_txNodeSize.setText(cl); }catch(NumberFormatException e){ } } cl = ap.getParameter("background"); if(cl != null) backgroundString = cl; String nodeImage = "CNodeMove-image"; m_nImageCNodeMoveCount = 12; for(int cnt=0;cnt
* 新しい{@link CNode}の派生クラスのソースを書いた場合、この関数 *の中に m_NodeTypeList.Add(new String((new <<NEW CLASS<<(0,0,this *)).getClass().getName()));を追加する。<<NEW CLASS<<はクラス名。
* @param panel 配置するパネル * @param x 描画するパネルの幅 * @param y 描画するパネルの高さ */ CArea(JPanel panel,int x,int y){ m_parentPanel = panel; m_NodeTypeList = new Vector(); ///////////////////////////////////////////////// // 新しいNodeを作成した場合、以下に1行追加する // ///////////////////////////////////////////////// m_NodeTypeList.add(new String((new CNodeMove(0,0,this)).getClass().getName())); m_NodeTypeList.add(new String((new CNodeInfluence(0,0,this)).getClass().getName())); m_NodeTypeList.add(new String((new CNodeHate(0,0,this)).getClass().getName())); m_NodeTypeList.add(new String((new CNodeHateNomove(0,0,this)).getClass().getName())); m_NodeTypeList.add(new String((new CNodeInfluenceNomove(0,0,this)).getClass().getName())); m_NodeList = new Vector(); // Nodeの作成は以下で行う for(int cnt=0;cnt * このクラスのインスタンスは生成しない。
* @author 中田豊久 */ class CNode { /** * x軸の位置

*
	 * 座標軸は以下の様。
	 *
	 *       |
	 *   ----+----> x plus
	 *       |
	 *       ↓y plus
	 * 
*/ double m_dX; /** y軸の位置
座標軸は{@link #m_dX}参照。 */ double m_dY; /** 移動可能な最大のx軸の値 */ int m_nMaxX; /** 移動可能な最大のy軸の値 */ int m_nMaxY; /** 色。但し、nodeに画像が割り当てられている時は無視される。 */ Color m_color; /** CArea ポインタ */ CArea m_Area; /** 寿命を表現する変数。この変数の値だけ、寿命確認関数 * {link #IsLifeOK()}がコールされると、このノードは消滅する。*/ int m_nSpanOfLife; /** コンストラクタ
* @param x 使用しない * @param y 使用しない * @param area nodeを配置する{@link CArea}クラス。 */ CNode(int x,int y,CArea area){ m_Area = area; m_color = Color.black; // 寿命は、CParameters::m_nSpanOfLifeMaxとCParameters::m_nSpanO // fLifeMinの間でランダムに設定される。 m_nSpanOfLife = (int)((ComplexPanel.m_Parameters.m_nSpanOfLifeMax - ComplexPanel.m_Parameters.m_nSpanOfLifeMin) * Math.random()) + ComplexPanel.m_Parameters.m_nSpanOfLifeMin; } /** x軸の値を取得する。 */ double getX(){return m_dX;} /** x軸の値をセットする。 * @param x x軸の値 */ void setX(double x){m_dX = x;} /** y軸の値を取得する。 */ double getY(){return m_dY;} /** y軸の値をセットする。 * @param y y軸の値 */ void setY(double y){m_dY = y;} /** 幅を取得する。 */ int getWidth(){return ComplexPanel.m_Parameters.m_nWidth;} /** 高さを取得する。 */ int getHeight(){return ComplexPanel.m_Parameters.m_nHeight;} /** スピードを取得する。 */ double getSpeed(){return 0;} /** * node位置を再計算する時にコールされる。 * {@link CRelation#recalc(CNode obj,CNode comp)}との違いは、この関 * 数は他のnodeとは関係なく動作するコードを記述して、CRelation.reca * lcは2つのnodeがどのように影響しあうかを記述する。*/ void recalc(){} /** node位置の再計算がすべて終了したことを通知する関数 */ void endRecalc(){} /** 描画関数 * @param g Graphics*/ public void paint(Graphics g){ g.setColor(m_color); g.fillRect((int)m_dX,(int)m_dY,getWidth(),getHeight()); return; } /** 寿命確認関数 この関数が、{link #m_nSpanOfLife}回数コールされると * ノードは消滅する */ boolean IsLifeOK(){ /* if(m_nSpanOfLife == 0) return false; m_nSpanOfLife--; return true; */ return true; } } /** * node間の関係を実装するためのテンプレートインターフェース。

*
 * 基本的なRelation派生Classの作り方
 *  クラス名
 *  XXX_YYY   XXXクラスがYYYクラスに影響を受ける
 *            注意 YYY_XXX とは別物
 *            (片方が影響されるだけの物もある)
 * 
* @author 中田豊久 */ interface CRelation { /** nodeの再計算の方法を定義する。{@link CNode#recalc()}を参照。 * @param obj 再計算する対象のnode * @param comp nodeに影響を与えるnode */ void recalc(CNode obj,CNode comp); /** nodeが関係するか、しないかを定義する。この関数で、trueを返すと * 引数の第一引数のobj nodeは、第二引数のcomp nodeに影響を受けると * 解釈される。falseの場合は影響を受けないと解釈される。 * @param obj 影響を受けるか、受けないかの対象となるnode * @param comp 影響を与えるか、与えないかの対象となるnode */ boolean isRelation(CNode obj,CNode comp); } /** * {@link CRelation}実装時に使用可能なテンプレートコードをまとめたクラス。 * CRelation派生クラスでこのクラスの静的関数をコールしても、独自に関数を * 作成しても構わない。
* このクラスは、ボイド間が仲良くなる(近づきあう)関係を表現している。 * @author 中田豊久 */ class CRelationSampleFriend { static boolean isRelation(CNode obj,CNode comp,double dCircle){ if(dCircle >= Math.sqrt(Math.pow(obj.getX()-comp.getX(),2)+Math.pow(obj.getY()-comp.getY(),2))){ return true; } return false; } static void recalc(CNode obj,CNode comp){ if(obj instanceof CNodeMove){ CNodeMove node = (CNodeMove)obj; if(comp instanceof CNodeMove){ CNodeMove mate = (CNodeMove)comp; // 角度の計算 double divRad = mate.getRad() - node.getRad(); // divRad の範囲は -Math.PI <= divRad < Math.PI if(divRad < -Math.PI) divRad += 2*Math.PI; else if(divRad >= Math.PI) divRad -= 2*Math.PI; double divPos = Math.sqrt( Math.pow(mate.getX()-node.getX(),2)+Math.pow(mate.getY()-node.getY(),2)); if(ComplexPanel.m_Parameters.m_dCircle == 0){ System.out.println("Error dCircle"); }else{ node.addRadNext(divRad* (((2*divPos)/ComplexPanel.m_Parameters.m_dCircle)-1) * ComplexPanel.m_Parameters.m_dEffectRelateRad); } /* ある程度の良い位置関係に、関連するnodeがあるときに、色を * 変えるテスト。 double range = ComplexPanel.m_Parameters.m_dCircle/3; if(divPos >= ((ComplexPanel.m_Parameters.m_dCircle-range)/2) && divPos <= (((ComplexPanel.m_Parameters.m_dCircle-range)/2)+range)){ node.NearColor(); } /**/ } // Speedの計算 double divSpeed = comp.getSpeed() - node.getSpeed(); node.addSpeedNext(divSpeed*ComplexPanel.m_Parameters.m_dEffectRelateSpeed); /* 他のnodeに影響を受けている時に色を変更する node.NearColor(); /**/ } } } /** * {@link CRelation}実装時に使用可能なテンプレートコードをまとめたクラス。 * CRelation派生クラスでこのクラスの静的関数をコールしても、独自に関数を * 作成しても構わない。
* このクラスは、嫌いあう(遠ざけあう)関係を表現している。 * @author 中田豊久 */ class CRelationSampleHate { static void recalc(CNode obj,CNode comp){ if(obj instanceof CNodeMove){ CNodeMove node = (CNodeMove)obj; CVector vec = new CVector(comp.getX()-node.getX(),comp.getY()-node.getY()); double mateRad = vec.getRad()+Math.PI; if(mateRad < 0) mateRad += 2*Math.PI; else if(mateRad >= 2*Math.PI) mateRad -= 2*Math.PI; double divRad = mateRad - node.getRad(); // divRad の範囲は -Math.PI <= divRad < Math.PI if(divRad < -Math.PI) divRad += 2*Math.PI; else if(divRad >= Math.PI) divRad -= 2*Math.PI; node.addRadNext(divRad*ComplexPanel.m_Parameters.m_dEffectRelateHateRad); /* 他のnodeに影響を受けている時に色を変更する node.NearColor(); /**/ } } } /** * 他のNodeに全く影響を受けないNode。自分勝手に動き回る。 * @author 中田豊久 */ class CNodeMove extends CNode{ /** *
	 * 進む方向を角度(rad)で表現する
	 *         3/2 PI rad
	 *            |
	 *  PI rad  --+--> 0 rad
	 *            |
	 *         1/2 PI rad
	 */
	double m_dRad;
	/** 計算結果を保持する。*/
	double m_dRadNext;
	/**
	 * スピードを表現する。値1は、1 pixel / 一回の再計算
	 */
	double m_dSpeed;
	/** 計算結果を保持する。*/
	double m_dSpeedNext;
	/** 計算結果を保持する。*/
	double m_dXNext;
	/** 計算結果を保持する。*/
	double m_dYNext;
	/** 方向性変更、スピード変更のイベント発生頻度を指定する。詳細は
	 * {@link CParameters#m_dNormalOccor}を参照。 */
	double m_dOccor;
	/** 方向変更の割合を指定する。詳細は{@link CParameters#m_dNormalOccor}
	 * を参照。*/
	double m_dDiv;

	/** x軸の値をセット */
	void setX(double x){
		m_dXNext = m_dX = x;
	}
	/** y軸の値をセット */
	void setY(double y){
		m_dYNext = m_dY = y;
	}

	/** コンストラクタ */
	CNodeMove(int x,int y,CArea area){
		super(x,y,area);
		m_dRadNext = m_dRad = Math.random()*2*Math.PI;
		m_dXNext = m_dX = x * Math.random();
		m_dYNext = m_dY = y * Math.random();
		m_dSpeedNext = m_dSpeed = ComplexPanel.m_Parameters.m_dSpeed;
		m_nMaxX = x;
		m_nMaxY = y;
		DefaultOccor();
		DefaultColor();
	}
	/** 通常時の方向変更、速度変更の頻度と割合をセットする。 */
	void DefaultOccor(){
		m_dOccor = ComplexPanel.m_Parameters.m_dNormalOccor;
		m_dDiv = ComplexPanel.m_Parameters.m_dNormalDiv;
	}
	/** 異常時の方向変更、速度変更の頻度と割合をセットする。 */
	void MoreOccor(){
		m_dOccor = ComplexPanel.m_Parameters.m_dMoreOccor;
		m_dDiv = ComplexPanel.m_Parameters.m_dMoreDiv;
	}
	/** 通常使用する色を指定する。 */
	void DefaultColor(){
		m_color = Color.magenta;
	}
	/** 他のnodeと関係を持っている時の色を指定する。*/
	void NearColor(){
		m_color = ComplexPanel.m_Parameters.m_NearColor;
	}
	/** 幅を取得する。 */
	int getWidth(){
		if(getNodeImage()==null)
			return ComplexPanel.m_Parameters.m_nWidth;
		else{
			int x;
			while(-1==(x=getNodeImage()[0].getWidth(null)));
			return x;
		}
	}
	/** 高さを取得する。 */
	int getHeight(){
		if(getNodeImage()==null)
			return ComplexPanel.m_Parameters.m_nHeight;
		else{
			int x;
			while(-1==(x=getNodeImage()[0].getHeight(null)));
			return x;
		}
	}
	/** 角度を取得する。 */
	double getRad(){return m_dRad;}
	void addRadNext(double rad){
		m_dRadNext += rad;
		regularRadNext();
	}
	/** 角度を0 <= x < 2*Math.PIに変換する。 */
	void regularRadNext(){
		if(m_dRadNext >= (2*Math.PI))
			m_dRadNext -= (2*Math.PI);
		else if(m_dRadNext < 0)
			m_dRadNext += (2*Math.PI);
		return;
	}
	/** スピードに引数の値を追加する。 */
	void addSpeedNext(double speed){
		m_dSpeedNext += speed;
	}
	/** スピードをパラメータで示された最大値{@link CParameters#m_dSpeedMax}
	 * 、最小値{@link CParameters#m_dSpeedMin}の間に変換する。 */
	void regularSpeedNext(){
		if(m_dSpeedNext > ComplexPanel.m_Parameters.m_dSpeedMax)
			m_dSpeedNext = ComplexPanel.m_Parameters.m_dSpeedMax;
		else if(m_dSpeedNext < ComplexPanel.m_Parameters.m_dSpeedMin)
			m_dSpeedNext = ComplexPanel.m_Parameters.m_dSpeedMin;
	}
	/** スピードを取得する。 */
	double getSpeed(){return m_dSpeed;}
	/** 自分の位置を再計算する。 */
	void recalc(){
		if(Math.random() <= m_dOccor){
			addRadNext((Math.random()-0.5)/m_dDiv);
			addSpeedNext((Math.random()-0.5)*ComplexPanel.m_Parameters.m_dEffectSpeed);
		}
		DefaultOccor();
		return;
	}
	/** 再計算終了時に、スピード、角度を調整し、新しいx軸、y軸の値をセ
	 * ットする。*/
	void endRecalc(){
		// m_dRadNextの最大値を設定する
		double var = m_dRadNext-m_dRad;
		if(var < -ComplexPanel.m_Parameters.m_dChangeRadMax){
			m_dRadNext = m_dRad-ComplexPanel.m_Parameters.m_dChangeRadMax;
			regularRadNext();
		}else if(var > ComplexPanel.m_Parameters.m_dChangeRadMax){
			m_dRadNext = m_dRad+ComplexPanel.m_Parameters.m_dChangeRadMax;
			regularRadNext();
		}
		// Speedの値を調整する
		double varSpeed = m_dSpeedNext-m_dSpeed;
		if(varSpeed < -ComplexPanel.m_Parameters.m_dChangeSpeedMax)
			m_dSpeedNext = m_dSpeed-ComplexPanel.m_Parameters.m_dChangeSpeedMax;
		else if(varSpeed > ComplexPanel.m_Parameters.m_dChangeSpeedMax)
			m_dSpeedNext = m_dSpeed+ComplexPanel.m_Parameters.m_dChangeSpeedMax;
		regularSpeedNext();

		/* アプレットのサイズの枠の中でnodeが動く場合のコード
		 * アプレットの端にnodeがぶつかるようになる。
		m_dXNext += getSpeed() * Math.cos(m_dRadNext);
		if((int)m_dXNext+getWidth() > m_nMaxX){
			m_dXNext = m_nMaxX-getWidth();
			MoreOccor();
		}else if(m_dXNext < 0.0){
			m_dXNext = 0.0;
			MoreOccor();
		}
		m_dYNext += getSpeed() * Math.sin(m_dRadNext);
		if((int)m_dYNext+getHeight() > m_nMaxY){
			m_dYNext = m_nMaxY-getHeight();
			MoreOccor();
		}else if(m_dYNext < 0.0){
			m_dYNext = 0.0;
			MoreOccor();
		}
		/**/
		/* 枠を無視した仮想無限の空間でnodeを動作させる時のコード。左右
		 * 、上下がつながっていて、例えば右から出たnodeは即座に左から画
		 * 面に入ってくる。 
		 */
		m_dXNext += getSpeed()*Math.cos(m_dRadNext);
		if(m_dXNext<0)
			m_dXNext += m_nMaxX-getWidth();
		else
			m_dXNext %= m_nMaxX-getWidth();

		m_dYNext += getSpeed()*Math.sin(m_dRadNext);
		if(m_dYNext<0)
			m_dYNext += m_nMaxY-getHeight();
		else
			m_dYNext %= m_nMaxY-getHeight();
		/**/
		return;
	}
	/**
	 * 描画関数
	 */
	public void paint(Graphics g){
		m_dRad = m_dRadNext;
		m_dX = m_dXNext;
		m_dY = m_dYNext;
		m_dSpeed = m_dSpeedNext;

		Image nodeImage[]=null;
		if(null == (nodeImage=getNodeImage())){
			g.setColor(m_color);
			g.fillRect((int)m_dX,(int)m_dY,
				getWidth(),getHeight());

			/* 現在のスピードを表示する
			g.drawString(""+getSpeed(),(int)m_dX,(int)m_dY);
			/**/

			DefaultColor();
		}else{
			int n = (int)(m_dRad*getNodeImageCount()/(2*Math.PI));
			g.drawImage(ComplexPanel.m_Parameters.m_imageCNodeMove[n],
				(int)m_dX,(int)m_dY,null);
		}
	}
	/** nodeのイメージ画像を取得する。{@link CParameters#m_imageCNodeMove}
	 * 参照。*/
	Image[] getNodeImage(){
		return ComplexPanel.m_Parameters.m_imageCNodeMove;
	}
	/** nodeのイメージ画像数を取得する。{@link CParameters#m_nImageCNodeMoveCount}
	 * 参照 */
	int getNodeImageCount(){
		return ComplexPanel.m_Parameters.m_nImageCNodeMoveCount;
	}
}

/**
 * {@link CNodeMove}が{@link CNodeHate}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeMove_CNodeHate implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle*2);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
		return;
	}
}

/**
 * {@link CNodeMove}が{@link CNodeHateNomove}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeMove_CNodeHateNomove implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle*2);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleHate.recalc(obj,comp);
		return;
	}
}

/**
 * 他のNodeに影響を受けるNode
 * @author 中田豊久
 */
class CNodeInfluence extends CNodeMove {
	CNodeInfluence(int x,int y,CArea area){
		super(x,y,area);
	}
	void DefaultColor(){
		m_color = ComplexPanel.m_Parameters.m_NormalColor;
	}
	/*
	 * 描画関数 (nodeの周りに影響を受ける範囲の円を描画するためにだけに
	 * オーバライドした関数。
	public void paint(Graphics g){
		super.paint(g);

		// 影響を受ける円のを描画する 
		g.setColor(Color.black);
		g.drawOval(
			(int)(m_dX-ComplexPanel.m_Parameters.m_dCircle),
			(int)(m_dY-ComplexPanel.m_Parameters.m_dCircle),
			(int)(ComplexPanel.m_Parameters.m_dCircle*2),
			(int)(ComplexPanel.m_Parameters.m_dCircle*2));
	}
	*/
}

/**
 * {@link CNodeInfluence}が{@link CNodeMove}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeInfluence_CNodeMove implements CRelation {
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
	}
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
}

/**
 * {@link CNodeInfluence}が{@link CNodeInfluence}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeInfluence_CNodeInfluence implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
		return;
	}
}

/**
 * {@link CNodeInfluence}が{@link CNodeInfluenceNomove}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeInfluence_CNodeInfluenceNomove implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
		return;
	}
}

/**
 * {@link CNodeInfluence}が{@link CNodeHate}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeInfluence_CNodeHate implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle*2);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleHate.recalc(obj,comp);
		return;
	}
}

/**
 * {@link CNodeInfluence}が{@link CNodeHateNomove}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeInfluence_CNodeHateNomove implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle*2);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleHate.recalc(obj,comp);
		return;
	}
}

/**
 * 周りから嫌われるNode
 * @author 中田豊久
 */
class CNodeHate extends CNodeMove {
	CNodeHate(int x,int y,CArea area){
		super(x,y,area);
	}
	void DefaultColor(){
		m_color = Color.red;
	}
	void NearColor(){
		super.NearColor();
		m_color = Color.pink;
	}
	/*
	int getWidth(){return (int)((double)super.getWidth()*1.5);}
	int getHeight(){return (int)((double)super.getHeight()*1.5);}
	*/
	Image[] getNodeImage(){return null;}
}

/**
 * {@link CNodeHate}が{@link CNodeInfluence}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeHate_CNodeInfluence implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleHate.recalc(obj,comp);
		return;
	}
}
/**
 * {@link CNodeHate}が{@link CNodeInfluenceNomove}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeHate_CNodeInfluenceNomove implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleHate.recalc(obj,comp);
		return;
	}
}
/**
 * {@link CNodeHate}が{@link CNodeHate}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeHate_CNodeHate implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
		return;
	}
}
/**
 * {@link CNodeHate}が{@link CNodeHate}に影響を受けるコード
 * @author 中田豊久
 */
class CNodeHate_CNodeHateNomove implements CRelation {
	public boolean isRelation(CNode obj,CNode comp){
		return CRelationSampleFriend.isRelation(
			obj,comp,ComplexPanel.m_Parameters.m_dCircle);
	}
	public void recalc(CNode obj,CNode comp){
		CRelationSampleFriend.recalc(obj,comp);
		return;
	}
}

/**
 * 動かない嫌われるnode
 * @author 中田豊久
 */
class CNodeHateNomove extends CNode {
	CNodeHateNomove(int x,int y,CArea area){
		super(x,y,area);
		m_color = Color.red;
	}
	int getWidth(){return (int)((double)super.getWidth()*1.5);}
	int getHeight(){return (int)((double)super.getHeight()*1.5);}
}

/**
 * 動かない影響を受けるnode
 * @author 中田豊久
 */
class CNodeInfluenceNomove extends CNode {
	CNodeInfluenceNomove(int x,int y,CArea area){
		super(x,y,area);
		m_color = Color.black;
	}
	int getWidth(){return 10;}
	int getHeight(){return 10;}
}

/**
 * ベクトルを扱うライブラリクラス
* ボイドアプレットに依存していないので再利用が可能。
* java.util.Vectorとは全く無関係。 * @author 中田豊久 */ class CVector { /** メンバ変数 */ double m_x; /** メンバ変数 */ double m_y; /** コンストラクタ * @param x x軸値 * @param y y軸値 */ CVector(double x,double y){ m_x = x; m_y = y; } /** 現在のx,yの値を使用して、角度(radians)を返す * @return 角度(radians) */ double getRad(){ // 返す角度の範囲は 0 <= rad < 2*Math.PI if(m_y == 0){ if(m_x >= 0) return 0; else return Math.PI; }else if(m_x == 0){ if(m_y >= 0) return Math.PI/2; else return 3*Math.PI/2; } double rad = Math.acos(m_x/Math.sqrt(Math.pow(m_x,2)+Math.pow(m_y,2))); if(m_y < 0) return -rad; return rad; } /** 引数として与えられたベクトルに対して自分のベクトルをプラス方向 * に回転すれば角度が近づくか、マイナス方向に回転すれば近づくかを返 * す。
* 例えば、引数ベクトルが(1,1) 自分のベクトルが(1,-1)の場合、自分の * ベクトルをマイナス方向に回転させると、引数ベクトルに近づくのでこ * の関数はマイナス方向を示す -1 を返す。 * @param vec 対象となるベクトル * @return 1の場合はプラス方向、2の場合はマイナス方向。 */ int towordPlusMinus(CVector vec){ if((m_x == 0 && m_y == 0) || (vec.m_x == 0 && vec.m_y == 0)){ return 0; } int nDiff; switch(nDiff = diffWorld(vec)){ case 0: case 2: double x = ((double)vec.m_y/vec.m_x)-((double)m_y/m_x); if(x == 0) return 0; else{ if(nDiff==0) return x>0?1:-1; else return x>0?-1:1; } case -1: return -1; case 1: return 1; } return 0; // bug } /** {@link #getWorld()}により求められる象現の差分を求める。同じ象現 * の場合、差分は0。隣の象現に互いがある場合、1。対角線上に互いの * 象現が存在する場合、2となる。 * @param vec 比較対象のベクトル * @return 差分値(0-2) */ int diffWorld(CVector vec){ int w = getWorld(); int w2 = vec.getWorld(); if(w == w2) return 0; else if(Math.abs(w-w2)==2) return 2; else if(Math.max(w,w2)-Math.min(w,w2)==1) return 1; else return -1; } /** * m_x,m_yを以下の4つの象現に分ける
*
	 * 1.  ○      2.   ●    3.  |      4.  |
	 *     | |        | |         |          |
	 *     +-●      ○-+-     ●-+-        -+-○
	 *     |            |       | |          | |
	 *                            ○         ●
	 * 
* @return 象現の番号(1-4) */ int getWorld(){ if(m_x > 0 && m_y >= 0){ return 1; }else if(m_x <= 0 && m_y > 0){ return 2; }else if(m_x < 0 && m_y <= 0){ return 3; }else if(m_x >= 0 && m_y < 0){ return 4; } return 0;// bug } }