サイトのトップへ戻る

AndEngineドキュメント 日本語訳

Part 11. XMLからステージを読み込む、足場とコイン。

それでは、いくつかのゲームプレイの観点に着目してみましょう。このゲームの名前は"ジャンパーゲーム"です。 - キャラクターを操作して足場の間をジャンプしてコインを集めなければなりません。まず最初に、このゲームにおいては綺麗なグラフィックを作成しません。なぜなら:
  • これはコーディングについてのチュートリアルです。
  • 私はアーティストではありません。
  • 言えばなんでも用意してもらえると思わないでください。自分でも努力してください。


1. 足場の種類:
このゲームでは、3種類の足場があります:
Picture
足場 1 - 普通の固定足場。特別な機能はない。
Picture
足場 2 - 罠の足場。プレイヤーが接触したすると2秒後に落下する。
Picture
足場 3 - プレイヤーが触れた場合のみ落下する。


2. コインオブジェクト:
Picture

プレイヤーはコインを集めてスコアを獲得することができます。上記の画像を使用します。



3. 足場とコインの画像を読み込む:
  • Open our ResourcesManager クラスを開いて、画像と新しいテクスチャ用のテクスチャ領域のためにフィールドを作成します。:
    // Game Texture
    public BuildableBitmapTextureAtlas gameTextureAtlas;
        
    // Game Texture Regions
    public ITextureRegion platform1_region;
    public ITextureRegion platform2_region;
    public ITextureRegion platform3_region;
    public ITextureRegion coin_region;
    
  • 以前に作成したloadGameGraphics() メソッド内で、新たにゲームテクスチャを初期化してゲームリソース(足場とコイン)を読み込みましょう。
    private void loadGameGraphics()
    {
        BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/game/");
        gameTextureAtlas = new BuildableBitmapTextureAtlas(activity.getTextureManager(), 1024, 1024, TextureOptions.BILINEAR);
        
        platform1_region = BitmapTextureAtlasTextureRegionFactory.createFromAsset(gameTextureAtlas, activity, "platform1.png");
        platform2_region = BitmapTextureAtlasTextureRegionFactory.createFromAsset(gameTextureAtlas, activity, "platform2.png");
        platform3_region = BitmapTextureAtlasTextureRegionFactory.createFromAsset(gameTextureAtlas, activity, "platform3.png");
        coin_region = BitmapTextureAtlasTextureRegionFactory.createFromAsset(gameTextureAtlas, activity, "coin.png");
       
        try 
        {
            this.gameTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 1, 0));
            this.gameTextureAtlas.load();
        } 
        catch (final TextureAtlasBuilderException e)
        {
            Debug.e(e);
        }
    }
    

    ご覧の通り、新たにテクスチャを作成して、 gfx/game/フォルダからゲーム素材を読み込み、足場とコイン用のテクスチャ領域を4つ読み込んでいます。 これで、リソースの読み込みコードは完了です。次は別の観点について説明しましょう。



