今回メンドク・・簡単にするために、弾が作成された時に同時にサウンド再生をするようにしました。なので変更点は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));}
}
|
無事成功しました! |
画像はないので前回のを使用しました。サウンド再生自体は特別難しくないのですが、音源を作成するのがちょっと難しいですよね・・・オリジナルなのがほしいですし。 |
Androidプログラミング日記 (仮)


