Androidプログラミング日記 (仮)  

虫?潰し

あなたは

人目のプログラマーだよ。

Androidプログラミング日記 (仮).

 

 

 

 

虫?潰し

無理やりでも何か作れるようになってきたので、ちょっとした骨組みを目指しつつ虫潰しゲームを作ってみましたよ。まだまだ改良の余地と無駄なコードがあるのですが、きりのいいところで完成としました。下方から迫り来る(迫ってない・・)虫をタッチして潰すゲームです。しかし完成形はもっと四方八方から虫が・・としたいところですがそれはまた今度に。

では

このプログラムに4ファイルほど使用しました、オプションメニュー用にString.xmlファイルを変更しました。String.xmlファイルの変更は「オプションメニュー」をご覧ください。オプションメニューで使用するアイコンと、ゲーム内で使用する画像を載せておきます。

 

 
 

ファイル名「MushiTataki.java」

package and.roid.mushi;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;

public class MushiTataki extends Activity {
//登録するオプションメニューの種類3種
private static final int
MENU_ITEM0=0,
MENU_ITEM1=1,
MENU_ITEM2=2,
MENU_ITEM3=3,
MENU_ITEM4=4,
MENU_ITEM5=5;
public float disp_w,disp_h;//端末の画面の大きさを取得するための変数
private int col = Color.WHITE;
private boolean reset = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
//端末の画面の大きさを取得するための処理
Window window = getWindow();
WindowManager manager = window.getWindowManager();
Display disp = manager.getDefaultDisplay();
disp_w = disp.getWidth();//端末の画面の横幅取得
disp_h = disp.getHeight();//端末の画面の縦幅取得

//BoxViewを直接レイアウトに指定
setContentView(new BoxView(this));
}
//メニューボタンを押すと、セットされたメニューを表示
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);

//add(0,MENU_ITEM0,0,R.string.menu_item0)
//引数はグループID、アイテムID、優先順位、アイテムタイトルです
MenuItem item0 = menu.add(0,MENU_ITEM0,0,R.string.menu_item0);
//アイコン設定
item0.setIcon(R.drawable.ic_end);

MenuItem item1 = menu.add(0,MENU_ITEM1,0,R.string.menu_item1);
item1.setIcon(R.drawable.ic_white);

MenuItem item2 = menu.add(0,MENU_ITEM2,0,R.string.menu_item2);
item2.setIcon(R.drawable.ic_brack);

MenuItem item3 = menu.add(0,MENU_ITEM3,0,R.string.menu_item3);
item3.setIcon(R.drawable.ic_yellow);

MenuItem item4 = menu.add(0,MENU_ITEM4,0,R.string.menu_item4);
item4.setIcon(R.drawable.ic_blue);

MenuItem item5 = menu.add(0,MENU_ITEM5,0,R.string.menu_item5);
item5.setIcon(R.drawable.ic_gray);

return true;
}
//オプションメニューを選択した時の処理
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case MENU_ITEM0:
finish();//このメソッドでアプリ終了
return true;
case MENU_ITEM1:
col = Color.WHITE;
return true;
case MENU_ITEM2:
col = Color.BLACK;
return true;
case MENU_ITEM3:
col = Color.YELLOW;
return true;
case MENU_ITEM4:
col = Color.BLUE;
return true;
case MENU_ITEM5:
col = Color.GRAY;
return true;
}
return true;
}
public int getcolor(){return col;}
public boolean getreset(){return reset;}
public void setreset(){reset = false;}
}
 
 

ファイル名「BoxView.java」

package and.roid.mushi;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class BoxView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder holder;
private Thread thread;
//ゲーム状態
private static final int GAME_START = 0;
private static final int GAME_PLAY = 1;
private static final int GAME_END = 2;
private static final int GAME_CLEAR = 3;
private int gamestate = 0;//ゲーム状態を表す変数
private String massage="";//画面に表示させるメッセージ
private float disp_w,disp_h;//画面の幅高さ
private MushiTataki mushitataki;
private BoxGamen gamen;
private static final int//画面の飾りのための座標
gamen_x = 5,
gamen_y = 5;
private Bitmap img;

//コンストラクタ
public BoxView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
holder.setFixedSize(getWidth(), getHeight());
init(context);
}
//初期化処理
public void init(Context context){
Resources resources = context.getResources();//画像登録準備
img = BitmapFactory.decodeResource(resources,R.drawable.mushirobo);//imgに画像登録
mushitataki = (MushiTataki)context;
disp_w = mushitataki.disp_w;//画面幅取得
disp_h = mushitataki.disp_h;//画面高さ取得
//BoxGamenクラスを作成
gamen = new BoxGamen(gamen_x,gamen_y,(int)disp_w-5,(int)disp_h-35,img,gamestate);
}

