import java.awt.*; import java.applet.*; import java.io.*; import java.net.URL; import java.net.URLConnection; import java.awt.image.*; import java.util.StringTokenizer; //-------------------------------------------------- // キャラ管理クラス //-------------------------------------------------- class CharaManage extends BasicManage{ //-------------------------------------------------- // 定数 //-------------------------------------------------- // キャラ最大数 final byte CHARA_MAX = 99; // キャライメージ最大数 final byte CHARA_IMAGE_MAX = 99; // 最大でか画像数 final byte BIG_IMAGE_MAX_NUM = 10; // でか画像の幅 final short BIG_IMAGE_WIDTH = 288; final short BIG_IMAGE_HEIGHT = 256; // キャラの幅 final byte CHARA_WIDTH = 24; final byte CHARA_HEIGHT = 32; // 中央への補正値 static final byte CENTER_OFFSET_X = -4; static final byte CENTER_OFFSET_Y = -16; // キャラアニメ数 static final byte ANIME_NUM = 3; // 一枚あたりのキャラ数 final byte ONE_CHARA_NUM = 8; //-------------------------------------------------- // メンバ //-------------------------------------------------- // でかキャラチップ private Image BigCharaImage[]; // それぞれのキャライメージ CharaImage chara_image[]; // キャラ Chara chara[]; // カメラ座標 Point camera = new Point(); // キャラ登場数 int CharaNum; // イベントテーブル用文字列バッファ StringBuffer sb[]; // イベントテーブルの行数 int EventLineNum; // イメージファイル履歴 String file_history[] = new String[ BIG_IMAGE_MAX_NUM ]; // 履歴インデックス int history_index = 0; // キャラ表示用 ソートリスト Chara sort_chara[] = new Chara[ CHARA_MAX + PlayerManage.GetInstance().m_player_num ]; // 全登場キャラ数 int m_all_chara_num; // インスタンス static CharaManage m_instance; static CharaManage GetInstance(){ return m_instance; } static void NewInstance( MapEdit applet ){ m_instance = new CharaManage( applet ); } //-------------------------------------------------- // コンストラクタ //-------------------------------------------------- CharaManage( MapEdit applet ){ this.applet = applet; } //-------------------------------------------------- // 初期化 //-------------------------------------------------- void Initialize(){ // キャラ用でか画像32個 BigCharaImage = new Image[ 32 ]; // キャラ画像50個生成 chara_image = new CharaImage[ CHARA_IMAGE_MAX ]; // キャラ99体 chara = new Chara[ CHARA_MAX ]; // イベントリストは最大100行 sb = new StringBuffer[ CHARA_MAX+1 ]; // 変数初期化 Reset(); } //-------------------------------------------------- // リセット(マップ再読み込み用) //-------------------------------------------------- void Reset(){ int i; // ファイル履歴も消去 for( i = 0; i < history_index; i++ ){ file_history[ i ] = ""; } history_index = 0; CharaNum = 0; EventLineNum = 0; } //-------------------------------------------------- // キャラ画像読み込み //-------------------------------------------------- void LoadCharaImage( String file, int no, MediaTracker mediaT ){ BigCharaImage[ no ] = applet.getImage( applet.getDocumentBase(), file ); mediaT.addImage( BigCharaImage[ no ], 0 ); } //-------------------------------------------------- // グラフィックスセット //-------------------------------------------------- void SetGraphics( Graphics g ){ this.g = g; } //-------------------------------------------------- // キャラ作成 //-------------------------------------------------- void MakeChara(){ int i, j, k, id; DebugPrint( "MakeChara()" ); // でかキャライメージをピクセル分解して、それぞれのキャラを作成 for( i = 0; i < history_index; i++ ){ int[] CharaPixels = new int[ BIG_IMAGE_WIDTH * BIG_IMAGE_HEIGHT ]; PixelGrabber pg = new PixelGrabber( BigCharaImage[ i ], 0, 0, BIG_IMAGE_WIDTH, BIG_IMAGE_HEIGHT, CharaPixels, 0, BIG_IMAGE_WIDTH ); try{ pg.grabPixels(); }catch( InterruptedException e ){ System.err.println("Error"); } // でかチップ1枚につきキャラ8体 for( id = 0; id < ONE_CHARA_NUM; id++ ){ // コンストラクタ chara_image[ ONE_CHARA_NUM*i+id ] = new CharaImage(); // 透過色の指定 最初の1pixel chara_image[ ONE_CHARA_NUM*i+id ].AlphaColor = CharaPixels[ 0 ]; // 作成 // 方向4、アニメ3 for( j = 0; j < DIR_NUM; j++ ){ for( k = 0; k < ANIME_NUM; k++ ){ MakeChipImageByBigImage( chara_image[ ONE_CHARA_NUM * i + id ].chip_image[ j ][ k ], CharaPixels, CHARA_WIDTH, CHARA_HEIGHT, ( CHARA_WIDTH * k ) + ( CHARA_WIDTH * ANIME_NUM )*( id % (ONE_CHARA_NUM/2) ), // x ( CHARA_HEIGHT * j ) + ( CHARA_HEIGHT * DIR_NUM ) * ( id / (ONE_CHARA_NUM/2) ), // y BIG_IMAGE_WIDTH ); } } } } // キャラのイメージセット for( i = 0; i < CharaNum; i++ ){ // イメージIDを取得 // でかID×8+ちびID int id2 = chara[i].BigImageID * ONE_CHARA_NUM + chara[i].image_id; chara[ i ].SetImage( chara_image[ id2 ] ); } } //-------------------------------------------------- // キャラ検索 引数はワールド座標 //-------------------------------------------------- Chara SearchChara( int x, int y ){ int i; // 検索 for( i = 0; i < CharaNum; i++ ){ // HIT if( chara[i].px / MapManage.CHIP_SIZE == x && chara[i].py / MapManage.CHIP_SIZE == y ){ return chara[i]; } } return null; } //-------------------------------------------------- // キャラ検索 引数はワールド座標 + イベント開始方法 //-------------------------------------------------- Chara SearchChara( int x, int y, int way ){ int i; // 検索 for( i = 0; i < CharaNum; i++ ){ // HIT if( chara[i].px / MapManage.CHIP_SIZE == x && chara[i].py / MapManage.CHIP_SIZE == y && chara[ i ].GetEventWay() == way ){ return chara[i]; } } return null; } //-------------------------------------------------- // 歩行アニメ //-------------------------------------------------- void WalkAnime(){ int i; for( i = 0; i < CharaNum; i++ ){ chara[i].RenewAnime(); } } // 見かけの座標変換 int ToDspScreenX( int x ){ x = ToScreenX( x ); if( x >= MapManage.GetInstance().m_total_width - MapManage.CHIP_SIZE ){ x -= MapManage.GetInstance().m_total_width; }else if( x <= - (MapManage.GetInstance().m_total_width - MapManage.WIDTH) ){ x += MapManage.GetInstance().m_total_width; } return x; } int ToDspScreenY( int y ){ y = ToScreenY( y ); if( y >= MapManage.GetInstance().m_total_height - MapManage.CHIP_SIZE ){ y -= MapManage.GetInstance().m_total_height; }else if( y <= - (MapManage.GetInstance().m_total_height - MapManage.HEIGHT) ){ y += MapManage.GetInstance().m_total_height; } return y; } //-------------------------------------------------- // 描画 //-------------------------------------------------- void DrawCharaToMemory( int OffPix[] ){ int i; int x,y; // 縮小モードならキャラを消す if( Game.GetInstance().GetMapScaleState() != Game.NORMAL_SCALE_MAP ){ return; } // 見かけ上の座標(ループマップ対策 int dsp_x, dsp_y; // Y座標の小さいものから表示 // 単純選択ソートでおk // int sort_list[] = new int[ CharaNum ]; Chara temp; // どうせ毎フレーム来るから1ステップだけにしとく。 for( i = 0; i < m_all_chara_num - 1; i++ ){ if( ToDspScreenY( sort_chara[ i ].py ) > ToDspScreenY( sort_chara[ i + 1 ].py ) ){ temp = sort_chara[ i + 1 ]; sort_chara[ i + 1 ] = sort_chara[ i ]; sort_chara[ i ] = temp; } // Y座標が同じなら優先度を見て交換 else if( ToDspScreenY( sort_chara[ i ].py ) == ToDspScreenY( sort_chara[ i + 1 ].py ) && sort_chara[ i ].priority > sort_chara[ i + 1 ].priority ){ temp = sort_chara[ i + 1 ]; sort_chara[ i + 1 ] = sort_chara[ i ]; sort_chara[ i ] = temp; //DebugPrint("("+i+"<->"+(i+1)+")" + MapCanvas.SumFrameNum ); } } for( i = 0; i < m_all_chara_num; i++ ){ // 座標変換 // マップループ対策 見かけ上の座標を変換 if( applet.IsLoopMap() ){ dsp_x = ToDspScreenX( sort_chara[ i ].px ); dsp_y = ToDspScreenY( sort_chara[ i ].py ); }else{ dsp_x = ToScreenX( sort_chara[ i ].px ); dsp_y = ToScreenY( sort_chara[ i ].py ); } dsp_x += CENTER_OFFSET_X; dsp_y += CENTER_OFFSET_Y; drawChipImageToMemory( OffPix, sort_chara[i].GetChipImage(), dsp_x, dsp_y, sort_chara[i].GetAlphaColor(), MapManage.WIDTH, MapManage.HEIGHT ); } // バトルモードの場合、キャラの上にHPメータ表示 if( Game.GetInstance().GetNowPhase() == Game.BATTLE_PHASE ){ DrawHpMeter(); } } //-------------------------------------------------- // HPメーター描画 //-------------------------------------------------- void DrawHpMeter(){ int i; // 見かけ上の座標(ループマップ対策 int dsp_x, dsp_y; int color; for( i = 0; i < m_all_chara_num; i++ ){ // 座標変換 // マップループ対策 見かけ上の座標を変換 if( applet.IsLoopMap() ){ dsp_x = ToDspScreenX( sort_chara[ i ].px ); dsp_y = ToDspScreenY( sort_chara[ i ].py ); }else{ dsp_x = ToScreenX( sort_chara[ i ].px ); dsp_y = ToScreenY( sort_chara[ i ].py ); } dsp_x += CENTER_OFFSET_X; dsp_y += CENTER_OFFSET_Y; Game.GetInstance().fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), dsp_x, dsp_y, 24, 2, 0xFF000000 ); // 元気は緑 if( sort_chara[ i ].m_hp > 10 ){ color = 0xff00ff00; } // ピンチは赤 else{ color = 0xffff0000; } Game.GetInstance().fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), dsp_x, dsp_y, sort_chara[ i ].m_hp, 2, color ); } } //-------------------------------------------------- // メモリイメージに描画 //-------------------------------------------------- void drawChipImageToMemory( int []off, ChipImage chip_image, int x, int y, int aplha_color, int off_width, int off_height ){ int xx, yy, yyy; int point; for( yy = 0; yy < CHARA_HEIGHT; yy++ ){ yyy = (yy+y)*off_width; for( xx = 0; xx < CHARA_WIDTH; xx++ ){ // 領域外なら書き込まない if( x + xx < 0 || x + xx > off_width ){ continue; } if( y + yy < 0 || y + yy > off_height ){ continue; } // 書き込む場所 point = x + xx + yyy; if( point >= 0 && point < off_width * off_height ){ // 透過色ならスキップ if( chip_image.pix[ xx + yy*CHARA_WIDTH ] == aplha_color ) continue; off[ point ] = chip_image.pix[ xx + yy*CHARA_WIDTH ]; //off[ x + xx + (yy+y)*MapManage.WIDTH ] = 0xFFFF0000; } } } } // カメラの座標セット void SetCameraPoint( Point p ){ this.camera.x = p.x; this.camera.y = p.y; } //-------------------------------------------------- // イベントリスト読み込み //-------------------------------------------------- void LoadEventList( String file ){ int i, j; DebugPrint( file ); try{ InputStream is = new URL( applet.getDocumentBase(), file ).openStream(); // テキストだからリーダーを使う BufferedReader br = new BufferedReader( new InputStreamReader( is ) ); // ライン格納 String line; DebugPrint( "event_load_start" ); // 一行ずつ読み込む int line_num = 0; while( ( line = br.readLine() ) != null ){ // バッファに追加していく(StringBufferは軽いはず…) sb[line_num] = new StringBuffer(); sb[line_num].append( line ); line_num++; } is.close(); EventLineNum = line_num; // 解析してキャラ配置 AnalyzeEventTable(); }catch( IOException e ){ // イベントリストがない時もありえる DebugPrint( "load_fail" ); } // 主人公配置 // 全登場キャラ(主人公と合わせる) m_all_chara_num = CharaNum + PlayerManage.GetInstance().m_player_num; // ソートリストに登録 for( i = 0; i < CharaNum; i++ ){ sort_chara[ i ] = chara[ i ]; } for( i = 0; i < PlayerManage.GetInstance().m_player_num; i++ ){ sort_chara[ i + CharaNum ] = PlayerManage.GetInstance().GetPlayerInstance( i ); } // 先に完全ソートしとく Chara temp; for( i = 0; i < m_all_chara_num - 1; i++ ){ for( j = i + 1; j < m_all_chara_num; j++ ){ if( sort_chara[ i ].py > sort_chara[ j ].py ){ temp = sort_chara[ j ]; sort_chara[ j ] = sort_chara[ i ]; sort_chara[ i ] = temp; } // Y座標が同じなら優先度を見て交換 else if( sort_chara[ i ].py == sort_chara[ j ].py && sort_chara[ i ].priority > sort_chara[ j ].priority ){ temp = sort_chara[ j ]; sort_chara[ j ] = sort_chara[ i ]; sort_chara[ i ] = temp; //DebugPrint("("+i+"<->"+(i+1)+")" + MapCanvas.SumFrameNum ); } } } } //-------------------------------------------------- // イベントテーブル解析 //-------------------------------------------------- void AnalyzeEventTable(){ int i, j; int big_chip_id; boolean new_flag; // トークン分割用クラス StringTokenizer st; history_index = 0; for( i = 0; i < EventLineNum; i++ ){ st = new StringTokenizer( sb[i].toString(), "<>" ); // チップセットファイル名取得 String file = st.nextToken(); // ファイル利用履歴確認 new_flag = true; big_chip_id = history_index; // とりあえずIDは最新に for( j = 0; j < history_index; j++ ){ // 登録済み if( file.equals( file_history[ j ] ) ){ new_flag = false; big_chip_id = j; // ID更新(前のもの) break; } } // 画像の対応は後回しにしてキャラを作成しておく chara[ i ] = new Chara(); // でかちっぷIDセット chara[ i ].SetBigImageID( big_chip_id ); // イメージID chara[ i ].SetImageID( Integer.parseInt( st.nextToken() ) ); // 座標 int x = Integer.parseInt( st.nextToken() ); int y = Integer.parseInt( st.nextToken() ); chara[ i ].SetPoint( x * MapManage.CHIP_SIZE, y * MapManage.CHIP_SIZE ); // 方向 chara[ i ].SetDir( Integer.parseInt( st.nextToken() ) ); // 対応イベント if( st.hasMoreTokens() ){ chara[ i ].SetEvent( st.nextToken() ); } // イベント開始方法 if( st.hasMoreTokens() ){ chara[ i ].SetEventWay( Integer.parseInt( st.nextToken() ) ); } // 通行フラグ if( file.equals("null.gif") ){ chara[ i ].SetMoveFlag( true ); }else{ chara[ i ].SetMoveFlag( false ); } // 新しいでかチップファイルのようなら登録 if( new_flag ){ file_history[ history_index ] = new String( file ); history_index++; DebugPrint(file); } } CharaNum = EventLineNum; } }