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

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

ただいまの
回答率

90.48%

  • Java

    14119questions

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

花火プログラム スレッド

解決済

回答 1

投稿

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

nakamura-

score 40

コード
public class MainActivity extends Activity{

    private FrameLayout frameLayout;
    CanvasView canvasview;
    Hanabi hanabi1 = new Hanabi(((Math.random()*600) + 50),
                    ((Math.random()*50) + 150),
                    2000);
    Hanabi hanabi2 = new Hanabi(((Math.random()*600) + 50),
                    ((Math.random()*50) + 150),
                    5000);


    @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);

        /*hanabi1について*/
        canvasview.setHanabi1(hanabi1);
        hanabi1.setCanvasView(canvasview);
        hanabi1.start();

        /*hanabi2について*/
        /*canvasview.setHanabi2(hanabi2);
        hanabi2.setCanvasView(canvasview);
        hanabi2.start();*/
    }
}
コード
public class CanvasView extends View{

    Paint paint = new Paint();
    Hanabi hanabi1;
    Hanabi hanabi2;
    int select = 1;        //描画切り替え


    public CanvasView(Context context){
        super(context);
    }

    public void setHanabi1(Hanabi hanabi) {
        this.hanabi1 = hanabi;
    }
    public void setHanabi2(Hanabi hanabi) {
        this.hanabi2 = hanabi;
    }


    protected void onDraw(Canvas canvas){
        if(select == 1){
            paint.setStrokeWidth(5);
            canvas.drawPoint((float)hanabi1.X, (float)hanabi1.Y, paint);
            //canvas.drawPoint((float)hanabi2.X, (float)hanabi2.Y, paint);
        }

        else if(select == 2){
            paint.setStrokeWidth(2);
            for(int i = 0; i < 1000; i++){
                canvas.drawPoint((float)hanabi1.X2[i], (float)hanabi1.Y2[i], paint);
            }
            /*for(int i = 0; i < 1000; i++){
                canvas.drawPoint((float)hanabi2.X2[i], (float)hanabi2.Y2[i], paint);
            }*/
        }
    }
}
コード
public class Hanabi extends Thread{

    private Handler handler = new Handler();
    CanvasView canvasview;

    double G = 9.8*2;        //重力加速度
    double t;                //経過時間(0.1秒毎)
    int time;                //発射時刻

    /*打ち上がり段階で使う定数*/
    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){

        /*共通*/
        this.time = time;

        /*打ち上がり段階*/
        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;        
            V0x2[i] = V02[i]*Math.cos(angle[i]*(Math.PI/180));
            V0y2[i] = V02[i]*Math.sin(angle[i]*(Math.PI/180));
        }
    }

    /*runメソッド*/
    public void run(){
        Y = 5000;                            //最初枠外に置いて隠しておく

        try{
            Thread.sleep(time);                //発射する時間を設定
        }
        catch(InterruptedException e){
        }

        /*打ち上がり段階*/
        for(int T = 0; T < 1000 ; T++){
            t = T * 0.15;

            Vy = (V0y - G*t);
            Y = (Y0 - (V0y*t - G*t*t/2));

            try{
                Thread.sleep(50);
            }
            catch(InterruptedException e){
            }

            canvasview.paint.setColor(Color.WHITE);
            canvasview.paint.setAlpha(240-(3*T));

            viewStart();

            if(Vy < 0.2){
                canvasview.select = 2;
                break;
            }
        }

        /*爆発段階*/
        Arrays.fill(X02, X);
        Arrays.fill(Y02, Y);
        for(int T = 0; T < 30; T++){
            t = T * 0.15;

            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);
            }
            catch(InterruptedException e){
            }

            canvasview.paint.setColor(Color.RED);
            canvasview.paint.setAlpha(240-(8*T));

            viewStart();
        }
    }


    public void viewStart(){
        handler.post(new Runnable() {
            @Override
            public void run(){
                canvasview.invalidate();
            }
        });
    }


    public void setCanvasView(CanvasView canvasview) {
        this.canvasview = canvasview;
    }
}

上のプログラムは花火を描いたのもです。
インスタンス?hanabi1とhanabi2を作り花火が2発だけ上がるようになっています。

