fr.plnech.igem.game.PianoGame.java Source code

Java tutorial

Introduction

Here is the source code for fr.plnech.igem.game.PianoGame.java

Source

/*
=======================================================================
BactMan Adventures | Scientific popularisation through mini-games
Copyright (C) 2015 IONIS iGEM Team
Distributed under the GNU GPLv3 License.
(See file LICENSE.txt or copy at https://www.gnu.org/licenses/gpl.txt)
=======================================================================
*/

package fr.plnech.igem.game;

import android.util.Log;
import com.badlogic.gdx.math.Vector2;
import fr.plnech.igem.game.managers.ResMan;
import fr.plnech.igem.game.model.HUDElement;
import fr.plnech.igem.game.model.LandscapeGame;
import fr.plnech.igem.game.model.TouchableAnimatedSprite;
import fr.plnech.igem.game.model.WorldObject;
import fr.plnech.igem.game.model.res.FontAsset;
import fr.plnech.igem.game.model.res.GFXAsset;
import fr.plnech.igem.game.piano.Base;
import fr.plnech.igem.game.piano.Key;
import fr.plnech.igem.game.piano.Polymerase;
import org.andengine.engine.camera.SmoothCamera;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.DelayModifier;
import org.andengine.entity.modifier.IEntityModifier;
import org.andengine.entity.modifier.SequenceEntityModifier;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.opengl.font.IFont;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.modifier.IModifier;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

public class PianoGame extends LandscapeGame {
    private static final String TAG = "PianoGame";

    private static final int INIT_SCORE = 0;
    private static final float CREATION_INTERVAL = 0.05f;
    private static final float DURATION_SHADER = 0.25f;

    private HUDElement HUDScore;
    private HUDElement HUDTime;

    private int gameTime;
    private final ArrayList<Base> bases = new ArrayList<>();
    private final ArrayList<Base> baseCpls = new ArrayList<>();
    private final HashMap<Key.Type, Key> keyMap = new HashMap<>();

    private int currentBaseIndex = 0;

    public PianoGame(AbstractGameActivity pActivity) {
        super(pActivity);
    }

    @Override
    public List<GFXAsset> getGraphicalAssets() {
        if (graphicalAssets.isEmpty()) {
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_BG, 1841, 1395, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_L_PHO, 732, 512, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_L_PHO_CPL, 732, 512, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_POLY, 1536, 1014, 0, 0, 2, 1));

