2011年8月28日日曜日

Java LinkedListのテスト(Android Game 敵と弾の当たり判定〜削除)

Androidでゲームを作っているのですが、敵も沢山いて、プレイヤーが撃った弾も沢山ある場合、敵毎に全ての弾と当たり判定を実施する必要があります。敵が弾に当たっている場合は、敵と当たっている弾を削除します。簡単に出来ると思っていたのですが、今これにハマっています。。よって頭を整理しながらまとめていきたいと思います。

敵と弾は数が自在に調整できた方がいいので、今回のテスト対象であります、LinkedListに格納していきます。ArrayListかLinkedListかどちらを選択するかについてですが、このページを見て、削除が多いのでLinkedListを使うことにします。敵はEnemyクラスのインスタンスになり、弾はBulletクラスのインスタンスになります。

まず、Enemyクラスは下記とします。
public class Enemy {
	float x, y, w = 30, h = 30;
	
	public Enemy(float X, float Y){
		x = X; y = Y;
	}
}

次に、Bulletクラスは下記とします。(今回はテストなので分かり易くする為に弾の大きさを敵と同じにしました。)
public class Bullet {
	float x, y, w = 30, h = 30;
	
	public Bullet(float X, float Y){
		x = X; y = Y;
	}
}

次に、EnemyクラスとBulletクラスを格納するためのLinkedListを2つ作ります。
private LinkedList<Enemy> enemys = new LinkedList<Enemy>();
private LinkedList<Bullet> bullets = new LinkedList<Bullet>();

次に、敵と弾のインスタンスを3つずつ作成し、LinkedListに格納します。インスタンス作成時の引数はx座標とy座標になりますので、最初の敵と最初の弾はまさに同じ場所にいて、その他の敵と弾は全く別の場所にいることになります。つまり、後程のコードで、うまく最初の敵と最初の弾だけ消えればゴールになります。
//敵の生成
enemys.add(new Enemy(10,10));
enemys.add(new Enemy(30,50));
enemys.add(new Enemy(100,100));
//弾の生成
bullets.add(new Bullet(10,10));
bullets.add(new Bullet(200,200));
bullets.add(new Bullet(300,300));

それでは、実際に当たり判定処理と、当たっている場合の削除をしてみます。想定するコードは下記です。
//敵と弾の衝突判定
Enemy eNow; Bullet bNow;
for(Iterator<Enemy> i = enemys.iterator(); i.hasNext();){
	eNow = i.next();
	for(Iterator<Bullet> j = bullets.iterator(); j.hasNext();){
		bNow = j.next();
		if(eNow.x<bNow.x+bNow.w && bNow.x<eNow.x+eNow.w &&
				eNow.y<bNow.y+bNow.h && bNow.y<=eNow.y+eNow.h){
			j.remove(); //弾を消す
			i.remove(); //敵を消す
		}
	}
}

上記コードを通した結果を下記のコードで表示してみます。
//結果の表示
System.out.println("実行結果");
for(Iterator<Enemy> i = enemys.iterator(); i.hasNext();){
	eNow = i.next();
	System.out.println("敵は("+(int)eNow.x+","+(int)eNow.y+")にいます。");
}
for(Iterator<Bullet> i = bullets.iterator(); i.hasNext();){
	bNow = i.next();
	System.out.println("弾は("+(int)bNow.x+","+(int)bNow.y+")にあります。");
}

さて結果は下記のようになりました。やはり問題ないようだな。しっかり想定どおり最初の敵と最初の弾のみ消えている。別の部分に問題があるってことだな。。
実行結果
敵は(30,50)にいます。
敵は(100,100)にいます。
弾は(200,200)にあります。
弾は(300,300)にあります。

試しに弾の位置を少し変えて実行してみよう。最初の弾の位置をずらしました。
//敵の生成
enemys.add(new Enemy(10,10));
enemys.add(new Enemy(30,50));
enemys.add(new Enemy(100,100));
//弾の生成
bullets.add(new Bullet(30,40));
bullets.add(new Bullet(200,200));
bullets.add(new Bullet(300,300));

実行結果は下記のとおり。これは敵・弾ともに消えているけど、敵はもう一匹消えるべきだな。最初の敵と2番目の敵に両方当たっているはずだからね。まあでも今は敵同士は離れているので、これが問題ではないな。
実行結果
敵は(30,50)にいます。
敵は(100,100)にいます。
弾は(200,200)にあります。
弾は(300,300)にあります。

2011年8月22日月曜日

Android 横スクロールゲームをつくってみる


地面とボールをつくりました。ボールは既にタッチするとジャンプするようになっています。このページで作成したタッチするとジャンプし、ジャンプ中にタッチすると2段ジャンプする仕様です。ちなみに、タッチをし続けるとジャンプ力が増すようになっています。これからこれをベースに横スクロールゲームを作ってみます。

雲を表示する



とりあえず適当に雲を作りました。現時点のコードを記載します。

2011年8月21日日曜日

Android SDK 横画面に固定する方法

AndroidManifest.xmlのタグのscreenOrientation属性にlandscapeを指定すればOK。
尚、エミュレーターの向きを横に回転させるには、macの場合、fn+control+F11でOK。

AndroidSDK タッチイベント onTouchEventの研究

Androidアプリはタッチイベントによってことが進むので、タッチイベントの正確な把握は必須であり、基本中の基本だ。時間をかけてじっくり研究することは必要なことだ。まだ全体像がAndroidSDKはよく分かっていないので、間違った記載があると思いますので、ご指摘いただければ幸いです。

http://goo.gl/1AcZh
この記事によると、
タッチイベントを取得するには、ActivityクラスのonTouchEvent()をオーバーライドします。引数には、MotionEventのインスタンスが渡されます。
とある。
また、
MotionEventは、getAction()を呼び出すことで、タッチアクション(DOWN/UP/MOVE/CANCEL)、getEventTime()を呼び出すことで、イベント発生時刻(ms)、getX()、getY()を呼び出すことで、タッチされたx、y座標、を取得することができます。
とある。

指一本しか使わない場合


指一本しか使わない場合はかなり単純に実装できそうだ。例えば、どこでもいいからユーザーがタッチすると、ジャンプするボールをつくることにしよう。長くタッチした場合にジャンプ力を増したりするケースが多いと思うが、今回はそのようなことは考慮しないことにしよう。タッチしたらジャンプするだけだ。

サンプルコードは下記になります。黒い画面に白いボールが一つ表示され、タッチするとボールが跳ねます。

2011年8月4日木曜日

HTML5 - Canvas アニメーション Walk


<canvas id="game2" width="500" height="270"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("game2");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

var img_jero = [];
img_jero[0] = new Image();
img_jero[0].src = '/pic/jeronimo3.png';
img_jero[1] = new Image();
img_jero[1].src = '/pic/jeronimo2.png';
img_jero[2] = new Image();
img_jero[2].src = '/pic/jeronimo1.png';

var tm;
img_jero[2].onload = function() { 
 tm = setInterval(main,200);
}

var size_x = 50;
var size_y = 80;
var x = cw;
var y = 0;
var idx = 2;

function main(){
 ctx.clearRect(0,0,cw,ch);
 ctx.drawImage(img_jero[idx],x+250,y+175,size_x,size_y);
 ctx.drawImage(img_jero[idx],x,y);
 idx--;
 if(idx==-1){idx=2;}
 x=x-30;
 if(x<-300){x=cw;} 
}
</script>