サイトのトップへ戻る

AndEngineドキュメント 日本語訳

Part 13. カメラ領域、プレイヤーの死亡、コンタクトリスナー、雑記:

この記事では、以下のようないくつかの多岐にわたる内容を実装します:
  • カメラ領域 (制限)
  • プレイヤーの死亡イベント
  • コンタクトリスナー (空中ジャンプできてしまうのを修正する)
  • コインを収集できるようにする


1. カメラ領域を設定する:
カメラ領域を設定して、カメラの移動を特定の範囲内に制限します。そうすることで、例えばプレイヤーが落下して死亡した後には、カメラをプレイヤーを追いかけません。 X軸上の座標は0で止めます。まず最初やるべきことは、カメラの種類をCameraではなくBoundCameraに変更することです。
  • activity クラスを編集して、カメラの種類をBoundCameraに変更します。
    camera = new BoundCamera(0, 0, 800, 480);
    
  • BaseSceneクラスとResourcesManagerクラスを編集し、 Camera を BoundCamera に置き換えます。
  • eclipseが報告した全てのエラーを修正した後(単にカメラの種類を変更するだけです)、GameScene クラスを開いて、ステージデータファイルから取得したデータに基づいてカメラ領域を設定します。
  • loadLevel メソッド内で、 コメントアウトされている行が二つ (width とheight)あります。それらのコメントを解除して、カメラ領域の設定に使用します:
    levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(LevelConstants.TAG_LEVEL)
    {
        public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException 
        {
            final int width = SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_WIDTH);
            final int height = SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_HEIGHT);
            
            camera.setBounds(0, 0, width, height); // here we set camera bounds
            camera.setBoundsEnabled(true);
    
            return GameScene.this;
        }
    });
    
    カメラ領域の最小値を設定します。最小値は( 0x, 0y)で、最大値はステージファイルから解析した値です。以前作成したステージファイルの場合、以下の行があるので最大値は(2000x,700y)になります。:
    <level width="1000" height="780">
    


