前回までは
・画面の重力制御
・ボールの表示
・プレイヤーの移動&移動方向の補助線
・ゲームクリア
・ゲームオーバー
・制限時間
今回は敵キャラの実装と、その当たり判定をします。
敵キャラの実装
まず初めに、敵キャラの種類ですが3パターン考えています。
・ディフェンダー1
※移動しない/ボールが当たると消える。
・ディフェンダー2
※移動しない/ボールが当たっても消えない。
・キーパー
※左右に移動/ボールが当たっても消えない。
これらの敵の配置などを調整してステージにバリエーションをつけようと思います。
[java]
MainScene.java
private float keeperMoveX = 5;
private void addEnemyPlayer(float x, float y) {
final FixtureDef fixtureDef = PhysicsFactory.createFixtureDef(2, 0.2f, 0f);
AnimatedSprite enemyPlayerSprite = ResourceUtil.getInstance(getBaseActivity()).getAnimatedSprite("enemy1.png", 1, 2);
enemyPlayerSprite.setPosition(x, y);
enemyPlayerSprite.setRotation(enemyPlayerSprite.getRotation() – 90);
enemyPlayerSprite.setTag(TAG_ENEMYPLAYER);
Body enemyPlayerBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, enemyPlayerSprite, BodyDef.BodyType.StaticBody, fixtureDef);
enemyPlayerBody.setUserData(enemyPlayerSprite);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(enemyPlayerSprite, enemyPlayerBody, true, false));
this.attachChild(enemyPlayerSprite);
}
private void addEnemyPlayer2(float x, float y) {
final FixtureDef fixtureDef = PhysicsFactory.createFixtureDef(2, 0.2f, 0f);
AnimatedSprite enemyPlayerSprite = ResourceUtil.getInstance(getBaseActivity()).getAnimatedSprite("enemy2.png", 1, 2);
enemyPlayerSprite.setPosition(x, y);
enemyPlayerSprite.setRotation(enemyPlayerSprite.getRotation() – 90);
enemyPlayerSprite.setTag(TAG_ENEMYPLAYER2);
Body enemyPlayerBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, enemyPlayerSprite, BodyDef.BodyType.StaticBody, fixtureDef);
enemyPlayerBody.setUserData(enemyPlayerSprite);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(enemyPlayerSprite, enemyPlayerBody, true, false));
this.attachChild(enemyPlayerSprite);
}
private void addEnemyKeeper(float x, float y) {
final FixtureDef fixtureDef = PhysicsFactory.createFixtureDef(2, 0.2f, 0f);
AnimatedSprite enemyKeeperSprite = ResourceUtil.getInstance(getBaseActivity()).getAnimatedSprite("enemy3.png", 1, 2);
enemyKeeperSprite.setPosition(x, y);
enemyKeeperSprite.setRotation(enemyKeeperSprite.getRotation() – 90);
enemyKeeperSprite.setTag(TAG_KEEPER);
keeperBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, enemyKeeperSprite, BodyDef.BodyType.KinematicBody, fixtureDef);
keeperBody.setUserData(enemyKeeperSprite);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(enemyKeeperSprite, keeperBody, true, false) {
@Override
public void onUpdate(float pSecondsElapsed) {
if (!isEnd && null != keeperBody) {
super.onUpdate(pSecondsElapsed);
Sprite sprite = (Sprite) keeperBody.getUserData();
if (TAG_KEEPER == sprite.getTag()) {
if (sprite.getX() < camera.getWidth() / 3) {
System.out.println("X:" + (sprite.getX() – playerSprite.getWidth() / 2));
keeperMoveX = 5;
} else if (sprite.getX() + playerSprite.getWidth() > (camera.getWidth() / 3) * 2) {
System.out.println("X:" + sprite.getX());
keeperMoveX = -5;
}
keeperBody.setLinearVelocity(keeperMoveX, 0);
}
}
}
}
);
this.attachChild(enemyKeeperSprite);
}
[/java]
前回までに説明している「addPlayer」メソッドとほぼ同じですね。
>addEnemyPlayer
このキャラは動かないので「BodyDef.BodyType.StaticBody」で定義します。
setTagメソッドで「TAG_ENEMYPLAYER」を設定します。
>addEnemyPlayer2
これも同じ。
setTagメソッドで「TAG_ENEMYPLAYER2」を設定します。
>addEnemyKeeper
これも同じ。
setTagメソッドで「TAG_KEEPER」を設定します。
「onUpdate」メソッドをオーバーライドして、キーパーの移動を制御します。
キーパースプライトのX座標がカメラ幅の3分の1より小さかったらX座標の移動力を「5」にします。
3分の2より大きかったらX座標の移動力を「-5」にします。
X座標の移動力を5⇔-5を入れ替える事により、左右に移動するようになります。
[java]
@Override
public void init() {
・・・省略・・・
this.mPhysicsWorld.setContactListener(createContactListener());
・・・省略・・・
}
private ContactListener createContactListener(){
ContactListener contactListener = new ContactListener(){
@Override
public void beginContact(Contact contact){
}
@Override
public void endContact(Contact contact){
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null){
Sprite sprite1 = (Sprite)x1.getBody().getUserData();
Sprite sprite2 = (Sprite)x2.getBody().getUserData();
// 1:player, 2:enemyPlayer, 3:keeper, 4:ball
if ((TAG_ENEMYPLAYER == sprite1.getTag()
|| TAG_BALL == sprite1.getTag())
&& (TAG_ENEMYPLAYER == sprite2.getTag()
|| TAG_BALL == sprite2.getTag())){
if (TAG_ENEMYPLAYER == sprite1.getTag()){
x1.getBody().setActive(false);
crashAnimation(sprite1);
}
if (TAG_ENEMYPLAYER == sprite2.getTag()){
x2.getBody().setActive(false);
crashAnimation(sprite2);
}
}
}
}
@Override
public void preSolve(Contact contact, Manifold oldManifold){
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse){
}
};
return contactListener;
}
public void crashAnimation(Sprite sprite) {
final Sprite crashSprite = sprite;
crashSprite.registerEntityModifier(
new SequenceEntityModifier(
new FadeOutModifier(0.1f)
,new FadeInModifier(0.1f)
,new FadeOutModifier(0.1f)
,new FadeInModifier(0.1f)
,new FadeOutModifier(0.1f)
)
);
// アニメーション終了後に削除
registerUpdateHandler(new TimerHandler(0.5f, new ITimerCallback() {
public void onTimePassed(TimerHandler pTimerHandler) {
crashSprite.detachSelf();
}
}));
[/java]
>this.mPhysicsWorld.setContactListener(createContactListener());
上記処理を設定する事により、Body同士の当たり判定の制御が可能になります。
・beginContact
Body同士が当たった瞬間に処理する内容
・endContact
Body同士が当たり、離れる際に処理する内容
・preSolve
???未調査
・postSolve
???未調査
>final Fixture x1 = contact.getFixtureA();
>final Fixture x2 = contact.getFixtureB();
上記で、衝突したBodyの二つの情報が取得できます。
※どちらに何が入っているかの順番の保障はない?
>if ((TAG_ENEMYPLAYER == sprite1.getTag()
> || TAG_BALL == sprite1.getTag())
> && (TAG_ENEMYPLAYER == sprite2.getTag()
> || TAG_BALL == sprite2.getTag())){
ディフェンダー1とボールの組合せの衝突の場合、処理をする。
>if (TAG_ENEMYPLAYER == sprite1.getTag()){
> x1.getBody().setActive(false);
>
> crashAnimation(sprite1);
>}
ディフェンダー1は当たったら消える仕様なので、
Bodyをactiveではないように設定し、
crashAnimationメソッドを呼び出します。
>crashAnimation
0.1秒毎にフェードイン・アウトを繰り返し、点滅させる。
点滅処理が終わったら、スプライトを削除します。
これで、ボールが当たったらディフェンダー1だけ点滅して消えるようになりました。
試しに、画面に表示して見ます。
こんな感じになりました。
青色の敵がディフェンダー1なので、他の色の敵は当たっても消えません。
次回は、敵の配置を変えて、各ステージを作って行きます。
ステージ選択画面を作成して、ステージを選べるようにします。