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

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

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

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

Android

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

Q&A

解決済

3回答

2385閲覧

花火を時間差であげる方法

daichanman123

総合スコア32

Java

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

Android

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

0グッド

0クリップ

投稿2016/04/11 08:30

コード public class MainActivity extends Activity implements Runnable{ Handler mHandler; Thread thread; FrameLayout frameLayout; SampleView sv; ArrayList<Hanabi> list = new ArrayList<Hanabi>(); Hanabi hanabi1 = new Hanabi(150.0); Hanabi hanabi2 = new Hanabi(120.0); int time = 0; double mul = 0.15; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); frameLayout = new FrameLayout(this); setContentView(frameLayout); sv = new SampleView(this); list.add(hanabi1); list.add(hanabi2); sv.setHanabi(list); frameLayout.addView(sv); mHandler = new Handler(); thread = new Thread(this); thread.start(); } @Override public void run(){ hanabi1.setX(); hanabi2.setX(); for(time = 0; time < 1000; time++){ try{ Thread.sleep(50); } catch(InterruptedException e){ } hanabi1.setY(time * mul); hanabi2.setY(time * mul); mHandler.post(new Runnable(){ @Override public void run(){ sv.invalidate(); } }); } } }
コード public class SampleView extends View{ Paint paint = new Paint(); ArrayList<Hanabi> hanabi; public SampleView(Context context) { super(context); } public void setHanabi(ArrayList<Hanabi> hanabi){ this.hanabi = hanabi; } protected void onDraw(Canvas canvas){ paint.setColor(Color.RED); paint.setStrokeWidth(10); canvas.drawPoint(hanabi.get(0).getX(), hanabi.get(0).getY(), paint); canvas.drawPoint(hanabi.get(1).getX(), hanabi.get(1).getY(), paint); } }
コード public class Hanabi{ int x; int y; double V0x = 0.0; double V0y; double Vx = 0.0; double Vy; double G = 9.8*2; /*Hanabiクラスのコンストラクタ*/ public Hanabi(double V0y){ this.V0y = V0y; } public void setX(){ this.x = (int)(Math.random()*700) + 50; } public void setY(double time){ this.y = (int)(800 - (V0y*time - G*time*time/2)); } public void setVy(double time){ this.Vy = V0y - G*time; } public int getX(){ return this.x; } public int getY(){ return this.y; } public double getVy(){ return this.Vy; } }

前回の続きで同じような質問になりますがよろしくお願いします!
上のプログラムは花火の打ちあがりの部分だけのプログラムです。

Hanabiクラスを作り、xやyなどを持たせて、
Hanabi hanabi1 = new Hanabi(150.0);
Hanabi hanabi2 = new Hanabi(120.0);
のように2つインスタンス化?しました。
今、MainActivityクラスのrunメソッドで
hanabi1.setX();
hanabi2.setX();
hanabi1.setY(time * mul);
hanabi2.setY(time * mul);
のように2つ(hanabi1とhanabi2)を同じところに書いているのですが、これだと実行すると同時に花火が上がってしまいます。
hanabi2.setY(time * mul);のtimeを(time-10)*mulのように書き換えると、時間差で花火を上げることができたのですが、これだとあとで面倒なことになるので他の方法でしたいと思っています。
hanabi1に対してrunメソッドの動作を行って、t秒後にhanabi2に対してもrunメソッドの動作を行って、そのときの2つの位置を描画すればいいと思うのですが、プログラムをどのように書いたらいいのかがわかりません。
この考えが間違っているかもしれませんが・・

私のこの考えはどうでもいいんですけど、
花火を時間をあけて打ち上げるにはどのように修正したらいいのでしょうか?
よろしくお願いします。

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

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

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

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

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

guest

回答3

0

花火1つにつき1つスレッドを用意したらどうでしょう。

Java

1Thread hanabi1 =new Thread(new Runnable(){}); 2

投稿2016/04/11 09:00

yona

総合スコア18155

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

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

daichanman123

2016/04/12 00:39 編集

回答ありがとうございます。 例えば、花火を100発あげたい場合は Thread hanabi1 =new Thread(new Runnable(){略}); この記述を100回書くということでしょうか?
yona

2016/04/12 00:36

そこは作り方次第です。 100回書くこともできるし、for文を使う方がいいですが。
daichanman123

2016/04/12 00:42

そうですね! 了解です! onCreateメソッドの中でThread hanabi1 =new Thread(new Runnable(){略});を書いたのですが、「voidからThreadには変換できません」というエラーが出ました。 new Thread(new Runnable(){略});だとエラーが出ないのですが、これだと、どの花火に対するスレッドなのかわからなくなると思います。 Thread hanabi1 =new Thread(new Runnable(){略}); これはどこに書けばいいのでしょうか?
yona

2016/04/12 02:55

onCreateの中に書けばいいですよ。 下記の書き方の方が正しいですね。 ```Java Thread hanabi1 =new Thread(){ @override run(){} }; ```
daichanman123

