前回までは
・画面の重力制御
・ボールの表示
・プレイヤーの移動&移動方向の補助線

今回はゲームクリア・ゲームオーバーの処理を実装したいと思います。

ゲームクリア/ゲームオーバー

まず初めに、ゲームクリアの定義ですが
・相手ゴールにボールを入れる。

単純ですね。
ただ、今のままだとボールに入ってもボールが跳ね返ってしまうので
ゴールの背中部分だけ壁をなくします。
ついでなので、ゴールポストも作っちゃいましょう。

[java]
MainScene.java

@Override
public void init() {

・・・省略・・・

final VertexBufferObjectManager vertexBufferObjectManager = getBaseActivity().getVertexBufferObjectManager();
final Rectangle ground1 = new Rectangle(0, camera.getHeight() – 2, 170, 2, vertexBufferObjectManager);
final Rectangle ground2 = new Rectangle((camera.getWidth() / 3) * 2, camera.getHeight() – 2, 307, 2, vertexBufferObjectManager);
final Rectangle ground3 = new Rectangle(170, camera.getHeight() – 40, 4, 40, vertexBufferObjectManager);
final Rectangle ground4 = new Rectangle(307, camera.getHeight() – 40, 4, 40, vertexBufferObjectManager);

final Rectangle roof1 = new Rectangle(0, 0, 170, 2, vertexBufferObjectManager);
final Rectangle roof2 = new Rectangle((camera.getWidth() / 3) * 2, 0,307, 2, vertexBufferObjectManager);
final Rectangle roof3 = new Rectangle(170, 0, 4, 40, vertexBufferObjectManager);
final Rectangle roof4 = new Rectangle(307, 0, 4, 40, vertexBufferObjectManager);
final Rectangle left = new Rectangle(0, 0, 2, camera.getHeight(), vertexBufferObjectManager);
final Rectangle right = new Rectangle(camera.getWidth() – 2, 0, 2, camera.getHeight(), vertexBufferObjectManager);

final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.8f, 0.1f);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground1, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground2, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground3, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground4, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof1, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof2, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof3, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof4, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyDef.BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyDef.BodyType.StaticBody, wallFixtureDef);

roof1.setColor(0, 0, 0);
roof2.setColor(0, 0, 0);
roof3.setColor(0, 0, 0);
roof4.setColor(0, 0, 0);

ground1.setColor(0, 0, 0);
ground2.setColor(0, 0, 0);
ground3.setColor(0, 0, 0);
ground4.setColor(0, 0, 0);

this.attachChild(ground1);
this.attachChild(ground2);
this.attachChild(ground3);
this.attachChild(ground4);
this.attachChild(roof1);
this.attachChild(roof2);
this.attachChild(roof3);
this.attachChild(roof4);
this.attachChild(left);
this.attachChild(right);

・・・省略・・・

}
[/java]
roof1/roof2でゴールポストの絵に合わせたゴール部分だけ開いた壁を作ります。
roof3/roof4で左右のゴールポスト部分の壁を作ります。

色は分かりやすいように一旦黒にしておきましょう。
>roof1.setColor(0, 0, 0);

※自分のゴールも同じようにします。

つづいてゲームクリアの判定処理です。
[java]
// アップデートハンドラー
TimerHandler timerHandler = new TimerHandler(1 / 60f, true, new ITimerCallback() {
public void onTimePassed(TimerHandler pTimerHandler) {

if(isEnd){
return;
}

if(-50 > ballSprite.getY()){

showGameClear();
}
if(camera.getHeight() + 50 < ballSprite.getY()){

showGameOver();
}
if(currentTime <= 0){
showGameOver();
}
}
});
[/java]

1秒間に60回処理するハンドラーを登録します。
ボールのスプライトのY座標が-50より小さい場合、ゲームクリアとします。
すなわち、画面上部にボールが隠れるくらい移動した場合です。

同じように、ゲームオーバー処理も実装します。
画面の高さ+50よりY座標が大きい場合、ゲームオーバーとします。
>if(currentTime <= 0)は制限時間が0になったら終了処理ですね。 制限時間のカウント処理を後述します。 このハンドラーをinit()メソッドで設定します。 >registerUpdateHandler(timerHandler);

ゲームの制限時間

[java]
private void countTime(){

if(isEnd){
return;
}

currentTime–;
currentTimeText.setText("Time " + currentTime);
currentTimeText.setColor(0,0,0);

if(currentTime <= 0){
return;
}

registerUpdateHandler(new TimerHandler(1, new ITimerCallback() {
public void onTimePassed(TimerHandler pTimerHandler) {
countTime();
}
}));
}
[/java]
1秒毎に、自分自身を呼び出すようにして、currentTimeを1ずつマイナスしていきます。
currentTimeをsetTextで画面に表示していくと、毎秒数字がマイナスされた値が表示されます。
このメソッドをinit()でよびだすようにします。

