//
/* ----------------------------------------------------------------------------------------------
    tracking.java	CD のトラッキング制御						ver. 2.00 (JDK 1.02)
    															ueyama@infonet.co.jp  2001.05.03
    															update: 2007.08.22
---------------------------------------------------------------------------------------------- */
import java.applet.Applet;
import java.awt.*;
import java.util.*;


public class tracking extends Applet implements Runnable
{
	int			Px=33, Lx=94;											// ピットとレーザービームの X 座標値
	int			Py[][]=new int[3][4];									// ピットの Y 座標値
	int			Pl[][]=new int[3][4];									// ピットの長さ
	int			Ps[]={0,40,56,72,88,104};								// ピットの長さ(ピクセル)
	int			Gl[]={40,39,38,37,36,35,33,31,29,27,25,23};				// グラフの長さ
	int			Wait=32;												// 表示変更待機時間 (msec)
	int			N=0,D=1;
	int			Mf=-1;
	boolean		F0=false, F1=false;
	boolean		Run=false;
	Image		Img;
	Image		Buf;
	int			Bgc;
	Random		Rnd=new Random();
	Graphics	bf;
	Thread		th;
	
	public void init()
	{
		int i,j,k,l;
		String	bg=getParameter("bgcolor");
		Bgc=Integer.valueOf(bg,16).intValue();							// html 背景色
		setBackground(new Color(221,221,221));							// CD 鏡面色
		Buf=createImage(250,380);
		MediaTracker mt=new MediaTracker(this);
		Img=getImage(getCodeBase(), getParameter("figure"));
		mt.addImage(Img, 0);
		try
		{
			mt.waitForID(0);
		}
		catch(InterruptedException e){};
		for(i=0;i<3;i++)												// ピットの位置と長さの設定
		{
			for(j=0;j<4;j++) Pl[i][j]=Math.abs(Rnd.nextInt())%4+1;
			Py[i][0]=Rnd.nextInt()%40;
			for(j=1;j<4;j++) Py[i][j]=Py[i][j-1]+Ps[Pl[i][j-1]]+Ps[Math.abs(Rnd.nextInt())%4+1];
		}
	}
	
	public void start()
	{
		th=new Thread(this);
		th.start();
	}
	
	public void stop()
	{
		if(th!=null)
		{
			th.stop();
			th=null;
		}
	}
	
	public void update(Graphics g)
	{
		paint(g);
	}
	
	public boolean inside(int x, int a, int b)
	{
		return (x<=Math.max(a,b) && x>=Math.min(a,b)) ? true:false;
	}
	