2. コインを収集する:
コインを収集してスコアにポイントを追加し、収集した後にはコインを非表示する方法を説明します。 Go to the loadLevel code, to the line where we create coin, we left onManageUpdate method commented and left undone, now we will insert there code responsible for checking if player collides with coin. That`s how it should look like:
levelObject = new Sprite(x, y, resourcesManager.coin_region, vbom)
{
    @Override
    protected void onManagedUpdate(float pSecondsElapsed) 
    {
        super.onManagedUpdate(pSecondsElapsed);

        if (player.collidesWith(this))
        {
            addToScore(10);
            this.setVisible(false);
            this.setIgnoreUpdate(true);
        }
    }
};

このコードは、updateのたびにプレイヤーがコインと接触しているかを確認します。 接触していた場合は、以前作成したメソッドを使ってスコアに10点追加し、コインを非表示にし、コインにupdataを無視するよう設定します (既に収集されているのでそれ以上はupdataされません)



3. プレイヤーの死亡イベントを制御する:
それでは、プレイヤーの死亡イベントを実装します。プレイヤーが落下する(プレイヤーのY座標の値が0以下になる)度に、"game over"を表示します。 後で、このメッセージや似たような何かをクリックして、ゲームを再スタートする機能を実装することができます。 あなたの要件にも拠りますが、今のところはプレイヤーが死亡する(落下する)度にメッセージが表示されるだけにしましょう
  • ゲームオーバーメッセージのtextと、このメッセージが既に表示されているかどうかのboolean型フラグ(再表示されるのを防ぐため)のフィールドを二つ作成します。
    private Text gameOverText;
    private boolean gameOverDisplayed = false;
    
  • ゲームオーバーtextを初期化するメソッドとそれを表示するメソッドを作成します:
    private void createGameOverText()
    {
        gameOverText = new Text(0, 0, resourcesManager.font, "Game Over!", vbom);
    }
    
    private void displayGameOverText()
    {
        camera.setChaseEntity(null);
        gameOverText.setPosition(camera.getCenterX(), camera.getCenterY());
        attachChild(gameOverText);
        gameOverDisplayed = true;
    }
    
    ゲームオーバーtextを表示するメソッドでは、まずカメラの追跡エンティティを無効にして、それから現在のカメラの中央位置にゲームオーバーtextを設定し、 メッセージを貼り付けてフラグにtrueを設定します。
  • createScene() メソッド内でcreateGameOverText()メソッドを実行します。
    @Override
    public void createScene()
    {
        createBackground();
        createHUD();
        createPhysics();
        loadLevel(1);
        createGameOverText();
        setOnSceneTouchListener(this); 
    }
    
  • go to loadLevel function, to the line where we initialize our player, inside onDie execute code responsible for displaying game over text, firstly checking if it was not displayed:
    @Override
    public void onDie()
    {
        if (!gameOverDisplayed)
        {
            displayGameOverText();
        }
    }
    


4. コンタクトリスナーで、空中ジャンプをできないようにする:
現時点では、最初に地面に着地することなく、何度も空中ジャンプをすることができます。コンタクトリスナーを組み合わせた簡単な小技を使うことで、これを修正します。
  • Player クラスを開いて、接触回数を保存するためのintフィールドを新たに作成します。:
    private int footContacts = 0;
    
  • この値を増加(++)および減少(--)させるメソッドを作成します
    public void increaseFootContacts()
    {
        footContacts++;
    }
    
    public void decreaseFootContacts()
    {
        footContacts--;
    }
    
  • この値が0より大きいかどうかを確認するようにジャンプ機能を編集します。0より大きい場合は、プレイヤーをジャンプさせます。 プレイヤーが足場に着地する度にこの値を増やし、プレイヤーと足場との接触が終わる度にこの値を減らします。
    public void jump()
    {
        if (footContacts < 1) 
        {
            return; 
        }
        body.setLinearVelocity(new Vector2(body.getLinearVelocity().x, 12)); 
    }
    
  • GameScene クラスを開いて、コンタクトリスナーを作成します。コンタクトリスナーとは何でしょうか? これを使って、fixtures同士で接触の開始/終了といったイベントが発生した時にコードを実行することができます。 例えば、"player"というユーザーデータを設定することでそれがプレイヤーのbodyであると識別するように、 ユーザーデータを設定してfixturesやbodyを識別することができます。
    private ContactListener contactListener()
    {
        ContactListener contactListener = new ContactListener()
        {
            public void beginContact(Contact contact)
            {
                final Fixture x1 = contact.getFixtureA();
                final Fixture x2 = contact.getFixtureB();
    
                if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
                {
                    if (x2.getBody().getUserData().equals("player"))
                    {
                        player.increaseFootContacts();
                    }
                }
            }
    
            public void endContact(Contact contact)
            {
                final Fixture x1 = contact.getFixtureA();
                final Fixture x2 = contact.getFixtureB();
    
                if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
                {
                    if (x2.getBody().getUserData().equals("player"))
                    {
                        player.decreaseFootContacts();
                    }
                }
            }
    
            public void preSolve(Contact contact, Manifold oldManifold)
            {
    
            }
    
            public void postSolve(Contact contact, ContactImpulse impulse)
            {
    
            }
        };
        return contactListener;
    }
    
    ここでは、コンタクトリスナーの全てのbeginContactとendContact 内で、まずはfixture Aとfixture Bがユーザーデータを取得できるかどうか確認します(これらfixtures A と B は、beginContactのような特定のイベント間で発生する fixtures です)。後半では x2 body のユーザーデータが "player"に等しいかどうかを確認し、等しい場合は(begin contactでは)foot contactの値を増加させ、 ( end contactでは)foot contactの値を減少させます。 Keep in mind that player could be also fixture A (x1) so it might be useful to also check if x1 body user data equals player (In practice, you can make an educated guess about which fixture is which, mainly based on the order that you created things in the world) In this case, for our code it should work just fine.
  • 以下のようにして、physics worldの作成を司るメソッド内で、physics worldにコンタクトリスナーを登録します:
    private void createPhysics()
    {
        physicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0, -17), false); 
        physicsWorld.setContactListener(contactListener());
        registerUpdateHandler(physicsWorld);
    }
    
これで完了です。"空中ジャンプ"の問題は修正されました。もう問題ないでしょう。 後ほど、コンタクトリスナーを使って足場に機能を追加します(プレイヤーと接触した後に落ちる足場、などのような)。 この記事についてはこれで終わります。
player.java
ファイルをダウンロードする
gamescene.java
ファイルをダウンロードする
前の記事 次の記事