2016/04/12 05:03

回答ありがとうです! 花火1つ1つにスレッド作ったのですが、結局時間をずらすのはどこでどのように処理したらいいのでしょうか?
yona

2016/04/12 05:43

今の段階では各花火の描画がバラバラに実行される状態になっています。 しかし、スレッドの実行タイミングは同じなため同時に更新されてしまいます。 この状態で花火の時間は下記の2つの要素で管理されると思われます。 ・初回描画 ・描画間隔 この2つの時間を格納するフィールド変数をHanabiに追加すると下記のようにコードを書くことが出来ます。 run(){ try{ Thread.sleep(初回の描画); }catch(InterruptedException e){ } for(;;){ 更新処理 try{ Thread.sleep(描画間隔); }catch(InterruptedException e){ } } } また、PineMatsuさんが言っているように上記の処理全てをHanabiに入れた方が様々な面で優れています。 混乱しないように少しずつリファクタリングしていった方が良いでしょう。
daichanman123

2016/04/12 07:40

回答ありがとうございます。 今Hanabiクラスはセッターやゲッターだけになっていますが、そこにこのrunメソッドを加えるのでしょうか?
yona

2016/04/12 08:04

今、Hanabiはデータを持っているだけのクラスです。動作もHanabi内に技術した方が良いと判断するならrunメソッドはHanabiの中に書く必要があります。 そこは方針次第ですね。 もし、Hanabiが動きを管理するクラスにしたいのであればRunnableをimplementsする必要があります。
daichanman123

2016/04/12 08:39

そうなんですね! ですが先ほど、 上記の処理全てをHanabiに入れた方が様々な面で優れています。 とおっしゃっているので、一般的(オブジェクト指向的?)にはHanabiクラスで動作も書いたほうがいいってことですよね?
yona

2016/04/12 09:03

本当に設計方針次第なんですよ。 Hanabiはあくまでもデータを保持するだけのクラス、描画はSampleViewがやるのでスレッドの処理記述はSampleViewに書く。 一方でHanabiはデータとその更新を行うクラスなのでHanabiの中で更新を行い、SampleViewでその値を読み取って画面に描画する。 どちらも正しいと感じるし、どちらも正しくないとも感じますよね。 ここは方針を決めて、あとはそれに従うしかないとおもいます。 私ならHanabiはデータの保持とデータの定期更新をするクラスにし、SampleViewは定期的にHanabiのデータを読み取り、その値通りに描画するクラスにするかなと思います。
daichanman123

2016/04/13 01:48

人それぞれ作り方が違うってことですね! 私のプログラムは根本から間違ってそうですね笑 ・MainActivityクラスは単にプログラムを実行するだけのクラス ・Hanabiクラスは花火のデータ保持とデータの更新 ・SampleViewクラスは描画のみのクラス という感じですかね? Hanabiクラスですが、yanoさんの場合、花火の座標と速度は、配列にしてfor文で時間ごとの値を格納するんですかね? y[time] = (800 - (V0y*time - G*time*time/2));
yona

2016/04/13 02:19

作り方はいろいろあるけれど良い設計と悪い設計に分かれるとおもいます。 配列では作らないとおもいます。 Hanabiクラスに打ち上げ開始時間をフィールドに持たせ、updateY(long currentTime)メソッドを作り、打ち上げ開始時間と現在時刻との差分をとって高さを計算すると思います。
daichanman123

2016/04/13 04:59

t = 0; 打ち上げ開始時間 public void Y(int time){ y = (1000 - (V0y*time - G*time*time/2)); } V0y : 初速度、G : 重力加速度、 1000は最初の打ち上げる位置のy座標 こういう感じで現時時刻timeのときのy座標を出すということですか?
yona

2016/04/13 05:14

long diffTime = time - t; y = 1000 + (V0y* diffTime - G*diffTime*diffTime/2); とかじゃないですかね
daichanman123

2016/04/13 05:40

ですね。 開始直後に花火を打ち上げるとするなら、打ち上げ開始時間t=0と考えて long diffTime = time; とできますよね?
yona

2016/04/13 05:45

t=0ならできますね
daichanman123

2016/04/13 05:59

ありがとうございます。 ということはHanabiクラスでは現在時間timeのときの座標や速度を持たせるということですかね?
guest

0

ベストアンサー

今の状態からなら、各Hanabiに打ち上げ時刻を設定するのが簡単です。

hanabi2.setY(time * mul);のtimeを(time-10)*mulのように書き換えると、時間差で
花火を上げることができたのですが、これだとあとで面倒なことになるので
他の方法でしたいと思っています。

この方法ですね。10=打ち上げ時刻だろうと思います。
これをHanabiにsetStartTime(10)のような感じで与えて(setHanabiみたいな感じです)、
getStartTime()のような方法で取得できるようにすると以下のようにできます。

Java

1hanabi1.setY((time - hanabi1.getStartTime()) * mul); 2hanabi2.setY((time - hanabi2.getStartTime()) * mul);

