質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

1回答

2312閲覧

花火プログラム

nakamura-

総合スコア48

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2016/04/25 05:53

コード public class MainActivity extends Activity{ FrameLayout frameLayout; CanvasView canvasview; int hanabiNum = 5; //花火の数 Hanabi hanabi[] = new Hanabi[hanabiNum]; //Hanabiクラスのインスタンスの配列 @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); frameLayout = new FrameLayout(this); frameLayout.setBackgroundColor(Color.BLACK); setContentView(frameLayout); canvasview = new CanvasView(this); frameLayout.addView(canvasview); for(int i = 0; i < hanabiNum; i++){ hanabi[i] = new Hanabi(((Math.random()*600) + 50), //Hanabiのインスタンス化 ((Math.random()*50) + 150), (int)((Math.random()*10000) + 500), (int)(Math.random()*255), (int)(Math.random()*255), (int)(Math.random()*255)); hanabi[i].setCanvasView(canvasview); hanabi[i].start(); } canvasview.setNumAndHanabi(hanabiNum, hanabi); } }
コード public class CanvasView extends View{ int hanabiNum; Hanabi hanabi[] = new Hanabi[hanabiNum]; /*CanvasViewクラスのコンストラクタ*/ public CanvasView(Context context){ super(context); } public void setNumAndHanabi(int hanabiNum, Hanabi hanabi[]){ this.hanabiNum = hanabiNum; this.hanabi = hanabi; } /*描画メソッド*/ protected void onDraw(Canvas canvas){ for(int i = 0; i < hanabiNum; i++){ canvas.drawPoint((float)hanabi[i].X, (float)hanabi[i].Y, hanabi[i].paint); //paintで座標(x,y)点描画 for(int j = 0; j < 1000; j++){ canvas.drawPoint((float)hanabi[i].X2[j], (float)hanabi[i].Y2[j], hanabi[i].paint); //点描画 } } } }
コード public class Hanabi extends Thread{ private Handler handler = new Handler(); Paint paint = new Paint(); CanvasView cv; double G = 9.8*2; //重力加速度 double t; //経過時間(0.1秒毎) int time; //発射時刻 int red; //赤色成分 int green; //緑色成分 int blue; //青色成分 /*打ち上がり段階で使う定数*/ double X0; //初期のX座標 double Y0 = 1000; //初期のY座標(1000で固定) double X; //時刻t時のX座標 double Y; //時刻t時のY座標 double V0x = 0; //初速度のX成分(0で固定) double V0y; //初速度のY成分 double Vx; //時刻t時の速度のX成分 double Vy; //時刻t時の速度のY成分 /*爆発段階で使う定数*/ int hanabiball = 1000; //花火の拡散弾数 double angle[] = new double[hanabiball]; //発射する角度 double X02[] = new double[hanabiball]; //初期のX座標 double Y02[] = new double[hanabiball]; //初期のY座標 double X2[] = new double[hanabiball]; //時刻t時のX座標 double Y2[] = new double[hanabiball]; //時刻t時のY座標 double V02[] = new double[hanabiball]; //V0x2とV0y2の合成 double V0x2[] = new double[hanabiball]; //初速度のX成分 double V0y2[] = new double[hanabiball]; //初速度のY成分 double Vx2[] = new double[hanabiball]; //時刻t時の速度のX成分 double Vy2[] = new double[hanabiball]; //時刻t時の速度のY成分 /*Hanabiクラスのコンストラクタ*/ public Hanabi(double X0, double V0y, int time, int red, int green, int blue){ this.time = time; this.red = red; this.green = green; this.blue = blue; this.X0 = X0; this.V0y = V0y; X = X0; Vx = V0x; for(int i = 0; i < hanabiball; i++){ angle[i] = Math.random()*360; //拡散弾のアングル設定(0~360°) V02[i] = Math.random()*50; //拡散弾の初速度の設定(0~50) V0x2[i] = V02[i]*Math.cos(angle[i]*(Math.PI/180)); //V02のX成分 V0y2[i] = V02[i]*Math.sin(angle[i]*(Math.PI/180)); //V02のY成分 } } public void run(){ Y = 5000; //最初枠外に置いて隠しておく Arrays.fill(Y2, 5000); //Yと配列Y2の全てに5000代入 try{ Thread.sleep(time); //発射する時間を設定 } catch(InterruptedException e){ } /*打ち上がり段階*/ for(int T = 0; T < 1000 ; T++){ t = T * 0.1; Vy = (V0y - G*t); Y = (Y0 - (V0y*t - G*t*t/2)); try{ Thread.sleep(50); //0.05秒間隔 } catch(InterruptedException e){ } paint.setStrokeWidth(5); paint.setColor(Color.WHITE); viewStart(); if(Vy < 0.2){ break; } } /*爆発段階*/ Arrays.fill(X02, X); Arrays.fill(Y02, Y); for(int T = 0; T < 30; T++){ t = T * 0.1; for(int i = 0; i < hanabiball; i++){ Vx2[i] = V0x2[i]; Vy2[i] = (V0y2[i] - G*t); X2[i] = (X02[i] + (Vx2[i]*t)); Y2[i] = (Y02[i] - (V0y2[i]*t - G*t*t/2)); } try{ Thread.sleep(50); //0.05秒間隔 } catch(InterruptedException e){ } paint.setStrokeWidth(2); paint.setColor(Color.rgb(red, green, blue)); paint.setAlpha(240-(8*T)); viewStart(); } } public void viewStart(){ handler.post(new Runnable() { @Override public void run(){ cv.invalidate(); //onDrawメソッド呼び出し } }); } public void setCanvasView(CanvasView cv) { this.cv = cv; } }

上のプログラムは花火のプログラムで一応完成しました。
MainActivityクラスの花火の打ち上げる数int hanabiNumが1発の場合は綺麗な花火になっているのですが10発や20発と増やしていくと描画の点と点の間隔が広がっていき、綺麗な花火を描けません。
Hanabiクラスに点を描画する座標や時間を書いてインスタンスごとに持たしているのに、このようになる理由がわかりません。
この原因はなぜなのでしょうか?
また改善方法も教えていただきたいです。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yona

2016/04/25 07:32

画像を追加することはできますか?
nakamura-

2016/04/25 07:44

花火が1発だけの場合と10発の場合の画像ということですよね? 画像を載せることはできますが、動画でないと画像では違いがわかりにくいと思います。 言葉で言うと花火1発の方はぬるぬる動いて、花火10発はかくかくに動きます。
yona

2016/04/25 08:08

「描画の点と点の間隔」の意味がわかりません。 時間的な描画間隔が広がっているのか、点と点の間の距離が広がっているのかがわかりません。 「花火1発の方はぬるぬる動いて、花火10発はかくかくに動きます。」からすると描画間隔ですか?
nakamura-

2016/04/25 08:13

すみません。 点と点の距離です!
guest

回答1

0

ベストアンサー

今の状況だと各スレッドから再描画依頼が届くので、各HanabiクラスのviewStartメソッドを廃止し、CanvasViewに定期的にinvalidを実施するスレッドを追加してみてはどうでしょうか?

投稿2016/04/25 08:57

yona

総合スコア18155

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakamura-

2016/04/26 02:06

回答ありがとうございます^^ 「各スレッドから再描画依頼が届くので」とありますが、これは何かまずいのでしょうか? また「CanvasViewに定期的にinvalidを実施するスレッドを追加」ですが、これは必ずCanvasViewクラスでないといけないということはありますか? よろしくお願いします!
yona

2016/04/26 03:07

例えば、あなたが20人に囲まれながら絵を描いていたとして、周囲の人が口々に「ここに、こんな線を描いて」と言ってきたら混乱しますよね?だいたいこれと同じようなことが起きていると考えられます。 そこで、周囲の人はメモに描画したいものについての設定値を書いておき、あなたが自分のタイミングで、メモの設定値から描画すると混乱は起きにくいですよね。 上の例えでは周りの20人はHanabiに存在するスレッドであり、あなたは「CanvasView」または「MainActivity」に存在するスレッドになります。
nakamura-

2016/04/26 04:21 編集

わかりやすい解説ありがとうございます! MainActivityクラスに定期的にinvalidを実施するスレッドを追加しました! コード public class MainActivity extends Activity implements Runnable { Handler handler = new Handler(); Thread thread; //以下略 @Override protected void onCreate(Bundle savedInstanceState){ //省略 canvasview.setNumAndHanabi(hanabiNum, hanabi); thread = new Thread(this); thread.start(); } public void run(){ handler.post(new Runnable() { @Override public void run(){ canvasview.invalidate(); //onDrawメソッド呼び出し handler.postDelayed(this, 1); } }); } このように書き換えたのですが結果が変わらず、描画の点と点があいたままでした。 「定期的にinvalidを実施するスレッドを追加」とはどのように書いたらいいのでしょうか?
yona

2016/04/26 05:00 編集

Hanabi側のスレッドは削除しましたか? また、現状では1ms間隔で描画更新をしているのでとりあえず500等の大きい値に変更して見てください。
nakamura-

2016/04/26 05:18

はい! ちゃんと消しましたよ。 500で実行しても描画時間の間隔が長いので余計に点と点の間隔があきました! 私の追加したプログラムではダメなんですかね?
yona

2016/04/26 05:29

点と点の間隔という表現ではわからないと言いましたよね? 具体的にどの点とどの点ですか? 前に表示した点と今表示されている点ですか?
yona

2016/04/26 05:34

CanvasViewのonDrawの処理が怪しいです。なぜ二重ループになっているのでしょうか?
nakamura-

2016/04/26 06:03

すみません。 今表示されている点と次に表示される点の距離の長さも時間間隔もあきました。 ・花火1発だけのとき 最初の点y=1000 次の点y=980 その次の点y=960 この点と点の間の時間0.1秒 ・花火10発のとき 最初の点y=1000 次の点y=950 その次の点y=900 この点と点の間の時間0.5秒 見たいな感じです 二重ループは打ち上がる花火の数につき、爆発のときの拡散弾1000個を描画しています。 確かに打ち上がっているときも拡散弾のほうも描画されているので無駄な処理ではありますね。 これが処理を重たくしているんですかね?
yona

2016/04/26 06:36

10*1000回描画処理をしているので、なかなかな計算量になりそうです。 一度コメントアウトしてみるとどうなりますか?
nakamura-

2016/04/26 08:53

コメントアウトしたところ普通に動きました。 yonaさんの言うとおりここが原因みたいでした! 1000のところを200にすると花火も普通に動きました。 10*1000回ってそんなに多いんですね笑 ありがとうございました!
yona

2016/04/26 09:54

一秒間に24回以上描画しない人間の目が違和感を感じるので、いろいろなオーバーヘッドを考えてもonDrawの中はなるべく重い処理は書かないほうがいいですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問