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

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

ただいまの
回答率

90.47%

  • Java

    14089questions

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

  • Android

    6628questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 816

daichanman123

score 26

コード
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つの位置を描画すればいいと思うのですが、プログラムをどのように書いたらいいのかがわかりません。
この考えが間違っているかもしれませんが・・

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

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

Thread hanabi1 =new Thread(new Runnable(){略});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/12 09:00 編集

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

    キャンセル

  • 2016/04/12 09:36

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

    キャンセル

  • 2016/04/12 09:42

    そうですね!
    了解です!

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

    キャンセル

  • 2016/04/12 11:55

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

    キャンセル

  • 2016/04/12 14:03

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

    キャンセル

  • 2016/04/12 14:43

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

    キャンセル

  • 2016/04/12 16:40

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

    キャンセル

  • 2016/04/12 17:04

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

    もし、Hanabiが動きを管理するクラスにしたいのであればRunnableをimplementsする必要があります。

    キャンセル

  • 2016/04/12 17:39

    そうなんですね!

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

    キャンセル

  • 2016/04/12 18:03

    本当に設計方針次第なんですよ。

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

    私ならHanabiはデータの保持とデータの定期更新をするクラスにし、SampleViewは定期的にHanabiのデータを読み取り、その値通りに描画するクラスにするかなと思います。

    キャンセル

  • 2016/04/13 10:48

    人それぞれ作り方が違うってことですね!
    私のプログラムは根本から間違ってそうですね笑

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

    キャンセル

  • 2016/04/13 11:19

    作り方はいろいろあるけれど良い設計と悪い設計に分かれるとおもいます。

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

    キャンセル

  • 2016/04/13 13:59

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

    キャンセル

  • 2016/04/13 14:14

    long diffTime = time - t;
    y = 1000 + (V0y* diffTime - G*diffTime*diffTime/2);

    とかじゃないですかね

    キャンセル

  • 2016/04/13 14:40

    ですね。

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

    キャンセル

  • 2016/04/13 14:45

    t=0ならできますね

    キャンセル

  • 2016/04/13 14:59

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

    キャンセル

checkベストアンサー

0

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/12 08:48

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

    キャンセル

  • 2016/04/12 10:45

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

    キャンセル

  • 2016/04/12 14:06

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

    キャンセル

  • 2016/04/12 17:03

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

    キャンセル

  • 2016/04/12 17: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);
    }
    }
    こういうことでいいのでしょうか?

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Java

    14089questions

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

  • Android

    6628questions

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