4. xml ファイルからステージを読み込む:
それでは、再度 GameScene クラスを開いて、ステージの読み込みについて説明しましょう!
  • まず、ステージの読み込みに必要な変数をいくつか作成します:
    private static final String TAG_ENTITY = "entity";
    private static final String TAG_ENTITY_ATTRIBUTE_X = "x";
    private static final String TAG_ENTITY_ATTRIBUTE_Y = "y";
    private static final String TAG_ENTITY_ATTRIBUTE_TYPE = "type";
        
    private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1 = "platform1";
    private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2 = "platform2";
    private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3 = "platform3";
    private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN = "coin";
    
  • 次にxmlファイルの読み込みと解析を司るメソッドを作成します。SimpleLevelLoaderと呼ばれるandengine の内蔵クラスを使用します。
    private void loadLevel(int levelID)
    {
        final SimpleLevelLoader levelLoader = new SimpleLevelLoader(vbom);
        
        final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.01f, 0.5f);
        
        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);
                
                // TODO later we will specify camera BOUNDS and create invisible walls
                // on the beginning and on the end of the level.
    
                return GameScene.this;
            }
        });
        
        levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(TAG_ENTITY)
        {
            public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException
            {
                final int x = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_X);
                final int y = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_Y);
                final String type = SAXUtils.getAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_TYPE);
                
                final Sprite levelObject;
                
                if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1))
                {
                    levelObject = new Sprite(x, y, resourcesManager.platform1_region, vbom);
                    PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF).setUserData("platform1");
                } 
                else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2))
                {
                    levelObject = new Sprite(x, y, resourcesManager.platform2_region, vbom);
                    final Body body = PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF);
                    body.setUserData("platform2");
                    physicsWorld.registerPhysicsConnector(new PhysicsConnector(levelObject, body, true, false));
                }
                else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3))
                {
                    levelObject = new Sprite(x, y, resourcesManager.platform3_region, vbom);
                    final Body body = PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF);
                    body.setUserData("platform3");
                    physicsWorld.registerPhysicsConnector(new PhysicsConnector(levelObject, body, true, false));
                }
                else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN))
                {
                    levelObject = new Sprite(x, y, resourcesManager.coin_region, vbom)
                    {
                        @Override
                        protected void onManagedUpdate(float pSecondsElapsed) 
                        {
                            super.onManagedUpdate(pSecondsElapsed);
                            
                            /** 
                             * TODO
                             * we will later check if player collide with this (coin)
                             * and if it does, we will increase score and hide coin
                             * it will be completed in next articles (after creating player code)
                             */
                        }
                    };
                    levelObject.registerEntityModifier(new LoopEntityModifier(new ScaleModifier(1, 1, 1.3f)));
                }            
                else
                {
                    throw new IllegalArgumentException();
                }
    
                levelObject.setCullingEnabled(true);
    
                return levelObject;
            }
        });
    
        levelLoader.loadLevelFromAsset(activity.getAssets(), "level/" + levelID + ".lvl");
    }
    
    それでは、このコードを何をしているかを説明しましょう。registerEntityLoader内では、
    1. xmlファイルから読み込んだ全てのエンティティの"mother entity"を戻り値として返します。"mother entity"とは、言い換えると、読み込まれた全てのエンティティが貼り付けられるエンティティのことです。もうお分かりでしょうが、 game sceneを戻り値として返す必要があります (上記のコードでしているように)
    2. 二つ目の registerEntityLoader では、実際にxmlファイルを解析しています。type 変数がどれと等しいのかを確認し、 "platform1"と等しかった場合は、最初の足場タイプのspriteを新規に作成して、戻り値として返します。また、bodyを作成してユーザーデータに "platform1" を設定します(これらのユーザーデータは、後でcontact listener内にて物理オブジェクトに識別するために必要になります)。 足場2と足場3になぜphysics connectorも登録しているのか疑問に思うかもしれません。 この記事の冒頭の説明から分かるように、これら二つの足場は特定の状況下で崩壊します。 そのためphysics connectorを登録しています(so sprite will update its positions, following body) 。 また、コインの作成を司るコードもあります。ご覧の通り、onManagedUpdateメソッドを上書きしています。 後でそれを使用してプレイヤーがコインと接触しているかどうかを確認し、コインの非表示設定やスコア追加などの特定のコードを実行します。 また、コインに loop scale entity modifierを登録して見た目を良くしています(少しアニメーションします)。
  • createScene メソッド内で新たに作成したメソッドを実行します:
    @Override
    public void createScene()
    {
        createBackground();
        createHUD();
        createPhysics();
        loadLevel(1);
    }
    
    この例では、assets/level/ ディレクトリから1.lvlという名前のファイルを読み込みます。
  • 指定されたディレクトリ内に以下のファイルを作成します。以下例:
    <?xml version="1.0" encoding="utf-8"?>
    <level width="1000" height="780">    
        <entity x="100" y="100" type="platform1"/>
        <entity x="200" y="200" type="platform1"/>
        <entity x="400" y="200" type="platform3"/>
        <entity x="550" y="300" type="platform2"/>
        <entity x="720" y="240" type="platform3"/>
        <entity x="400" y="270" type="coin"/>
        <entity x="500" y="400" type="coin"/>
        <entity x="600" y="400" type="coin"/>
    </level>
    
Picture

ゲームコードを実行すると、ゲームシーンに入った後に上記の結果が表示されます。 今のところは何もできません。ただxmlからゲームオブジェクトを読み込んだだけです。 次の記事では、プレイヤー・プレイヤーの移動を操作するゲームコントローラー・足場の挙動を扱うコードの作成方法を説明します。ゲームをプレイできるようにします。 

前の記事 次の記事