今上のプログラムはhanabi2の方をコメントアウトしているのでhanabi1しか打ちあがりません。
この状態で実行するとHanabiクラスに書かれている通り、打ち上がり段階は白色でだんだん透明になっていき、爆発段階も赤色でだんだん透明になっていきます。
色も打ち上がり段階と爆発段階で白と赤ではっきり分かれています。
「canvasview.paint.setColor(Color.WHITE);
canvasview.paint.setAlpha(240-(3*T));

canvasview.paint.setColor(Color.RED);
canvasview.paint.setAlpha(240-(8*T));の部分」

次にコメントアウトを戻してhanabi2を追加して実行すると、花火自体はきちんと描画されているのですが、爆発するときに白色と赤色が混ざったり、透明になっていくのも急に明るくなったり変な動きをします。

調べると2つのスレッドで同じオブジェクトを使用したらダメらしく、今回CanvasView canvasview;同じオブジェクトを使用しているから変な動きをしたのかと思ったのですが、原因はこれなのでしょうか?
またどのように対処したらいいのでしょうか?
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

原因は、その通りです。

対処としては、
CanvasViewが持っているPaintの変数をHanabiクラスに持たせて、
描画時にそれぞれのインスタンスにあるPaintの変数を使用したらいいだけです。

どこにPaint変数を持たせるかだけ、

public class CanvasView extends View{

    // こいつは、花火の描画に使わない
    // Paint paint = new Paint();
    Hanabi hanabi1;
    Hanabi hanabi2;
    int select = 1;        //描画切り替え

// 省略
}
public class Hanabi extends Thread{

    private Handler handler = new Handler();
    CanvasView canvasview;

    // インスタンスごとに管理する!!
    Paint paint = new Paint();

// 省略
}


処理のほうは自分で適当に修正してください。

ほとんどの変数が、
パッケージプライベートになっているのが気になりますが、
この話はまた別の機会でしょうかね・・・

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/22 13:19

    回答ありがとうございます。
    インスタンスごとにPaintを管理すればよかったんですね!
    ですが2つのスレッドは同じCanvasViewクラスのオブジェクトを使っていると思うのですが、CanvasViewクラスについては何もしなくていいのでしょうか?
    それとも、CanvasViewクラスの中のものでHanabiクラスで使われているのがPaintだけだからPaintをHanabiクラスに移してインスタンスごとに管理させたのですか?

    パッケージプライベートになっているのが気になりますが、 とありますが変数なにかまずかったですかね?

    キャンセル

  • 2016/04/22 13:38

    変数[int select]で打ち上げ時と爆発時を分けていますが、これも、hanabi1とhanabi2で異なる値が必要ですよね。(hanabi1爆破中に、hanabi2打ち上げとか)
    これもそれぞれのインスタンスで管理した方がいいです。

    キャンセル

  • 2016/04/22 15:58

    >CanvasViewクラスについては何もしなくていいのでしょうか?
    →何もしなくても大丈夫です。
    CanvasViewのpaintを操作している処理を除いてしまえば、
    後は、handler使って全部UIスレッドに処理をさせている
    invalidate()の実行に使用しているだけになるため、
    2つのスレッドから、という問題は解決できています。

    >CanvasViewクラスの中のものでHanabiクラスで使われているのがPaintだけだからPaintをHanabiクラスに移してインスタンスごとに管理させたのですか?
    →YES?
    (実際あんまり考えてなかったので何ともいえません、そういった理由もありますし、
    そもそもHanabiクラスで色を管理したほうがよさげだなと思ってたのもあります。
    言うならば、このほうがしっくりきたって感じです。)

    パッケージプライベートの件については、「カプセル化」で検索してみてください。

    キャンセル

  • 2016/04/25 11:13

    dsuzuki さん
    そうですね!
    int selectもインスタンスで管理したいと思います!
    ありがとうございます。


    abs123
    回答ありがとうございます^^
    確かに色はHanabiクラスで管理した方がいいかもですね!
    ありがとうございました!
    またカプセル化勉強します。





    キャンセル

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

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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

  • Java

    14119questions

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