setYに負の値が与えられることになるので、内部でガードした方が良いでしょう。
この方法の弱点としては、最初に打ち上げ時刻が決定している必要があるというところです。
目指す場所(プログラムの仕様)によっては、プログラムの構造を見直したほうが良いです。
この場合、例えばPineMatsuさんのような方法を検討することになると思います。

投稿2016/04/11 09:03

編集2016/04/13 07:16
tnd-.-b

総合スコア247

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

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

0

具体的なプログラミングではなくて考え方だけですが、打ち上げの軌跡を決める処理をHanabiクラスの中に持って行ったほうがいいと思います。
クラスの外部からは点火だけ行い、点火されたら軌跡の設定はHanabiクラスの中で行うのです。
外部からは、軌跡を描かせるために一定周期で軌跡を描くメソッドを呼び出します。
時間差をつける場合は、時間差のパラメータをHanabiクラスに持たせ、その時間が経過するまでは最初に位置に留まるようにします。
実際の花火も、花火師が点火した後は花火任せのはずです。それと同じように考えたらどうでしょうか?

追記:
折角Hanabi をクラスオブジェクトにしているので、花火をもっとオブジェクトとして考えましょう。つまり、点火は自分ではできないが、点火された後は自分で設定されたパラメータ動くようにするわけです。
他の方が書かれているようにスレッドとして動かしてもいいかもしれません。(スレッド起動が点火になるわけです)
そうすれば、個々の花火に色々な性格を持たせることができます。打ち上げ速度やどこまで高く上がるかなどなど。
今のように位置を外部で決める形だと、花火の種類など全て外部で決める必要が出てきます。(どこで中の小玉が弾けだすかなど)

投稿2016/04/11 08:58

編集2016/04/11 09:14
PineMatsu

総合スコア3579

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

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

daichanman123

2016/04/11 23:48

回答ありがとうございます。 「打ち上げの軌跡を決める処理をHanabiクラスの中に持って行ったほうがいい」とのことですが、Hanabiクラスでx,yを持たせているのですが、私的にはこれで軌跡を表しています。 このx,yではダメなのでしょうか?
PineMatsu

2016/04/12 01:45

ダメではないですが、私が提案しているのは、軌跡をHanabiクラスの中で決定してやるということです。現在の位置を保持することは当然必要です。ある時間後の位置をクラスの外部からではなく、クラスの内部で決定するんです。垂直に打ち上がるものや斜めに打ち上がるものなどなど、クラスの中で決めてやるほうがオブジェクトっぽくなります。 別に言い方をすれば、リモコンで花火の位置を制御するのではなく、自律的に花火を制御するということです。
daichanman123

2016/04/12 05:06

Hanabiクラスで軌跡を決定というのはMainActivityクラスの for(time = 0; time < 1000; time++){ try{ Thread.sleep(50); } catch(InterruptedException e){ } をHanabiクラスに移して毎時間ごとの位置を全て設定すればいいのでしょうか?
PineMatsu

2016/04/12 08:03

ざっくり言うとそういうことになります。 軌跡を描く方法はいくつか考えられると思います。直線の式を組み込んで時間を引数に位置を決めたり、ポイントを幾つか保持しておいて各ポイントを直線補間するなどです。 そういったXとYの座標を決める処理をHanabiクラスに組み込んでしまうということです。 花火は時間経過とともに位置が変わるはずなので、時間経過に伴って位置が変わるような処理をHanabiクラスに組み込むわけです。 まあ、実際の花火の動きに近づけるには、重力に逆らって打ち上げるわけなので、時間経過とともに上がる速度は落ちていくはずです。(こういう細かい処理は後からHanabiクラスを組み替えたりすればできると思うので、まずはそういうのを無視して一定時間で一定高さまで単位時間毎に移動するような処理でいいと思います。) イメージ的には、MainActivityが花火師の役割になるわけです。 そうやって実際の花火の各機能をオブジェクトとしてプログラムしていけば、複雑なものも単機能の集まりとして記述することができるようになるはずです。 うまく作れば、花火シミュレータ的なものを作るところまで行けると思います。
daichanman123

2016/04/12 08:29

回答ありがとうございます。 時間経過とともに上がる速度は落ちていくのはできています! MainActivityで花火を打ち上げるスタートの処理だけしてあとはHanabiクラスで処理するということですかね! 今Hanabiクラスはセッターやゲッターである時間のy座標や速度を設定していますが、全ての時間のy座標や速度を設定するということですよね? public void setY(){     for(int time = 0; time > 1000; time++){         try{             Thread.sleep(50); } catch(InterruptedException e){ } double t = time * 0.15; this.y[time] = (float) (800 - (V0y*t - G*t*t/2)); } } public void setVy(){ for(int time = 0; time > 1000; time++){ try{ Thread.sleep(50); } catch(InterruptedException e){ } double t = time * 0.15; this.Vy[time] = (float) (V0y - G*t); } } こういうことでいいのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問