ゲームクリア/ゲームオーバーシーン

[java]
private void showGameClear(){

isEnd = true;

Text text = new Text(0, 0, font, "ゴーーーーーール!!", new TextOptions(HorizontalAlign.CENTER), getBaseActivity().getVertexBufferObjectManager());
text.setPosition((camera.getWidth() / 2) – (text.getWidth() / 2), (camera.getHeight() / 2) – (text.getHeight() / 2));
text.setColor(convertRGB(246),convertRGB(6),convertRGB(6));
attachChild(text);

text.registerEntityModifier(new ParallelEntityModifier(new ScaleModifier(3.0f, 0.1f, 1.5f), new RotationByModifier(2.0f, 360)));

physicsClear();

setEndButton();
}

private void showGameOver(){
isEnd = true;

Text text = new Text(0, 0, font, "ゲームオーバー!!", new TextOptions(HorizontalAlign.CENTER), getBaseActivity().getVertexBufferObjectManager());
text.setPosition((camera.getWidth() / 2) – (text.getWidth() / 2), (camera.getHeight() / 2) – (text.getHeight() / 2));
text.setColor(convertRGB(246),convertRGB(6),convertRGB(6));
attachChild(text);

text.registerEntityModifier(new ParallelEntityModifier(new ScaleModifier(3.0f, 0.1f, 1.5f), new RotationByModifier(2.0f, 360)));

physicsClear();

setEndButton();
}

private void setEndButton(){
ButtonSprite btnRetry = getBaseActivity().getResourceUtil()
.getButtonSprite("retry1.png", "retry1.png");
btnRetry.setPosition((camera.getWidth() / 2) – (btnRetry.getWidth() / 2), (camera.getHeight() / 2) + 50);
btnRetry.setTag(TAG_RETRY);
btnRetry.setOnClickListener(this);
attachChild(btnRetry);
registerTouchArea(btnRetry);

ButtonSprite btnMenu = getBaseActivity().getResourceUtil()
.getButtonSprite("stageSelect1.png", "stageSelect1.png");
btnMenu.setPosition((camera.getWidth() / 2) – (btnRetry.getWidth() / 2), (camera.getHeight() / 2) + 150);
btnMenu.setTag(TAG_STAGE);
btnMenu.setOnClickListener(this);
attachChild(btnMenu);
registerTouchArea(btnMenu);
}

private void physicsClear() {
Iterator<Body> localIterator = mPhysicsWorld.getBodies();
while (true) {
if (!localIterator.hasNext()) {
mPhysicsWorld.clearForces();
mPhysicsWorld.clearPhysicsConnectors();
mPhysicsWorld.reset();
return;
}
try {
final Body localBody = (Body) localIterator.next();
Sprite sprite = (Sprite) localBody.getUserData();
if(null == sprite){
continue;
}
sprite.detachSelf();
mPhysicsWorld.destroyBody(localBody);
} catch (Exception localException) {
Debug.e(localException);
}
}
}

public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX,
float pTouchAreaLocalY) {
//btnPressedSound.play();
switch (pButtonSprite.getTag()) {
case TAG_RETRY:
physicsAllClear();
MainScene mainScene = new MainScene(getBaseActivity(), camera, stage);
getBaseActivity().refreshRunningScene(mainScene);
break;
case TAG_STAGE:
physicsAllClear();
StageSelectScene stageSelectScene = new StageSelectScene(getBaseActivity());
getBaseActivity().refreshRunningScene(stageSelectScene);
break;
}
}
[/java]
>showGameClear
上記メソッドでisEndをtrueにします。
このフラグで、各処理でゲーム処理の判定をしているところをスキップするようにします。
それから、ゲームクリア時のメッセージを画面に表示します。
「ゴーーーーーール!!」回転しながら段々大きくなるように表示してます。

>physicsClear
画面に表示されているBodyや画像などをクリアしてます。

>setEndButton
ゲーム終了時の「リトライ」「ステージ選択」などの遷移用の画像を表示します。
※ステージ選択については今後記載します。

>onClick
各ボタンが押下された時の処理です。
リトライは、再度MainSceneをセットして起動します。
ステージは、ステージ選択画面のSceneをセットして起動します。

これで、ゲームクリア・ゲームオーバーの処理ができました!

vol6_3

vol6_4

vol6_5

次回はディフェンダー・キーパーの敵キャラを表示します。