今回メンドク・・簡単にするために、弾が作成された時に同時にサウンド再生をするようにしました。なので変更点はMainLoopクラスとMesodクラスのみとなっています。 |
ファイル名「MainLoop.java」 /* * SurfaceViewをextendsさせたクラス * メインループなどはここにあります * 基本的にSurfaceViewを使用した時には決まった変数の使用 * などがあるので、そういう変数やメソッドの末尾に * ”お決まり”と書いておきます */ package and.roid.shooting2; import java.util.ArrayList; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.MediaPlayer; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MainLoop extends SurfaceView implements SurfaceHolder.Callback,Runnable{ private SurfaceHolder holder;//お決まり private Thread thread;//お決まり //どのActivityを使用しているかのための変数 private Shooting2Activity s2a; private Mesod ms; private float disp_w,disp_h; private Drawable jikiimg,tamaimg; private Bitmap jikibit,tamabit; //弾用、連続で重ならないようにの変数 private boolean tamaflg; private int tamatime; //弾変化ボタン用 private Rect tamabtn; //音源用3種 private MediaPlayer jitama1s,jitama2s,jitama3s; /* * 今回画面に表示させるオブジェクトは自機と弾です * 全然違うオブジェクトですがObjectクラスをextends * することで同じような変数として扱うことができます。 * 自機は一つのオブジェクトだけですが、弾はたくさん * 表示します。しかし数は決まっていません。なので * ArrayListを使用することにしました。 * 普通の配列変数では、いくつ配列を使用するかを決めないと * いけませんが、ArrayListの場合は使用したいときに配列的な * ものをいくつでも作成することができます。 */ private ArrayList<Object> object = new ArrayList(); //コンストラクタが二つあるけど気にしないように //こちらのコンストラクタは、自前でViewを実装するときに //呼ばれるコンストラクタっぽい public MainLoop(Context context) { super(context); init(context); } //こちらはxml方式でViewを呼び出すときに呼ばれるぽい public MainLoop(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void init(Context context){ holder = getHolder();//お決まり holder.addCallback(this);//お決まり holder.setFixedSize(getWidth(), getHeight());//お決まり /* * s2a = (Shooting2Activity)context; * よくわからないけども、私的には使用している(今現在 * 画面に表示させている)アプリの何か色々なものをcontext * として受け取り、それがいまどのActivityのやつかとか * そんな感じの雰囲気と思います。(キニシテナイ) */ s2a = (Shooting2Activity)context; ms = new Mesod(); disp_w = s2a.disp_w; disp_h = s2a.disp_h; Resources resources = context.getResources();//画像登録準備 //ビットマップ方式で画像取り込み //ビットマップで取り込む理由として、使用したい大きさなどに変換できるので Bitmap img= BitmapFactory.decodeResource(resources,and.roid.shooting2.R.drawable.jiki); //ここで画像分割 //わざわざ画像の大きさをgetWidthgetHeightを使用するのは //確実に大きさを図って分割するため jikibit = Bitmap.createBitmap(img,0,0,img.getWidth()/2,img.getHeight()); tamabit = Bitmap.createBitmap(img,img.getWidth()/2,0,img.getWidth()/2,img.getHeight()); /* * Onjectクラスではインスタンス(実装)できないので * ObjectクラスをextendsさせたJikiクラスを実装 * ArrayListを使用しているため、addでインスタンスしています * メソッドなどを使用する場合はget(インデックス).でメソッドなど * 色々呼び出したりします。 * 今回はArrayListの0番目の要素に自機が入っています */ object.add(new Jiki(disp_w,disp_h)); object.get(0).Oint(jikibit, 240, 425, 0, 0, jikibit.getWidth(), jikibit.getHeight(),0); tamaflg = true; tamatime = 5; //弾ボタン用座標 tamabtn = new Rect(50,50,100,100); //3種類の音源を取り込み使用準備 jitama1s = MediaPlayer.create(context,R.raw.jitama1); jitama2s = MediaPlayer.create(context,R.raw.jitama2); jitama3s = MediaPlayer.create(context,R.raw.jitama3); try{ jitama1s.prepare(); jitama2s.prepare(); jitama3s.prepare(); }catch (Exception e){} } //implements Runnableを実装するとこのメソッドが自動追加 //ここがメインループとなります public void run() {//お決まり Canvas c; Paint p = new Paint(); p.setAntiAlias(true); while(thread != null){ c = holder.lockCanvas();//お決まり c.drawColor(Color.BLACK); //弾変化ボタン p.setColor(Color.BLUE); c.drawRect(tamabtn, p); p.setTextSize(30); c.drawText("tama:"+object.get(0).tamajoutai, 50, 150, p); /* * 自機も弾も同じObjectの要素を持っているので * インスタンス(実装)時に作成したいクラスを * 指定しておけば、同じObjectクラスとして使用 * することができます。わざわざ各オブジェクトの * メソッドを呼ぶのではなく、共通しているObjectの * メソッドを呼ぶことで解決しています */ for(int i=0;i<object.size();i++){ object.get(i).ODraw(c); object.get(i).OMove(); /* * 弾が画面外に出たらオブジェクト要素を消去します */ if(object.get(i).Ogetdead()==true) object.remove(i); } /* * 弾を1發打ったら連続で打てないようになり、タイマー * が0になったら打てるようにしています。 */ if(tamaflg == false){ --tamatime; if(tamatime < 0){ tamatime = 5; tamaflg = true; } } holder.unlockCanvasAndPost(c);//お決まり try { Thread.sleep(50);//お決まり } catch (Exception e){} } } public boolean onTouchEvent(MotionEvent event){ int action = event.getAction(); int x = (int)event.getX(); int y = (int)event.getY(); switch(action){ case MotionEvent.ACTION_DOWN: /* * 弾を打っていいよ状態であり自機画像範囲にタップしていれば * Jitama(弾クラス)を作成する */ if(tamaflg == true && ms.RectTap( x, y, object.get(0).OgetTapRect()) == true){ /* * 今回は弾を出すような操作をすると * どんな弾を作成するかのメソッドを * 呼び出します */ Tamajoutai(); tamaflg = false; } /* * 弾状態を変化させるボタン * 本来ならアイテムなどで弾の飛び方などの * 変化をさせるものでしょうけども、今回は * テストということで青短形タップで変化します */ if(ms.RectTap(x, y, tamabtn)==true){ ++object.get(0).tamajoutai; object.get(0).tamajoutai = (object.get(0).tamajoutai+3)%3; } break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: /* * 一応自機の移動もできますが、移動と弾発射は同時にはまだ * できません */ if(ms.RectTap(x, y, object.get(0).OgetTapRect()) == true) object.get(0).OMove(x, y); break; } return true; } /* * Objectクラスに弾の状態を表す変数を用意しています * それを外部から操作して変化させることでここのif文 * の分岐に割り当てられます */ public void Tamajoutai(){ //通常の1発だけ if(object.get(0).tamajoutai == 0){ object.add(new JiTama(disp_w,disp_h)); object.get(object.size()-1).Oint( tamabit, object.get(0).cx, object.get(0).cy-jikibit.getHeight(), 0, 30, tamabit.getWidth(), tamabit.getHeight(),0); //音源再生 ms.playSound(jitama1s); } //2発並んで if(object.get(0).tamajoutai == 1){ object.add(new JiTama(disp_w,disp_h)); object.get(object.size()-1).Oint( tamabit, object.get(0).cx-20, object.get(0).cy-jikibit.getHeight(), 0, 30, tamabit.getWidth(), tamabit.getHeight(),0); object.add(new JiTama(disp_w,disp_h)); object.get(object.size()-1).Oint( tamabit, object.get(0).cx+20, object.get(0).cy-jikibit.getHeight(), 0, 30, tamabit.getWidth(), tamabit.getHeight(),0); //音源再生 ms.playSound(jitama3s); } /* * 36度づつ自機の周りに10発一気に出ます */ if(object.get(0).tamajoutai == 2){ for(int i=0;i<10;i++){ object.add(new JiTama(disp_w,disp_h)); object.get(object.size()-1).Oint( tamabit, object.get(0).cx, object.get(0).cy, 30, 30, tamabit.getWidth(), tamabit.getHeight(),i*(360/10)); } //音源再生 ms.playSound(jitama2s); } } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}//お決まり public void surfaceCreated(SurfaceHolder arg0) {thread = new Thread(this);thread.start();}//お決まり public void surfaceDestroyed(SurfaceHolder arg0) {thread = null;}//お決まり } ファイル名「Mesod.java」 /* * 無理やり作った汎用メソッド群 * なんども使用するようなメソッドをかためて置いて * おきたかったので無理やりつくったクラス */ package and.roid.shooting2; import android.graphics.Rect; import android.media.MediaPlayer; public class Mesod { /* * わたくしの環境がXPERIAでその画面幅でアプリを作成 * しているのでそれから各アプリの画面幅に合うように調整 * させるための変数 */ static public final float XPERIA_W = 480f; static public final float XPERIA_H = 854f; //せっかくなので0も固定値に static public final float ZERO = 0f; private static final double PIE = 3.1415926; //サウンド再生用 public void playSound( MediaPlayer mp){ mp.seekTo(0); mp.start(); } /* * sin,cosなどを使用するときに入れ込む数値は * 3.14を半周とした数値を180で割ったラジアン値 * というものを使用しなければなりません。 * (1周3.14×2=6.28を360で割った数値) * 角度設定などは度数で出したほうが簡単なので設定は * 度数でして、使用するときにここのメソッドでラジアン値 * に変換しています */ public double toRadian(double deg){return (deg * PIE / 180);} /* * 受け取ったxy座標と調べたい短形範囲が重なっているかいないか */ public boolean RectTap(int x,int y,Rect gazou){ return gazou.left < x && gazou.top < y && gazou.right > x && gazou.bottom > y; } /* * この2行で各座標を実装機種の画面比に合わせます */ public int setSizeX(float disp_w,float zahyou){return (int) (zahyou * (disp_w / XPERIA_W));} public int setSizeY(float disp_h,float zahyou){return (int) (zahyou * (disp_h / XPERIA_H));} } |
無事成功しました! |
画像はないので前回のを使用しました。サウンド再生自体は特別難しくないのですが、音源を作成するのがちょっと難しいですよね・・・オリジナルなのがほしいですし。 |