package gameCanvasUtil;


import java.awt.*;   // グラフィックスクラスの読み込み
import javax.swing.JFrame;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.*;
import java.util.*;
import javax.swing.JOptionPane;
import javax.imageio.ImageIO;
import gameCanvasUtil.vector.*;
import gameCanvasUtil.classLoad.*;

/** さまざまな機能を取りまとめたクラス
  *
  * 基本的には他にたらい回すだけです
  */
public class gameCanvas{
	/** 画面の幅 */
	public static final int WIDTH=640;
	/** 画面の高さ */
	public static final int HEIGHT=480;
	/** FPSの設定 */
	public static final int CONFIG_FPS = 30;
	/** saveDataのサイズ */
	private static final int SAVE_DATA_SIZE = 1024;
	
	
	/** 上ボタン */
	public static final int KEY_UP=inputManager.BUTTON_UP;
	/** 下ボタン */
	public static final int KEY_DOWN=inputManager.BUTTON_DOWN;
	/** 左ボタン */
	public static final int KEY_LEFT=inputManager.BUTTON_LEFT;
	/** 右ボタン */
	public static final int KEY_RIGHT=inputManager.BUTTON_RIGHT;

	/** Zキー */
	public static final int KEY_Z=inputManager.BUTTON_A;
	/** Xキー */
	public static final int KEY_X=inputManager.BUTTON_B;
	/** Cキー */
	public static final int KEY_C=inputManager.BUTTON_C;
	/** Vキー */
	public static final int KEY_V=inputManager.BUTTON_D;

	/** ENTER */
	public static final int KEY_ENTER=inputManager.BUTTON_PAUSE;

	/** SPACE */
	public static final int KEY_SPACE=inputManager.BUTTON_SELECT;
	
	
	//色関係の定数

	/** 白色 */
	public static final int COLOR_WHITE =  0xFFFFFF;
	/** 黒色 */
	public static final int COLOR_BLACK =  0x000000;
	/** 灰色 */
	public static final int COLOR_GRAY =   0x808080;
	/** 赤色 */
	public static final int COLOR_RED =    0xFF0000;
	/** 青色 */
	public static final int COLOR_BLUE =   0x0000FF;
	/** 緑色 */
	public static final int COLOR_GREEN =  0x00FF00;
	/** 黄色 */
	public static final int COLOR_YELLOW = 0xFFFF00;
	/** 紫色 */
	public static final int COLOR_PURPLE = 0xFF00FF;
	/** シアン色 */
	public static final int COLOR_CYAN=    0x00FFFF;
	/** みずいろ */
	public static final int COLOR_AQUA=    0x7F7FFF;

	//画像の管理とかをするオブジェクト
	private imageManager images;
	//SEの管理をするオブジェクト
	private soundManagerInterface sound_effect;
	//BGMの管理をするオブジェクト
	private soundManagerInterface bgm;
	//キーの入力を管理するオブジェクト
	private inputManager input;
	//実行するゲームインターフェースを継いだオブジェクト
	private gameInterface game;

	//ランダム用
	private Random rand = new Random();
	
	//フォントサイズ
	private int FontSize=10;
	
	//前のBGM
	private int bk_snd;

	//描画先
	private Graphics g;
	private Image offImage;

	//JFrameへの参照
	private JFrame frame;
	
	//シングルトン用に作成
	static private gameCanvas _gc;
	
	//デフォルトで起動するゲームインターフェース
	private gameInterface default_game;


	/** シングルトン
	 * 既にgameCanvasオブジェクトが生成されていたら、それを返す。ないなら生成して返す。
	 * @return gameCanvasオブジェクトを返す
	 */
	static public gameCanvas getInstance(){
		if(_gc==null)
			_gc = new gameCanvas();
		return _gc;
	}


	/** シングルトンのため、プライベートコンストラクタ
	 */
	private gameCanvas(){
	}