            /* Bases */
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_A, 317, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_A_CPL, 317, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_T, 334, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_T_CPL, 334, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_G, 334, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_G_CPL, 334, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_C, 331, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_C_CPL, 329, 1024, 0, 0));

            /* Effects */
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_SHADER_OK, 329, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.PIANO_SHADER_KO, 329, 1024, 0, 0));

            /* HUD */
            graphicalAssets.add(new GFXAsset(ResMan.HUD_TIME, 1885, 1024, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.HUD_SCORE, 1885, 1024, 0, 0));
        }
        return graphicalAssets;
    }

    @Override
    public List<GFXAsset> getProfAssets() {
        if (profAssets.isEmpty()) {
            final int profWidth = 2400;
            final int profHeight = 1440;
            if (Locale.getDefault().getLanguage().equals("fr")) {
                profAssets.add(new GFXAsset(ResMan.PROF_PIANO_1_FR, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_PIANO_2_FR, profWidth, profHeight));
            } else {
                profAssets.add(new GFXAsset(ResMan.PROF_PIANO_1, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_PIANO_2, profWidth, profHeight));
            }
        }
        return profAssets;
    }

    @Override
    public List<FontAsset> getFontAssets() {
        if (fontAssets.isEmpty()) {
            fontAssets.add(new FontAsset(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE, ResMan.F_HUD_BIN_COLOR,
                    ResMan.F_HUD_BIN_ANTI));
        }
        return fontAssets;
    }

    @Override
    public List<HUDElement> getHudElements() {
        if (elements.isEmpty()) {
            final ITiledTextureRegion textureScore = activity.getTexture(ResMan.HUD_SCORE);
            final ITiledTextureRegion textureTime = activity.getTexture(ResMan.HUD_TIME);

            final float scale = 0.08f;

            Vector2 posS = new Vector2(5, 0);
            Vector2 offS = new Vector2(65, 23);
            Vector2 posT = new Vector2(350, 0);
            Vector2 offT = new Vector2(345, 21);

            IFont fontRoboto = activity.getFont(FontAsset.name(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE,
                    ResMan.F_HUD_BIN_COLOR, ResMan.F_HUD_BIN_ANTI));
            Log.d(TAG, "getHudElements - Score: sprite: " + posS + " - text:" + offS.add(posS));
            Log.d(TAG, "getHudElements - Time:  sprite: " + posT + " - text:" + offT.add(posT));

            final VertexBufferObjectManager vbom = activity.getVBOM();

            HUDScore = new HUDElement().buildSprite(posS, textureScore, vbom, scale).buildText("", "31337".length(),
                    offS, fontRoboto, vbom);
            HUDTime = new HUDElement().buildSprite(posT, textureTime, vbom, scale)
                    .buildText("", 8, offT, fontRoboto, vbom).setUrgent(false);

            elements.add(HUDScore);
            elements.add(HUDTime);
        }

        return elements;
    }

    @Override
    public Scene prepareScene() {
        Scene scene = activity.getScene();

        resetGamePoints();
        final SmoothCamera camera = activity.getCamera();
        final VertexBufferObjectManager vbom = activity.getVBOM();

        scene.setBackground(new SpriteBackground(new Sprite(0, 0, camera.getWidth(), camera.getHeight(),
                activity.getTexture(ResMan.PIANO_BG), vbom)));

        Polymerase polymerase = new Polymerase(189, 35, activity);
        scene.getChildByIndex(AbstractGameActivity.LAYER_FOREGROUND).attachChild(polymerase.getSprite());

        createKeys();
        createADN();

        scene.setTouchAreaBindingOnActionDownEnabled(true);

        TimerHandler myTimer = new TimerHandler(1, true, new ITimerCallback() {
            public void onTimePassed(TimerHandler pTimerHandler) {
                decrementTime();
            }
        });
        scene.registerUpdateHandler(myTimer);
        return scene;
    }

    private void createADN() {
        createADN(15);
    }

    private void createADN(final int count) {
        if (count > 0) {
            createBase();
            activity.registerUpdateHandler(CREATION_INTERVAL, new ITimerCallback() {
                @Override
                public void onTimePassed(TimerHandler pTimerHandler) {
                    createADN(count - 1);
                }
            });
        }
    }

    private void createBase() {
        shiftBases();
        createBase(Base.Type.random(), new Vector2(800, 200), false);
    }

    private void createCplBase(Base.Type type) {
        createBase(type, new Vector2(245, 125), true);
    }

    private void createBase(Base.Type t, Vector2 pos, boolean cpl) {
        Base b = new Base(pos.x, pos.y, t, cpl, activity);
        final IEntity layerBG = activity.getScene().getChildByIndex(AbstractGameActivity.LAYER_BACKGROUND);
        layerBG.attachChild(b.getPhosphate());
        layerBG.attachChild(b.getSprite());
        if (cpl) {
            baseCpls.add(b);
        } else {
            bases.add(b);
        }
    }

    private void createKeys() {
        createKey(Base.Type.A);
        createKey(Base.Type.T);
        createKey(Base.Type.G);
        createKey(Base.Type.C);
    }

    private void createKey(Base.Type type) {
        Key key = new Key(type, this);
        keyMap.put(type, key);
        final Scene scene = activity.getScene();
        final TouchableAnimatedSprite sprite = key.getSprite();
        final TouchableAnimatedSprite shape = key.getShape();

        final IEntity layerBG = scene.getChildByIndex(AbstractGameActivity.LAYER_FOREGROUND);
        layerBG.attachChild(key.getShadowInvalid());
        layerBG.attachChild(key.getShadowValid());
        layerBG.attachChild(sprite);
        layerBG.attachChild(shape);
        scene.registerTouchArea(shape);
    }

    private Vector2 shiftPos(float x, float y) {
        final float baseWidth = 27; // Maximum sprite width, once scaled
        final float margin = 10;
        return new Vector2(x - baseWidth - margin, y);
    }

    private void shiftBases() {
        for (Base base : bases) {
            shiftBase(base);
        }
        for (Base base : baseCpls) {
            shiftBase(base);
        }
    }

    private void shiftBase(Base base) {
        final Sprite s = base.getSprite();
        final Sprite phosphate = base.getPhosphate();
        final Vector2 newPos = shiftPos(s.getX(), s.getY());
        final Vector2 newPosPho = shiftPos(phosphate.getX(), phosphate.getY());

        Log.d(TAG, "shiftBase: shifted from " + s.getX() + ", " + s.getY() + " to " + newPos.x + ", " + newPos.y);
        s.setPosition(newPos.x, newPos.y);
        phosphate.setPosition(newPosPho.x, newPosPho.y);
    }

    private void resetGamePoints() {
        gameScore = INIT_SCORE;
        gameTime = INIT_TIME;
        setScore(gameScore);
        setTime(gameTime);
    }

    private void setScore(int score) {
        String padding = "";
        final int scoreLength = String.valueOf(score).length();
        if (scoreLength < 2) {
            padding += " ";
        }
        if (scoreLength < 3) {
            padding += " ";
        }
        setScore(padding + score);
    }

    private void setScore(CharSequence text) {
        HUDScore.getText().setText(text);
    }

    private void gameOver() {
        final float posRatioX = 0.5f;
        final float posRatioY = 0.2f;
        if (gameScore >= 50) {
            activity.onWin(gameScore, posRatioX, posRatioY);
        } else {
            activity.onLose(gameScore, posRatioX, posRatioY);
        }
    }

    private void incrementScore() {
        super.playSoundSuccess();
        setScore(++gameScore);
        Log.v(TAG, "beginContact - Increasing score to " + gameScore + ".");
    }

    private void decrementScore() {
        super.playSoundFailure();
        setScore(--gameScore);
        Log.v(TAG, "beginContact - Decreasing score to " + gameScore + ".");
    }

    private void decrementTime() {
        setTime(--gameTime);
        if (gameTime == 0) {
            gameOver();
        }
    }

    private void setTime(int time) {
        String padding = "";
        if (time < 10) {
            padding += " ";
            HUDTime.setUrgent(true);
        }
        if (time < 100)
            padding += " ";
        setTime(padding + time);
    }

    private void setTime(CharSequence text) {
        HUDTime.getText().setText(text);
    }

    @Override
    public void resetGame() {
        for (Base b : bases) {
            deleteBase(b);
        }
        for (Base b : baseCpls) {
            deleteBase(b);
        }

        bases.clear();
        baseCpls.clear();
        currentBaseIndex = 0;
        resetGamePoints();
        createADN();
    }

    private void deleteBase(Base b) {
        final TouchableAnimatedSprite sprite = b.getSprite();
        final Sprite phosphate = b.getPhosphate();
        sprite.setVisible(false);
        sprite.detachSelf();
        phosphate.setVisible(false);
        phosphate.detachSelf();
    }

    public void onKeyPress(final Base.Type type) {
        final Base.Type currentType = bases.get(currentBaseIndex).getCplType();
        final Key keyValid = keyMap.get(currentType);
        final Key keyInvalid = keyMap.get(type);
        final boolean isValid = currentType == type;

        animate(keyValid, new SequenceEntityModifier(new DelayModifier(DURATION_SHADER)),
                new IEntityModifier.IEntityModifierListener() {
                    @Override
                    public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                        keyValid.showShadow(true, Key.Animation.VALID_HIT);
                        if (!isValid) {
                            keyValid.showShadow(true, Key.Animation.VALID_HIT);
                            keyInvalid.showShadow(true, WorldObject.Animation.INVALID_HIT);
                        }
                    }

                    @Override
                    public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                        keyValid.hideShadows();
                        if (!isValid) {
                            keyInvalid.hideShadows();
                        }
                    }
                });

        if (isValid) {
            createBase();
            createCplBase(type);
            currentBaseIndex++;
            incrementScore();
        } else {
            decrementScore();
        }
    }

    @Override
    public boolean isPortrait() {
        return false;
    }
}