//ループ:SurfaceViewのimprements Runnableを使用すると自動的に作成されるメソッド
public void run() {
Canvas c;
Paint p = new Paint();
p.setAntiAlias(true);

while(thread != null){
c = holder.lockCanvas();
c.drawColor(mushitataki.getcolor());
//ゲーム状態によってスイッチ処理
switch(gamestate){
case GAME_START:
massage = "TOUCH GAME START";
break;
case GAME_PLAY://プレイ中にゲームオーバーかクリアかの判定
massage = "";
if(gamen.getEnd()==true) {gamestate=2;gamen.setGameState(gamestate);}
if(gamen.getCla()==true) {gamestate=3;gamen.setGameState(gamestate);}
break;
case GAME_END:
massage = "虫の勝ち(´;ω;`)";
break;
case GAME_CLEAR:
massage = "GAMECLEAR!(*´∀`*)";
break;
}

gamen.draw(c, p,massage);

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:
switch(gamestate){
case GAME_START:
gamestate = 1;
gamen.setGameState(gamestate);
gamen.init(disp_w,img);
break;
case GAME_PLAY:
gamen.RectRect(x, y);
break;
case GAME_END:
gamestate = 0;
gamen.setGameState(gamestate);
gamen.setEnd();
break;
case GAME_CLEAR:
gamestate = 0;
gamen.setGameState(gamestate);
gamen.setCla();
break;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}

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;}

}
 
 

ファイル名「BoxGamen.java」

package and.roid.mushi;

import java.util.ArrayList;
import java.util.Date;
import java.util.Random;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;

public class BoxGamen {
//ゲーム状態
private static final int GAME_START = 0;
private static final int GAME_PLAY = 1;
private static final int GAME_END = 2;
private static final int GAME_CLEAR = 3;
private int gamestate = 0;
private boolean endflg = false;//ゲームオーバーフラグ
private boolean claflg = false;//クリアフラグ
private static final double PIE = 3.1415926;
private int gamen_x,gamen_y,gamen_w,gamen_h;//画面の大きさ取得用
private ArrayList mushi = new ArrayList();
private Bitmap[] imgs = new Bitmap[4];
private int score = 0;//スコア用
private int kazu;//虫の数用

BoxGamen(int x,int y,int w,int h,Bitmap img,int state){
gamestate = state;
gamen_x = x;
gamen_y = y;
gamen_w = w;
gamen_h = h;
//一旦ここで画像を4つに分ける
for(int i=0;i<imgs.length;i++){
imgs[i] = Bitmap.createBitmap(img, i*(img.getWidth()/4), 0, img.getWidth()/4, img.getHeight());
}
}
//初期化
public void init(float w,Bitmap img){
//ここから虫の初期位置決め
Random r = new Random(new Date().getTime());
kazu = r.nextInt(20)+5;//虫の数決め
//kazu分だけ虫を作成
for(int i=0;i<kazu;i++){
r = new Random(new Date().getTime());
int d = 90;//虫移動方向
int wh = 50;//虫大きさ
int vxy = r.nextInt(10)+5;//補正虫移動量用
double rad = toRadian((d+360)%360);//虫移動角度をラジアンに変換
int xspeed = (int) (Math.cos(rad)*vxy);//移動了確定
int yspeed = (int) -(Math.sin(rad)*vxy);//移動量確定
int x = r.nextInt((gamen_w-wh)-wh)+wh;//初期虫x座標
int y = gamen_h;//初期虫y座標
int count = r.nextInt(100);//虫出発用カウント
//虫作成
mushi.add(new BoxOb(count,x,y,wh,rad,vxy,xspeed,yspeed,imgs));
}
}
//表示
public void draw(Canvas c, Paint p,String massage){
switch(gamestate){
case GAME_START:
p.setTextSize(30);
p.setColor(Color.GREEN);
c.drawText(massage, gamen_x/2, gamen_h/2, p);
break;
case GAME_PLAY:
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.BLACK);
c.drawRect(new Rect(gamen_x, gamen_y, gamen_w, gamen_h), p);
for(int i=0;i<mushi.size();i++){
mushi.get(i).draw(c, p);
mushi.get(i).setAnime();
mushi.get(i).move();
if(mushi.get(i).getEnd() == true) endflg=true;
if(mushi.get(i).getDead() > 20) ++score;
if(mushi.get(i).getDead() > 20 || endflg==true) Reset(i);
if(score == kazu) claflg=true;
}
break;
case GAME_END:
p.setTextSize(30);
p.setColor(Color.RED);
c.drawText(massage, gamen_x, gamen_h/2, p);
break;
case GAME_CLEAR:
p.setTextSize(30);
p.setColor(Color.RED);
c.drawText(massage, gamen_x, gamen_h/2, p);
break;
}

p.setTextSize(30);
p.setColor(Color.BLACK);
c.drawText("SCORE:"+score, 10, 30, p);

}
//虫消去用
public void Reset(int index){
mushi.remove(index);
}
//タッチ座標と虫座標を比べて潰したか否か
public void RectRect(int x, int y){
for(int i=0;i<mushi.size();i++){
if(mushi.get(i).Hanni(x, y) == true) {mushi.get(i).setSpeed();}
}
}
//ラジアン変換
public double toRadian(double deg){return (deg * PIE / 180);}