	/** gameCanvasの初期化を行う
	 */
	public void init(JFrame _f){
		this.frame = _f;
		this.bk_snd = -1;
		
		this.setImageManager(new imageManager("res/img",imageManager.NUMBER_AUTO_CULC));
		this.setSeManager( new soundManager("res/snd",soundManager.NUMBER_AUTO_CULC));
		this.setBgmManager( new midiManager("res/bgm",midiManager.NUMBER_AUTO_CULC));
		this.changeBgmVolume(60);
		this.changeSeVolume(100);
		this.input = inputManager.getInstance();	
		this.readRecord();
	}



	/** gameCanvasの終了時の処理です
	 */
	public void finalize(){
		if(this.game!=null){
			this.game.finalGame();
		}
		//セーブ処理
		if(save_flag){
			this.writeRecord();
			save_flag = false;
		}
	}

	/** Graphicsクラスへの参照をセットする
	 * @param gra
	 */
	public void setGraphics(Graphics gra,Image img){
		this.g = gra;
		this.offImage = img;
		setFont("",0,25);
	}


	/** 現在の画面を、画像として保存します
	 * @param file 拡張子を除いたファイル名を入れます
	 * @return 保存に成功したかを返します
	 */
	public boolean writeScreenImage(String file){
		BufferedImage cur_off = new BufferedImage(gameCanvas.WIDTH,gameCanvas.HEIGHT , BufferedImage.TYPE_INT_RGB);
		Graphics gr = cur_off.getGraphics();
		gr.drawImage( offImage , 0 , 0 , null );
		try{
			return ImageIO.write( cur_off , "PNG" , new File( file+".png") );
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}
	}

	/** Windowの文字列を指定します
	 * @param title Windowのタイトルの文字列を指定
	 */
	public void setWindowTitle(String title){
		frame.setTitle(title);
	}


	/** 文字列を描画する
	 * @param str 描画する文字列
	 * @param x   左上のＸ座標
	 * @param y   左上のＹ座標
	 */
	public void drawString(String str,int x,int y){
		g.drawString(str,x,y+g.getFont().getSize());
	}


	/** 文字列を中心位置を指定して描画する
	 * @param str 描画する文字列
	 * @param x   中心のＸ座標
	 * @param y   上のＹ座標
	 */
	public void drawCenterString(String str,int x,int y){
		this.drawString(str, x - getStringWidth(str)/2,y);
	}


	/** 文字列を右寄せにして描画する
	 * @param str 描画する文字列
	 * @param x   右上のＸ座標
	 * @param y   上のＹ座標
	 */
	public void drawRightString(String str,int x,int y){
		this.drawString(str, x - getStringWidth(str),y);
	}

	///フォントオブジェクト
	private Font myFont;

	/** drawStringなどで使用するフォントを変更します。
	 * @param font_name フォント名の指定
	 * @param font_style フォントのスタイルの指定
	 * @param font_size フォントのサイズの指定
	 */
	public void setFont( String font_name, int font_style, int font_size){
		myFont = new Font(font_name,font_style,font_size);
		g.setFont(myFont);
		FontSize = font_size;
	}

	/** フォントサイズの変更
	 * @param font_size フォントのサイズを指定します
	 */
	public void setFontSize(int font_size){
		this.setFont("",0,font_size);
	}


	/**　文字列のどっと幅を調べます
	 * 
	 * 引数strをdrawString等で描画したときの幅を返します。
	 * @param str 調べる文字列
	 * @return 引数strを描画したときの幅
	 */
	public int getStringWidth(String str){
		FontMetrics obj = g.getFontMetrics();
		return obj.stringWidth(str);
	}


	/** drawStringや、drawRectなどで使用する色のセット
	 * @param color RGBで指定
	 */	
	public void  setColor(int color){
		int r=(color>>16)&0xFF;
		int g=(color>>8)&0xFF;
		int b=color&0xFF;
		setColor(r,g,b);
	}


	/** drawStringや、drawRectなどで使用する色のセット
	 * @param red Ｒ成分
	 * @param green Ｇ成分
	 * @param blue Ｂ成分
	 */
	public void setColor(int red,int green,int blue){
		g.setColor(  new Color(red,green,blue) );
	}


	/** 直線の描画
	 * @param sx 開始点のX座標
	 * @param sy 開始店のY座標
	 * @param ex 終了点のX座標
	 * @param ey 終了点のY座標
	 */
	public void drawLine(int sx,int sy,int ex,int ey){
		g.drawLine(sx,sy,ex,ey);
	}