	public void dsp_p(int x, int y, int l)								// ピットの表示
	{
		int i;
		dsp_g(x,y,0,0,3);												// ピットの上部を描く
		for(i=0;i>, <<, |>, □)
			case  3: w= 25; h= 12; ox=  0; oy=  0; break;				// ピット上部
			case  4: w= 25; h= 16; ox=  0; oy= 12; break;				// ピット中央
			case  5: w= 25; h= 12; ox=  0; oy= 28; break;				// ピット下部
			case  6: w= 13; h= 13; ox= 66; oy= 92; break;				// 矢印
		}
		Graphics gx=bf.create();
		gx.clipRect(x,y,w,h);
		gx.drawImage(Img,x-(ox+w*m),y-(oy+h*n),this);
		gx.dispose();
	}

	public int btn(int n)												// ボタンの表示条件
	{
		int m=0;														// 通常は白いボタン
		if((n==0 && Mf==0) || (n==2 && Mf==2)) m=1;						// クリックされているときは緑のボタン
		if((n==0 && Wait==512) || (n==2 && Wait==8)) m=2;				// 早すぎ、遅すぎは灰色に
		return m;
	}

	public void paint(Graphics g)
	{
		int i,j,l;
		bf=Buf.getGraphics();
		bf.clearRect(0,0,250,350);
		for(i=0;i<3;i++) for(j=0;j<4;j++) dsp_p(Px+i*80,Py[i][j],Pl[i][j]);	// ピットの表示
		dsp_g(Lx,119,0,0,0);											// レーザビーム(主)の表示
		dsp_g(Lx+45,18,0,0,1); dsp_g(Lx-23,241,0,0,1);					// レーザビーム(副)の表示
		bf.setColor(new Color(Bgc));
		bf.fillRect(0,300,250,80);
		dsp_g( 82,357, btn(0),1,2);										// << ボタンの表示
		dsp_g(112,357, (Mf==1)?1:0,(Run)?3:2,2);						// |> & □ ボタンの表示
		dsp_g(142,357, btn(2),0,2);										// >> ボタンの表示
		bf.setColor(new Color(255,156,156));							// グラフの表示色
		l=(F0)? Gl[get_dup(-1)]:40;										// 左のグラフの長さを求める
		bf.fillRect(80,310+(40-l),20,l);								// グラフの表示
		if(l<40) dsp_g(107,307, (N%20)/10*2,0,6);						// グラフが短いときは矢印をウインクさせる
		l=(F1)? Gl[get_dup(1)]:40;										// 右側のグラフも同様に
		bf.fillRect(150,310+(40-l),20,l);
		if(l<40) dsp_g(130,307, (N%20)/10*2+1,0,6);
		g.drawImage(Buf,0,0,this);										// バッファの表示
		bf.dispose();
	}

	public void run()
	{
		int i,j,y0,y1,y2,x0,x1;
		while(true)
		{
			repaint();
			try
			{
				Thread.sleep((Run)?Wait:128);
			}
			catch (InterruptedException e){};
			if(Run)
			{
				for(i=0;i<3;i++)
				{
					for(j=0;j<4;j++) Py[i][j]--;						// ピットを上方に移動
					if(Py[i][0]+Ps[Pl[i][0]]==0)						// 画面から消えた
					{
						for(j=0;j<3;j++) Py[i][j]=Py[i][j+1];			// 新規ピットデータの作成
						for(j=0;j<3;j++) Pl[i][j]=Pl[i][j+1];
						Py[i][j]=Py[i][j-1]+Ps[Pl[i][j-1]]+Ps[Math.abs(Rnd.nextInt())%4+1];
						Pl[i][j]=Math.abs(Rnd.nextInt())%4+1;
					}
				}
				F0=false; F1=false;
				for(i=0;i<4;i++)										// レーザーとピットの接触検出
				{
					x1=Px+80+13; y1=Py[1][i]+13; y2=y1+Pl[1][i]*16;		// ピットの中心座標
					if(x1-Lx>32) {x0=Lx+45+21; y0= 18+21;}				// レーザ副ビームの中心座標
					else         {x0=Lx-23+21; y0=241+21;}
					if(inside(y0,y1,y2) && x0-x1<33)					// ピット直線部の接触
					{
						if(i<2) F1=true;
						if(i>0) F0=true;
					}
					else												// ピットの両端での接触
					{
						if(y10) F0=true;
						}
					}
				}
				N++;
				if(N%100==0)
				{
					if((Lx-Px)!=61) Lx+=D;								// レーザーをピットの方向に移動
					else if(Px!=33)										// ピットとレーザーを中央に戻す
					{
						i=33-Px; i/=Math.abs(i);
						Lx+=i; Px+=i;
					}
				}
			}
		}
	}

	public int get_dup(int m)											// レーザーとピットの重なり幅
	{
		int d=0;
		d=(m>0)? (Px+80+25)-(Lx+45): (Lx-23+41)-(Px+80);
		if(d>11) d=11;													// 11 は配列 Gl[] の要素数
		return (d<0)?0:d;
	}

	public boolean mouseDown(Event e, int x, int y)						// マウスがクリックされたときの処理
	{
		int m=(x-125)/63, g=get_dup(m);
		if(y<300)
		{
			if(g<11) Px+=m;												// CD 部両端をクリック
			if(m==0) {Px=33; Lx=94;}									// CD 部中央をクリック
			else     D=m;
		}
		if(inside(x, 82,168) && y>357)									// ボタンをクリック
		{
			Mf=(x-82)/30;												// Mf: 0=<<,  1=|>,  2=>>
			if(inside(x, 82,108) && Wait<512) Wait*=2;					// << ボタンをクリック
			if(inside(x,142,168) && Wait>  8) Wait/=2;					// >> ボタンをクリック
		}
		return true;
	}
	
	public boolean mouseUp(Event e, int x, int y)						// クリックを止めたときの処理
	{
		if(Mf==1) Run=!Run;
		if(inside(x, 82,168) && y>357) Mf=-1;
		return true;
	}
}
//
戻る