//ゲーム状態セット用
public void setGameState(int state){gamestate = state;}

//ゲームオーバー確認用
public boolean getEnd(){return endflg;}

//ゲームクリア確認用
public boolean getCla(){return claflg;}

//ゲームオーバー確定用
public void setEnd(){endflg=false;}

//ゲームクリア確定用
public void setCla(){claflg=false;}
}
 
 

ファイル名「BoxOb.java」

package and.roid.mushi;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class BoxOb {
private float obj_x,obj_y;//オブジェクト座標
private int obj_wh;//オブジェクト大きさ
private int obj_xspeed;//移動量
private int obj_yspeed;//移動量
private Drawable[] image2;
private int anime;//アニメーション用
private int deadcount;//虫死亡用カウント
private boolean dead;//虫死亡フラグ
private int count;//虫出発用カウンタ

//コンストラクタ
BoxOb(int cou,int x,int y, int wh, double d, int vxy,int xspeed,int yspeed,Bitmap[] img){
count = cou;
dead = false;
anime = 0;
obj_x = x;
obj_y = y;
obj_xspeed = xspeed;
obj_yspeed = yspeed;
deadcount = 0;
obj_wh = wh;
image2 = new Drawable[4];
for(int i=0;i<image2.length;i++){image2[i] = new BitmapDrawable(img[i]);}
}
//表示
public void draw(Canvas c, Paint p){
image2[anime].setBounds((int)obj_x,(int)obj_y,(int)obj_x+obj_wh,(int)obj_y+obj_wh);
image2[anime].draw(c);
}
//移動
public void move(){
if(count <= 0){
obj_x += obj_xspeed;
obj_y += obj_yspeed;
if(dead==true) ++deadcount;
}
--count;
}
//虫生き残り用ゲームオーバー用
public boolean getEnd(){return obj_y+obj_wh < 0;}

//虫死亡用
public boolean getDeadtrue(){return dead;}

//虫死亡用
public int getDead(){return deadcount;}

//虫アニメーション用
public void setAnime(){if(dead==false){anime=(++anime)%3;}else{anime=3;}}

//虫座標と渡された座標の比較
public boolean Hanni(int x1, int y1){return (x1>obj_x && x1<obj_x+obj_wh && y1>obj_y && y1<obj_y+obj_wh);}

//虫死亡時の処理用
public void setSpeed(){obj_xspeed=0;obj_yspeed=0;dead=true;}

}
 
 

 
     

 

このプログラムの説明

タッチすると虫?が下方から出てくるので虫をタッチして潰して下さい。クリア条件は虫を潰した数がランダムで決められた規定数に達すればクリアです。画面上部を虫が1匹でも超えてしまうとゲームオーバーです。オプションメニューから、終了と背景色の変更ができます。

まだまだ知られざる便利なメソッドなどがAndroidプログラムには隠されています。完成形は見えているのですが、ここから進もうとするとそれらのメソッドをものにしないと進めない感じです。たとえば「Matrix」などは簡単に画像などを回転させてくれるのですが、扱うと画面全体が回転したり・・・・使い方をちゃんと覚えないといけませぬ。虫を四方八方から出現さして、好きな方向に進ませるには画像回転も必須ですし、ランダムポップにするなら条件分岐もちょっと複雑になります。わたしの経験ではまだぜんぜんダメダメです。

ですがここまで出来たのなら理想の完成形までもうちょっとなのでがんばりますよ!

PS.

みなさんプログラムを設計開発するときってどうやってるんでしょうか?わたしは頭の中の理想形に向かってちょっとずつコードを実行しながらエラーが出ないようにやっていきます。わかってるんです、これじゃだめだと・・・。メモでもなんでもいいので、作る物の概要を書き出し、それに必要なファイルと変数も軽く書いておくくらいしないとダメだな、と思いながらいつもやっています。趣味だからいっか!っていつも思いながらやるのですが、ちょっとコードが長くなりエラーが出たり、あ、これ付け加えたいな、とか思ってやっていくと書いたメソッドの意味があとから見てもわからなくなったりします。このへんの改革こそが一番必要なのかもしれません。

 

Androidプログラミング日記 (仮) | サイトマップ | 個人情報保護方針 | 応援メールテヘペロ | ©2012 Japan  相互リンク大募集中です