	/** 中抜きの長方形の描画
	 * @param x 長方形の左上のＸ座標
	 * @param y 長方形の左上のＹ座標
	 * @param w 長方形の幅
	 * @param h 長方形の高さ
	 */
	public void drawRect(int x,int y,int w,int h){
		g.drawRect(x,y,w,h);
	}


	/** 塗りつぶしの長方形の描画
	 * @param x 長方形の左上のＸ座標
	 * @param y 長方形の左上のＹ座標
	 * @param w 長方形の幅
	 * @param h 長方形の高さ
	 */
	public void fillRect(int x,int y, int w,int h){
		g.fillRect(x,y,w,h);
	}


	/** 中抜き円の描画
	 * @param x 円の中心のＸ座標
	 * @param y 円の中心のＹ座標
	 * @param r 円の半径
	 */
	public void drawCircle(int x,int y,int r){
		g.drawArc(x-r,y-r, r*2, r*2 , 0, 360 );
	}


	/** 塗りつぶし円の描画
	 * @param x 円の中心のＸ座標
	 * @param y 円の中心のＹ座標
	 * @param r 円の半径
	 */
	public void fillCircle(int x,int y,int r){
		g.fillArc(x-r,y-r, r*2, r*2 , 0, 360);
	}


	/** 画像描画
	 * @param id 画像のID。img0.gifならIDは0。img1.gifならIDは1。
	 * @param x 画像の左上のＸ座標
	 * @param y 画像の左上のＹ座標
	 */
	public void drawImage(int id,int x,int y){
		try{
			g.drawImage(images.getImage(id), x, y ,null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}


	/** 画像部分描画
	 * @param id 画像のID。img0.gifならIDは0。img1.gifならIDは1。
	 * @param x 画像の左上のＸ座標
	 * @param y 画像の左上のＹ座標
	 * @param u 元画像より使用する部分の左上Ｘ座標
	 * @param v 元画像より使用する部分の左上Ｙ座標
	 * @param w 描画する幅
	 * @param h 描画する高さ
	 */
	public void drawClipImage(int id,int x,int y,int u,int v,int w,int h){
		try{
			g.drawImage(images.getImage(id), x, y,x+w,y+h,u,v,w+u,v+h,null);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}


	/// アフィントランス用
	private AffineTransform tr = new AffineTransform();

	/** 画像を拡大縮小・回転をかけて表示
	 * @param id　  画像のナンバーです
	 * @param x     画像の中心Ｘ座標です
	 * @param y     画像の中心Ｙ座標です
	 * @param xsize 横にどのくらい拡大するか？100%を基準にしてます。(xsizeが100の時、等倍。200なら2倍の大きさ)
	 * @param ysize 縦にどのくらい拡大するか？100%を基準にしてます。(ysizeが100の時、等倍。200なら2倍の大きさ)
	 * @param angle 画像を何度回転させるか？(角度で指定)not弧度法
	 */
	public void drawScaledRotateImage(int id,int x,int y,
			int xsize,int ysize,double rotate){
		double w = (double)(this.getImageWidth(id))/2.0;
		double h = (double)(this.getImageHeight(id))/2.0;
		this.drawScaledRotateImage(id,x,y,xsize,ysize,rotate,w,h);
	}

	/** 画像を拡大縮小・回転をかけて表示
	 * @param id　  画像のナンバーです
	 * @param x     画像の中心Ｘ座標です
	 * @param y     画像の中心Ｙ座標です
	 * @param xsize 横にどのくらい拡大するか？100%を基準にしてます。(xsizeが100の時、等倍。200なら2倍の大きさ)
	 * @param ysize 縦にどのくらい拡大するか？100%を基準にしてます。(ysizeが100の時、等倍。200なら2倍の大きさ)
	 * @param angle 画像を何度回転させるか？(角度で指定)not弧度法
	 * @param px    画像の回転の中心位置のＸ座標
	 * @param py    画像の回転の中心位置のＹ座標
	 */
	public void drawScaledRotateImage(int id,int x,int y,
			int xsize,int ysize,double rotate,double px,double py){
		Image img = this.images.getImage(id);
		if(img == null)
			return;
		Graphics2D gr = (Graphics2D)this.g;
		
		px *= xsize/100.0;
		py *= ysize / 100.0;
		
		//正規化
		tr.setToIdentity();
		
		tr.translate(x,y);
		tr.rotate(rotate*Math.PI/360.0 );
		tr.translate(-px,-py);

		tr.scale( xsize/100.0,ysize/100.0);
		gr.drawImage(img,tr,null);
	}

	/** 画像の幅を得る
	 * @param id 画像のID。img0.gifならIDは0。img1.gifならIDは1。
	 * @return 引数idで指定された画像の幅を返す
	 */
	public int getImageWidth(int id){
		return images.getPicXsize(id);
	}


	/**
	 * 画像の高さを得る
	 * @param id 画像のID。img0.gifならIDは0。img1.gifならIDは1。
	 * @return 引数idで指定された画像の高さを返す
	 */
	public int getImageHeight(int id){
		return images.getPicYsize(id);
	}


	/** 乱数の種をセットする
	 * @param seed セットする乱数のシード
	 */
	public void setSeed(int seed) {
		rand.setSeed(seed);
	}


	/** min～maxまでの間のランダムな値を返す。
	 * @param min ランダムの最小値
	 * @param max ランダムの最大値
	 * @return    生成したランダム値
	 */
	public int rand(int min,int max){
		int tmp = rand.nextInt();
		if(tmp < 0)
			tmp = -tmp;
		if(min < max){
			max = max - min + 1;
			return tmp%max + min;
		}else{
			min = min - max + 1;
			return tmp%min + max;
		}
	}


	/** ゲームステートの変更
	 * @param g 実行するgameInterfaceを継承したクラス
	 * @param flag init、finalGameを行うかのフラグ。trueなら現在のオブジェクトをfinalGameして、initを行います
	 */
	public void changeGameState(gameInterface g , boolean flag){
		if(this.game!=null && flag)
			this.game.finalGame();
		if( g != null && flag)
			g.initGame();
		this.game = g;
	}

	/** ゲームステートの変更
	 * @param g 実行するgameInterfaceを継承したクラス
	 */
	public void changeGameState(gameInterface g){
		this.changeGameState( g , true );
	}

	/** ゲームステートの変更(動的にクラスをロードする)
	 * @param file クラスファイルを指定します
	 * @param flag init、finalGameを行うかのフラグ。trueなら現在のオブジェクトをfinalGameして、initを行います
	 * @return classファイルの読み込みに成功したかを返します
	 */
	public boolean loadGameState( String file ,boolean flag){
		try{
			//Class cur_class = Class.forName(file, true, ClassLoader.getSystemClassLoader());
			Class cur_class = new FileClassLoader().loadClassFile(new File(file) );
			if(cur_class == null)
				return false;
			this.changeGameState( (gameInterface)cur_class.newInstance() , flag);
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}

		return true;
	}

	/** ゲームステートをデフォルト状態にします
	 */
	public void resetGame(){
		this.changeGameState( null );
		this.stopBgm();
		this.stopSe();
		this.translate(0,0);
	}


	/** デフォルトで実行されるクラスの設定
	 */
	public void setDefaultGameState(gameInterface g){
		this.default_game = g;
	}


	/** 更新時に行う処理
	 */
	public void updateMessage(){
		if(this.game!=null){
			this.game.updateGame();
			//セーブ処理
			if(save_flag){
				this.writeRecord();
				save_flag = false;
			}
		}
		else{
			try{
				this.changeGameState( (gameInterface)default_game.getClass().newInstance() );
			}
            catch(Exception e)
            {
                e.printStackTrace();
			}
		}
		//BGMがストリーミング再生なのでアップデート
		this.bgm.update();
	}


	/** 描画時に行う処理
	 */
	public void drawMessage(){
		if(this.game!=null && this.g!=null)
			this.game.drawGame();
	}


	/** 画面を白で塗りつぶす
	 * 
	 */
	public void clearScreen(){
		setColor(255,255,255);
		fillRect(0,0,WIDTH,HEIGHT);
	}


	//現在どれくらい画面がずれているか？
	private int offset_x,offset_y;

	/** ゲーム画面を少しずらす
	 * @param x ずらすＸ成分 
	 * @param y ずらすＹ成分
	 */
	public void translate(int x,int y){
		this.g.translate(x-offset_x,y-offset_y);
		this.offset_x = x;
		this.offset_y = y;
	}


	/** アプリを終了させる
	 */
	public void exitApp(){
		try{
			this.game.finalGame();
		}catch(Exception e){
			e.printStackTrace();
		}
		System.exit(0);
	}


	/** YesNoを選択させるダイアログを出す
	 * @param message 確認用のメッセージ
	 * @return 選択肢の結果を返す
	 */
	public boolean showYesNoDialog(String message){
		return ( JOptionPane.YES_OPTION == 
			JOptionPane.showConfirmDialog(null,message,null,JOptionPane.YES_NO_OPTION ) );
	}


	/** ユーザーに文字列の入力を求めるダイアログを出す
	 * 
	 * @param message ユーザーに対するメッセージ
	 * @param default_input デフォルト状態での入力
	 * @return 入力されたメッセージを返す
	 */
	public String showInputDialog(String message,String default_input){
		return JOptionPane.showInputDialog(null, message,default_input);
	}


	//---------------- Sound 関係 -------------------//
	/// 現在鳴らしているBGM
	private int cur_bgm = -1;

	/** BGM再生
	 * BGMの再生は排他的で、二個同時というのは基本なしです
	 * @param id BGMの番号
	 */
	public void playBgm(int id){
		this.playBgm(id,true);
	}


	/** BGM再生
	 * BGMの再生は排他的で、二個同時というのは基本なしです
	 * @param id BGMの番号
	 * @param loop ループするかどうかを指定する
	 */
	public void playBgm(int id,boolean loop){
		if(cur_bgm != id){
			bgm.stopSound();
			bgm.playSound(id,loop);
		}
		cur_bgm = id;
	}


	/** BGMボリューム調整
	 * @param volume 音量の指定(0-100)
	 */
	public void changeBgmVolume(int volume){
		bgm.changeVolume(volume);
	}


	/** BGM停止
	 */
	public void stopBgm(){
		if(bgm != null)
			bgm.stopSound();
		cur_bgm = -1;
	}


	/** BGM一時停止
	 */
	public void pauseBgm(){
		bgm.pauseSound();
		cur_bgm = -1;
	}


	/** SE再生
	 * @param id SEの番号
	 */
	public void playSe(int id){
		this.playSe(id,false);
	}


	/** SE再生
	 * @param id SEの番号
	 * @param loop SEをループさせるかセットする
	 */
	public void playSe(int id,boolean loop){
		this.sound_effect.playSound(id,loop);
	}


	/** SEボリューム調整
	 * @param volume 音量の指定(0-100)
	 */
	public void changeSeVolume(int volume){
		this.sound_effect.changeVolume(volume);
	}


	/** 全てのSE停止
	 */
	public void stopSe(){
		this.sound_effect.stopSound();
	}


	/** 全てのSE一時停止
	 */
	public void pauseSe(){
		this.sound_effect.pauseSound();
	}

	//-------------------キー入力関係-----------//

	/** キーを押している長さを調べる
	 * 引数で指定したキーが、どのくらい押されているかを返す。
	 * @param keyCode KEY_0 なら「0キー」KEY_LEFT なら 「左カーソルキー」という感じで、調べたいキーを指定
	 * @return 引数 keyCodeで指定されたキーを押している長さを返す。-1が離した直後。0なら押されていない。1以上は押している長さ
	 */
	public int getKeyPressLength(int keyCode){
		return input.getKeyPressLength(keyCode);
	}


	/** キーを押しているか確かめる
	 * 引数で指定したキーが、押している場合trueを返します。
	 * @param keyCode KEY_0 なら「0キー」KEY_LEFT なら 「左カーソルキー」という感じで、調べたいキーを指定
	 * @return 引数 keyCodeで指定されたキーが押された直後であった場合 true。離していた場合 false
	 */
	public boolean isKeyPress(int keyCode){
		return input.isKeyPressed(keyCode);
	}


	/** キーが押した瞬間か確かめる
	 * 引数で指定したキーが、押された直後であった場合trueを返します。
	 * @param keyCode KEY_0 なら「0キー」KEY_LEFT なら 「左カーソルキー」という感じで、調べたいキーを指定
	 * @return 引数 keyCodeで指定されたキーが押された直後であった場合 true。キーが押しっぱなし、離されている状態の場合 false
	 */
	public boolean isKeyPushed(int keyCode){
		return input.isKeyPushed(keyCode);
	}


	/** キーを離した瞬間か確かめる
	 * 引数で指定したキーが、離した直後であった場合trueを返します。
	 * @param keyCode KEY_0 なら「0キー」KEY_LEFT なら 「左カーソルキー」という感じで、調べたいキーを指定
	 * @return 引数 keyCodeで指定されたキーが離された直後であった場合 true。キーを押している、離しっぱなしの状態の場合 false
	 */
	public boolean isKeyReleased(int keyCode){
		return input.isKeyReleased(keyCode);
	}


	/** マウスのX座標を取得する
	 * @return 現在のマウスのX座標を返す
	 */
	public int getMouseX(){
		return this.input.getMouseX();
	}


	/** マウスのY座標を取得する
	 * @return 現在のマウスのX座標を返す
	 */
	public int getMouseY(){
		return this.input.getMouseY();
	}


	/** マウスのボタンを押している時間を調べる
	 * @return マウスの押している時間を調べる
	 */
	public int getMouseClickLength(){
		return this.input.getMouseClickLength();
	}


	/** マウスのボタンを押した瞬間か調べる
	 * @return マウスのボタンを押した瞬間ならtrueを返す
	 */
	public boolean isMousePushed(){
		return this.input.isMousePushed();
	}


	/** マウスのボタンを離した瞬間かを調べる
	 * @return マウスのボタンを離した瞬間ならtrueを返す
	 */
	public boolean isMouseReleased(){
		return this.input.isMouseReleased();
	}


	/** マウスのボタンを押しているか調べる
	 * @return マウスのボタンを押していたらtrueを返す
	 */
	public boolean isMousePress(){
		return this.input.isMousePress();
	}


	//-------------------- セーブデータ系 ------------------//
	///セーブデータ用バッファ
	private int saveData[];
	//セーブデータに変更を加えたかのフラグ
	private boolean save_flag = false;

	/** セーブデータバッファに溜め込んだデータを書き出す
	 */
	private void writeRecord(){
		byte tmp[] = saveDataUtil.intarr2bytearr(saveData);
		saveDataUtil.writeByteArray("savedata.dat", tmp);
	}


	/** ファイルからセーブデータバッファに溜め込む
	 */
	private void readRecord(){
		byte tmp[] = saveDataUtil.readByteArray("savedata.dat");
		if(tmp==null){
			this.saveData = new int[SAVE_DATA_SIZE];
			this.writeRecord();
		}else{
			this.saveData = saveDataUtil.bytearr2intarr(tmp);
		}
	}


	/** セーブデータバッファからデータを取得する。
	 * @param position セーブデータバッファの位置を指定
	 * @return 指定された位置からデータを読み出して返す
	 */
	public int load(int position){
		return saveData[position];
	}


	/** セーブデータバッファにデータをセットする
	 * @param position セーブデータバッファの位置を指定
	 * @param param セーブデータに書き込む値をセット
	 */
	public void save(int position,int param){
		this.saveData[position] = param;
		save_flag = true;
	}


	//--------------- 当たり判定系 ----------------//

	/** 矩形Ａと矩形Ｂがぶつかっているか判定する
	 * @param x1 矩形Ａの左上Ｘ座標
	 * @param y1 矩形Ａの左上Ｙ座標
	 * @param w1 矩形Ａの幅
	 * @param h1 矩形Ａの高さ
	 * @param x2 矩形Ｂの左上Ｘ座標
	 * @param y2 矩形Ｂの左上Ｙ座標
	 * @param w2 矩形Ｂの幅
	 * @param h2 矩形Ｂの高さ
	 *
	 */
	public boolean checkHitRect(
			int x1,int y1,int w1,int h1,
			int x2,int y2,int w2,int h2
	){
		return collision.checkHitRect(x1, y1, w1, h1, x2, y2, w2, h2);
	}


	/** 画像Aと画像Bを指定位置に書いたとしたときに画像同士が当たっているかを確かめる
	 * 
	 * drawImageでもし、画像Aと画像Bを書いたときに
	 * @param img1 画像AのIDを指定
	 * @param x1 画像Aの左上X座標を指定
	 * @param y1 画像Aの左上Y座標を指定
	 * @param img2 画像BのIDを指定
	 * @param x2 画像Bの左上X座標を指定
	 * @param y2 画像Bの左上Y座標を指定
	 * @return 画像同士が当たっているかどうかを返します
	 */
	public boolean checkHitImage(
			int img1,int x1,int y1,int img2,int x2,int y2
	){
		return this.checkHitRect(
				x1,y1,this.getImageWidth(img1),this.getImageHeight(img1),
				x2,y2,this.getImageWidth(img2),this.getImageHeight(img2) );
	}


	/** 円Aと円Bの当たり判定を行う
	 * 
	 * @param x1 円Aの中心X座標
	 * @param y1 円Aの中心Y座標
	 * @param r1 円Aの半径
	 * @param x2 円Bの中心X座標
	 * @param y2 円Bの中心Y座標
	 * @param r2 円Bの半径
	 * @return 円Aと円Bが当たったかどうか？
	 */
	public boolean checkHitCircle(int x1,int y1,int r1,
		int x2,int y2,int r2){
		return collision.checkHitCircle(x1, y1, r1, x2, y2, r2);
	}

	//-----------------　数学系のメソッド ------------//

	/** 平方根(√)を求める
	 * 
	 * @param data 平方根を求めたい数字
	 * @return 引数で与えられた数字の平方根を返す
	 */
	public double sqrt(double data){
		return Math.sqrt(data);
	}


	/** cosを求める
	 * 
	 * @param angle 角度を指定する(not 弧度法)
	 * @return angleのcos
	 */
	public double cos(double angle){
		return Math.cos(angle * Math.PI / 180.0);
	}


	/** sinを求める
	 * 
	 * @param angle 角度を指定する(not 弧度法)
	 * @return angleのsin
	 */
	public double sin(double angle){
		return Math.sin(angle * Math.PI / 180.0);
	}


	/** atan2を求める(ベクトルの角度を求める)
	 * 
	 * @param x ベクトルのX成分
	 * @param y ベクトルのY成分
	 * @return ベクトルの角度を返す
	 */
	public double atan2(double x,double y){
		return Math.atan2(x,y) * 180.0 / Math.PI;
	}


	//------------- 画像・サウンドの管理者のset/get --------//

	/** 画像の管理者をセットします。
	 * @param manager 変更したい画像の管理者
	 */
	public void setImageManager(imageManager manager){
		this.images = manager;		
	}


	/** 効果音の管理者をセットします
	 * @param manager 変更したい効果音の管理者
	 */
	public void setSeManager(soundManagerInterface manager){
		if( this.sound_effect != null)
			this.sound_effect.stopSound();
		this.sound_effect = manager;		
	}


	/** BGMの管理者をセットします
	 * @param manager 変更したいBGMの管理者
	 */
	public void setBgmManager(soundManagerInterface manager){
		this.stopBgm();
		this.bgm = manager;		
	}


	/** gameCanvasで今、画像を管理している奴を取得します
	 * @return 現在のgameCanvasの画像管理者
	 */
	public imageManager getImageManager(){
		return this.images;
	}


	/** gameCanvasで今、効果音を管理している奴を取得します 
	 * @return 現在のgameCanvasの効果音管理者
	 */
	public soundManagerInterface getSeManager(){
		return this.sound_effect;
	}


	/** gameCanvasで今、BGMの管理をしている奴を取得します 
	 * @return 現在のgameCanvasのBGM管理者
	 */
	public soundManagerInterface getBgmManager(){
		return this.bgm;
	}


}
