//java.appletパッケージをimport宣言 //Graphicsクラスはawtパッケージに属しているのでawtパッケージもimport宣言 //画面ちらつきを抑えるためにダブルバッファをする import java.applet.*; import java.awt.*; import java.awt.event.*; import java.net.*;//ネットワーク関係 import java.io.*;//ファイル読み込み import java.util.Random;//乱数 import java.lang.Math;//tan^-1(アークタンジェント用、角度計算 import javax.media.*;//動画再生用 import javax.swing.*;//テスト public class nico_player extends JApplet implements MouseListener, MouseMotionListener, Runnable, ControllerListener,ActionListener { //*******************************************************# //init()内入力処理 //*******************************************************# int x_max;//アプレット最大X座標(px) int y_max;//アプレット最大Y座標(px) String id;//ページID String server;//保存先サーバホスト名 String message = "起動開始\n"; int com_max = 40;//コメント総合件数 TextArea ta = new TextArea();//テキストエリア(メッセージフォーム作成) TextField tf = new TextField();//テキストフィールド("初期値") Player player = null;//動画再生Player String FILE;//ファイル名(アプレットより取得) //*******************************************************# //*******************************************************# //ターゲット移動・イベント処理 //*******************************************************# Thread th = null;//スレッド生成 Graphics gBuf;//オフスクリーンバッファのグラフィックコンテキスト Image imgBuf;//バッファイメージ AudioClip audio[] = new AudioClip[4];//爆発・発射オーディオファイル Image img[] = new Image[3];//ゴミ箱・ふるぼっこ画像表示 int font_size = 40;//移動文字フォントサイズ int mouse_count = 0;//マウスカウント数 String str[] = new String[com_max];//流れるコメントデータ[移動コメント最大個数] int x_str[] = new int[com_max];//移動X座標 int y_str[] = new int[com_max];//移動Y座標 int target_count = com_max;//残りターゲット数 int com_counter = 0;//コメント投稿カウンター String Test_com = "完全にうごいたああああああああ!!!!!";//ローカルテスト用コメント //*******************************************************# public void init()//アプレットの初期化時呼び出される { //アプレットサイズ取得 Dimension d = getSize();//アプレットサイズ取得 this.x_max = d.width;//アプレット最大X座標取得 this.y_max = d.height;//アプレット最大Y座標取得 //*******************************************************# //以下フォーム部品追加クラス //import java.applet.*;//java.appletパッケージをimport宣言 //import java.awt.*;//java.awtパッケージもimport宣言 //*******************************************************# //AWTのGUIコンポーネントクラスの作成 Label la = new Label("コメント");//ラベル Button bu = new Button("投稿");//書き込みボタン //TextField tf = new TextField();//テキストフィールド("初期値") //TextArea ta = new TextArea();//TextArea ta = new TextArea("初期値");//と初期値を入力することもできる。 //TextArea ta = this.ta;//共通テキストエリアメッセージフィールド読み込み //レイアウトを自由に設定する setLayout(null); //アプレット領域にGUIコンポーネント(部品)の追加(載せる) add(la); add(bu); add(tf); add(ta); //(x,y,w 表示横幅,h 表示高さ)コンポーネントを指定した位置に配置する。 la.setBounds(this.x_max*2/5, this.y_max - 25, 60, 25);//ラベル tf.setBounds(this.x_max*2/5+60, this.y_max - 25, (int)(this.x_max * 2 / 5) - 120, 25);//テキストフィールド bu.setBounds((int)(this.x_max * 4 / 5) - 60, this.y_max - 25, 60, 25);//書き込みボタン this.ta.setBounds((int)(this.x_max * 4 / 5), 0, (int)(this.x_max / 5), this.y_max);//メッセージウィンドウ bu.addActionListener(this);//イベント待機 //*******************************************************# //オフスクリーンバッファ(以下バッファ)の作成 imgBuf = createImage(x_max, y_max);//バッファ生成 gBuf = imgBuf.getGraphics();//グラフィックコンテキスト(仮想的な画面)取得 //マウスイベントを受け取る addMouseListener(this); addMouseMotionListener(this); //オーディオクリップ取得 this.audio[0] = getAudioClip(getDocumentBase(), "./tama.wav"); this.audio[1] = getAudioClip(getDocumentBase(), "./burst.wav"); this.audio[2] = getAudioClip(getDocumentBase(), "./delete.wav"); this.audio[3] = getAudioClip(getDocumentBase(), "./return.wav"); //画像ファイル取得 this.img[0] = getImage(getDocumentBase(), "./houdai.gif");//砲台 this.img[1] = getImage(getDocumentBase(), "./gomi.gif");//ゴミ箱 this.img[2] = getImage(getDocumentBase(), "./gomi2.gif");//ゴミ箱 //*******************************************************# //アプレットパラメーター取得(サーバ情報、表示ファイル名、ページID) //※各種パラメータはサーバ側で可変生成することでアクセスIDごとに違う動画を再生 //*******************************************************# String id = getParameter("id");//ページID取得 String server = getParameter("server");//データ保存先サーバホスト名取得 String FILE = getParameter("FILE");//ファイル名取得 if (id == null)//ページID取得 { this.message = "パラメータ \"id\" が指定されていません。\n" + this.message; } else { this.message = "データID取得完了\n"+this.message; this.id = id;//ページID取得 } if (server == null)//サーバID取得 { this.message = "パラメータ \"server\" が指定されていません\n" + this.message; } else { this.message = "サーバホスト情報取得完了\n" + this.message; this.server = server;//サーバホスト名取得 } if (FILE == null)//動画ファイル取得 { this.message = "動画ファイル \"FILE\" が指定されていません\n" + this.message; } else { this.message = "動画ファイルPASS取得完了\n" + this.message; this.FILE = FILE;//サーバホスト名取得 } this.ta.setText(this.message);//メッセージフォーム更新(記入) //*******************************************************# //デバック用コメント(ネットワーク読み込みに変更する場合は消去) for (int i = 0; i < this.com_max; i++)//コメントデータ追加 { this.str[i] = i + this.Test_com; this.x_str[i] = this.x_max + 99;//初期値ターゲットX座標 this.y_str[i] = this.y_max + 99;//初期値ターゲットY座標 } //デバック用コメント--end-- //*******************************************************# //動画再生部分 implements ControllerListener、Player player = null; //*******************************************************# setLayout(null);//レイアウトを自由に設定する try { URL mediaURL = new URL(getDocumentBase(), this.FILE); //透過化するが、JMF独自のバグがあるため、有効化すると落ちるので今回は使わない。 //Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, new Boolean(true)); //Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true)); player = Manager.createPlayer(mediaURL); player.addControllerListener(this); } catch (Exception e) { System.err.println("Got exception " + e); } //*******************************************************# } //動画オブジェクト配置 public synchronized void controllerUpdate(ControllerEvent event) { if (event instanceof RealizeCompleteEvent) { Component comp; if ((comp = player.getVisualComponent()) != null) { add(comp); comp.setBounds((int)(this.x_max*2/5)-150,(int)((this.y_max-25)/2)-150, 300,300);//再生player画面 } if ((comp = player.getControlPanelComponent()) != null) { add(comp); comp.setBounds(0,this.y_max-25,(int)this.x_max*2/5, 25);//コントロールパネルサイズ } validate(); } } /* //背景描画 private void drawBackImage(Graphics g)//背景イメージ描画メソッド { g.setColor(new Color(0, 0,255));//背景描画文字カラー設定 g.setFont(new Font("serif", Font.BOLD, this.font_size)); g.drawString("背景に文字その1", 40, this.y_max / 2 + 16); g.drawString("背景に文字その2", 40, this.y_max / 2 + 36); g.drawString("背景に文字その3", 40, this.y_max / 2 + 56); } */ public void start()//アプレットが表示されると呼び出される { if (th == null) { th = new Thread(this);//スレッドの生成 th.start();//スレッドを開始させ、runメソッドを呼び出す } player.start();//動画再生用 } public void run()//実行中の処理 { //背景画像の作成 Image imgBack = createImage(this.x_max-(int)(this.x_max/5), this.y_max-25);//背景画像生成 Graphics gBack = imgBack.getGraphics();//グラフィックコンテキスト(仮想的な画面)取得 //drawBackImage(gBack);//背景画像描画(組立て)※必要なら描く gBack.dispose();//グラフィックコンテキスト破棄 int wait = this.x_max; while (th != null)//NULLでない限り回し続ける { gBuf.drawImage(imgBack, 0, 0, this);//背景画像をバッファに描画 gBuf.drawImage(this.img[0], (this.x_max*2/5-24),(this.y_max-(50+25)), this);//ふるぼっこイメージ描画 if (this.target_count == this.com_max)//ゴミ箱が空 { gBuf.drawImage(this.img[1], (this.x_max - (int)(this.x_max / 5) - 40), (this.y_max - 40 - 25), this);//ゴミ箱イメージ描画 } else//ゴミ箱がいっぱいの画像 { gBuf.drawImage(this.img[2], (this.x_max - (int)(this.x_max / 5) - 40), (this.y_max - 40 - 25), this);//ゴミ箱イメージ描画 } gBuf.setFont(new Font("serif", Font.BOLD, 12));//フォント・フォント指定 gBuf.drawString("クリック数:" + this.mouse_count, this.x_max*3/5, this.y_max - 30);//データ記入 gBuf.drawString("残りターゲット:" + this.target_count, this.x_max*2/5+48, this.y_max - 30);//データ記入 //*******************************************************# //文字を動かす処理(現在乱数制御、動画タイムラインとの連携が好ましい) //Random rand = new Random();//Randomクラスのインスタンス化 //int ran = (rand.nextInt(this.x_max) % (this.x_max - this.font_size)) + this.font_size;//40〜(500-40)までの乱数を 100回生成(要素数500-40個)※40から何個出すか //*******************************************************# wait++; for (int i = 0; i < this.com_max; i++)//表示件数分作成 { Random rand = new Random();//Randomクラスのインスタンス化 if (x_str[i] == (this.x_max+99) && wait > this.x_max)//画面外(描画領域内)の場合 { x_str[i] = this.x_max;//X座標配置(フォントサイズ分移動(オーバー)) y_str[i] = rand.nextInt(((this.y_max-25)-this.font_size)+this.font_size);//移動コメントy座標(フォントサイズ分ずらす) x_str[i] -= (int)(rand.nextFloat() * 7) * str[i].length();//移動速度 wait = this.x_max-(int)(rand.nextFloat() * 20) + 4; } else { x_str[i] -= (int)(rand.nextFloat() * 7) * str[i].length();//ターゲット移動 if (x_str[i] < -str[i].length()*this.font_size )//指定領域内になったら位置初期化 x_str[i] = this.x_max+99; gBuf.setFont(new Font("serif", Font.BOLD, this.font_size));//フォントサイズ gBuf.setColor(new Color(0xFF0000));//16進数文字色指定(配列より抽出する。0xff0000) gBuf.drawString(this.str[i],x_str[i], y_str[i]);//文字を動かす } } //*******************************************************# repaint();//画面の強制更新 try { Thread.sleep(50); //0.05秒間スリープ。これを忘れるとハングアップする } catch (InterruptedException e) { } } } //マウスイベント public void mousePressed(MouseEvent e) //コンポーネント上でマウスボタンが押されると呼び出される { AudioClip ac_tama = this.audio[0];//発射音 AudioClip ac_burst = this.audio[1];//爆発音 AudioClip ac_delete = this.audio[2];//一斉削除音 AudioClip ac_return = this.audio[3];//ゴミ箱復元音 int m_x = e.getX();//クリックX座標GET int m_y = e.getY();//クリックY座標GET ac_tama.play();//発射音声再生 this.mouse_count++;//マウスカウント //this.message = this.mouse_count + "回マウスクリックしました。\n" + this.message; //this.ta.setText(this.message);//メッセージフォーム更新 if(m_x >(this.x_max*4/5-35) && m_x < this.x_max*4/5 && m_y > this.y_max-60 && m_y < this.y_max-25) { //ゴミ箱をクリックした場合 //データをすべて元に戻す。 //デバック用コメント生成 ac_return.play();//ゴミ箱復元音再生 for (int i = 0; i < this.com_max; i++) { this.str[i] = i+this.Test_com; } this.target_count = this.com_max; this.message = "コメントをリサイクルしました。\n" + this.message; this.ta.setText(this.message);//メッセージフォーム更新 //デバック用コメント生成--end-- } else if(m_x > this.x_max*2/5-24 && m_x < this.x_max*2/5+24 && m_y > this.y_max-73 && m_y < this.y_max-25)//ふるぼっこをクリックした場合 { ac_delete.play();//一斉除去音声再生 //コメントデータ一斉削除 for (int i = 0; i < this.com_max; i++) { this.str[i] = "";//コメントデータ除去 } this.target_count = 0; this.message = "コメントを一斉削除しました。\n" + this.message; this.ta.setText(this.message);//メッセージフォーム更新 } else { for (int i = 0; i < this.com_max; i++) { if(this.target_count==0)//全部消した場合 { this.message = "コメントを全滅させました!\nMissionComplete!!\n" + this.message; this.ta.setText(this.message);//メッセージフォーム更新 break; } //マウスクリック位置があたり判定領域内の場合※コメントの長さが0以上 else if (this.str[i].length() > 0 && this.x_str[i] > m_x - this.font_size && this.x_str[i] < m_x + (this.str[i].length() * this.font_size) && this.y_str[i] > m_y - this.font_size && this.y_str[i] < m_y + this.font_size) { ac_burst.play();//爆発音声再生 this.str[i] = "";//空白を挿入し、データを除去 this.target_count--;//ターゲット数 } else { } } } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseDragged(MouseEvent e) { } public void mouseMoved(MouseEvent e) { } //マウス処理終了 //テキストフィールドコメント書き込み処理 public void actionPerformed(ActionEvent ev)//ボタンが押されたとき { this.message = this.tf.getText()+"\n" + this.message;//記入コメントをメッセージに表示 this.ta.setText(this.message);//メッセージフォーム更新(記入) if (this.com_counter >= this.com_max)//40以上ならば(※コメントは[0]~[39]) { this.com_counter = 0;//0を加算 if (this.str[this.com_counter].length() < 1)//文字の長さが1未満ならば { this.str[this.com_counter] = this.tf.getText();//メッセージを代入する this.com_counter++; this.target_count++;//ターゲット数加算 } else { this.str[this.com_counter] = this.tf.getText();//メッセージを代入する } } else//最大範囲内 { if (this.str[this.com_counter].length() < 1)//文字の長さが1未満ならば { this.str[this.com_counter] = this.tf.getText();//メッセージを代入する this.com_counter++; this.target_count++;//ターゲット数加算 } else { this.str[this.com_counter] = this.tf.getText();//メッセージを代入する } } this.com_counter++;//コメントカウント加算 this.tf.setText("");//テキストフィールドを消去 } public void update(Graphics g)//オーバーライドして最低限のことだけをする { paint(g);//repaint()でupdateが自動的に呼ばれるため、オーバーライドする必要がある。 } public void paint(Graphics g) { g.drawImage(imgBuf, 0, 0, this);//バッファを画面に描画 } public void stop() //アプレットが画面から消えると呼び出される { if (th != null) th = null; //動画停止 player.stop(); player.deallocate(); } public void destroy() { player.close(); } }