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

Java tutorial

Introduction

Here is the source code for fr.plnech.igem.game.PictoGame.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.support.annotation.NonNull;
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.PortraitGame;
import fr.plnech.igem.game.model.res.FontAsset;
import fr.plnech.igem.game.model.res.GFXAsset;
import fr.plnech.igem.game.picto.Card;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.*;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
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.*;

public class PictoGame extends PortraitGame {
    private static final String TAG = "PictoGame";
    private static final float FAIL_DURATION = 1.0f;
    private static final float WIN_DURATION = 1.0f;

    private double gameScorePercent = 0;
    private int gameTime = 100;

    private boolean isDisplayingCards = false;

    private final ArrayList<Card> cards = new ArrayList<>();

    private Card currentCard;
    private HUDElement HUDScore;

    private HUDElement HUDTime;
    private double cardCount;

    public PictoGame(AbstractGameActivity pActivity) {
        super(pActivity);
        gameScore = 0;
    }

    @Override
    public List<GFXAsset> getGraphicalAssets() {
        if (graphicalAssets.isEmpty()) {
            /* Cards */
            graphicalAssets.add(new GFXAsset(ResMan.CARD_BACK, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_BACK, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_BIOHAZARD, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_CMR, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_ENVIRONMENT, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_FACE, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_FLAMMABLE, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_GLOVES, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_MASK, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_OXIDISING, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_RADIOACTIVE, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_TOXIC, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_EYE, 512, 785, 0, 0));
            graphicalAssets.add(new GFXAsset(ResMan.CARD_SHOWER, 512, 785, 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 = 1440;
            final int profHeight = 2400;
            if (Locale.getDefault().getLanguage().equals("fr")) {
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_1_FR, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_2_FR, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_3_FR, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_4_FR, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_5_FR, profWidth, profHeight));
            } else {
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_1, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_2, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_3, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_4, profWidth, profHeight));
                profAssets.add(new GFXAsset(ResMan.PROF_MEMO_5, 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));
            fontAssets.add(new FontAsset(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE, ResMan.F_HUD_PICTO_COLOR,
                    ResMan.F_HUD_BIN_ANTI));
        }
        return fontAssets;
    }

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

        final float scale = 0.120f;

        Vector2 posS = new Vector2(5, 0); //activity.spritePosition(textureScore, 0.1f, 0.05f, HUDElement.SCALE_DEFAULT);
        Vector2 posT = new Vector2(155, 0); //activity.spritePosition(textureTime, 0.6f, 0.05f, HUDElement.SCALE_DEFAULT);

        Vector2 offS = new Vector2(90, 45);
        Vector2 offT = new Vector2(185, 45);

        IFont fontRoboto = activity.getFont(FontAsset.name(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE,
                ResMan.F_HUD_PICTO_COLOR, ResMan.F_HUD_BIN_ANTI));

        final VertexBufferObjectManager vbom = activity.getVBOM();

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

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

        return elements;
    }

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

        final Background backgroundColor = new Background(0.84706f, 0.64706f, 0.84314f);
        scene.setBackground(backgroundColor);

        resetGamePoints();
        createCards();

        scene.setTouchAreaBindingOnActionDownEnabled(true);

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

    @Override
    public void resetGame() {
        resetGamePoints();
        for (final Card card : cards) {
            deleteCard(card, false, false);
        }
        cards.clear();
        createCards();
    }

    private void incrementScore() {
        super.playSoundSuccess();
        gameScorePercent = ++gameScore * 2 * 100f / cardCount;
        Log.v(TAG, "beginContact - Increasing score to " + gameScore);
        setScore(gameScorePercent);
        if (gameScorePercent == 100) {
            activity.onWin(50 + 50 * gameTime / INIT_TIME, 0.5f, 0.2f);
        }
    }

    private void decrementTime() {
        setTime(--gameTime);
        if (gameTime == 0) {
            activity.onLose((int) (gameScorePercent * 0.5), 0.5f, 0.2f);
        }
    }

    private void deleteCard(Card card, boolean shouldRemove, boolean didUnregisteredTouchArea) {
        final Scene scene = activity.getScene();
        final Sprite back = card.getBack();

        card.setVisible(false);
        back.setVisible(false);
        if (didUnregisteredTouchArea) {
            scene.unregisterTouchArea(card);
        }
        if (shouldRemove) {
            cards.remove(card);
        }

        scene.getChildByIndex(PortraitGameActivity.LAYER_FOREGROUND).detachChild(card);
        scene.getChildByIndex(PortraitGameActivity.LAYER_FOREGROUND).detachChild(back);
    }

    private void createCards() {
        final double marginCoeff = 1.02;
        final float rows = 5;
        final float cols = 5;
        cardCount = rows * cols;
        final boolean countIsEven = cardCount % 2 != 0;
        if (countIsEven) {
            cardCount--; //We will remove a card.
        }

        final float cardWidth = (int) Math.ceil(512f * Card.SCALE_DEFAULT * marginCoeff);
        final float cardHeight = (int) Math.ceil(785f * Card.SCALE_DEFAULT * marginCoeff);
        final float baseX = 15;
        final float baseY = 110;

        Log.d(TAG, "createCards - cardW:" + cardWidth + ", H:" + cardHeight);
        Log.d(TAG, "createCards - baseX:" + baseX + ", Y:" + baseY);

        final Stack<String> cardStack = generateCardStack();

        for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
                final boolean isMiddleCard = i == Math.floor(cols / 2) && j == Math.floor(rows / 2);
                if (countIsEven && isMiddleCard) {
                    Log.d(TAG, "createCards - Skipping card " + i + "," + j + " to preserve evenness");
                } else {
                    createCard(cardStack.pop(), baseX + cardWidth * i, baseY + cardHeight * j);
                }
            }
        }

        //        Card debugCard = new Card(activity.getCamera().getWidth() / 2 - 40, baseY / 2 - 80, ResMan.CARD_BACK, activity.getTexture(ResMan.CARD_BACK), activity) {
        //            @Override
        //            public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
        //                final int action = pSceneTouchEvent.getAction();
        //                if (action == TouchEvent.ACTION_DOWN) {
        //                    for (Card card : cards) {
        //                        card.flip();
        //                    }
        //                    return true;
        //                }
        //                return false;
        //            }
        //        };
        //        addCard(debugCard);
    }

    private Stack<String> generateCardStack() {
        Stack<String> nameStack = new Stack<>();
        List<String> nameList = new ArrayList<>();
        Card.Type[] typeArray = Card.Type.valuesButBack();

        for (Card.Type type : typeArray) {
            nameList.add(cardName(type));
        }

        // Adding first cards of pairs, randomized to avoid position determinism
        Collections.shuffle(nameList);
        nameStack.addAll(nameList);

        // Adding second cards of pairs, randomized as well
        Collections.shuffle(nameList);
        nameStack.addAll(nameList);
        return nameStack;
    }

    @NonNull
    private String cardName(Card.Type type) {
        String resName;
        switch (type) {
        case BACK:
            resName = ResMan.CARD_BACK;
            break;
        case BIOHAZARD:
            resName = ResMan.CARD_BIOHAZARD;
            break;
        case CMR:
            resName = ResMan.CARD_CMR;
            break;
        case ENVIRONMENT:
            resName = ResMan.CARD_ENVIRONMENT;
            break;
        case FACE:
            resName = ResMan.CARD_FACE;
            break;
        case FLAMMABLE:
            resName = ResMan.CARD_FLAMMABLE;
            break;
        case GLOVES:
            resName = ResMan.CARD_GLOVES;
            break;
        case MASK:
            resName = ResMan.CARD_MASK;
            break;
        case OXIDISING:
            resName = ResMan.CARD_OXIDISING;
            break;
        case RADIOACTIVE:
            resName = ResMan.CARD_RADIOACTIVE;
            break;
        case TOXIC:
            resName = ResMan.CARD_TOXIC;
            break;
        case EYE:
            resName = ResMan.CARD_EYE;
            break;
        case SHOWER:
            resName = ResMan.CARD_SHOWER;
            break;
        default:
            throw new IllegalStateException("Missing sprite for type " + type);
        }
        return resName;
    }

    private void createCard(String resCardName, float pX, float pY) {
        Card card = new Card(pX, pY, resCardName, activity.getTexture(resCardName), activity);
        addCard(card);
    }

    private void addCard(Card card) {
        cards.add(card);
        final Scene gameScene = activity.getScene();
        gameScene.getChildByIndex(PortraitGameActivity.LAYER_FOREGROUND).attachChild(card);
        gameScene.getChildByIndex(PortraitGameActivity.LAYER_FOREGROUND).attachChild(card.getBack());
        gameScene.registerTouchArea(card);
    }

    public void onTouchCard(final Card card) {
        if (currentCard == null) {
            Log.d(TAG, "onTouchCard - First card: " + card.getType());
            currentCard = card;
            card.flip();
        } else {
            final String cardTypes = currentCard.getType() + " - " + card.getType();

            Log.d(TAG, "onTouchCard - Second card: " + card.getType());
            card.flip();

            if (card.equals(currentCard)) {
                Log.d(TAG, "onTimePassed - Same card :O");
                currentCard = null;
            } else if (card.getType().equals(currentCard.getType())) {
                Log.d(TAG, "onTimePassed - Same types :)" + cardTypes);
                final Card oldCard = currentCard;
                currentCard = null;
                incrementScore();

                animateCardDeletion(card);
                animateCardDeletion(oldCard);
            } else {
                Log.d(TAG, "onTimePassed - =/= types :( " + cardTypes);
                super.playSoundFailure();
                isDisplayingCards = true;
                activity.registerUpdateHandler(FAIL_DURATION, new ITimerCallback() {
                    @Override
                    public void onTimePassed(TimerHandler pTimerHandler) {
                        card.flip();
                        currentCard.flip();
                        currentCard = null;
                        isDisplayingCards = false;
                    }
                });
            }
        }
    }

    private void resetGamePoints() {
        gameScore = 0;
        gameTime = INIT_TIME;
        setScore(gameScore);
        setTime(gameTime);
        HUDTime.setUrgent(false);
    }

    private void setScore(double score) {
        final boolean isInteger = score == Math.floor(score);
        String padding = "";
        if (score == 0)
            padding += " ";
        if (score < 10)
            padding += " ";
        if (isInteger)
            padding += " ";
        final String formatStr = isInteger ? "%.0f%%" : "%.1f%%";
        final String scoreStr = padding + String.format(formatStr, score);
        Log.d(TAG, "setValue - Setting score to _" + scoreStr + "_");
        setScore(scoreStr);
    }

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

    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);
    }

    public boolean isDisplayingCards() {
        return isDisplayingCards;
    }

    private void animateCardDeletion(final Card card) {
        activity.getScene().unregisterTouchArea(card);

        final IEntityModifier.IEntityModifierListener logListener = new IEntityModifier.IEntityModifierListener() {
            @Override
            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
            }

            @Override
            public void onModifierFinished(final IModifier<IEntity> pEntityModifier, final IEntity pEntity) {
                activity.runOnUpdateThread(new Runnable() {
                    @Override
                    public void run() {
                        deleteCard(card, true, true);
                        Log.d(TAG, "run - Animation finished, deleting card " + card.getType());
                    }
                });
            }
        };
        final float fromAlpha = card.getAlpha();
        final float toAlpha = 0;

        final SequenceEntityModifier entityModifier = new SequenceEntityModifier(
                new AlphaModifier(WIN_DURATION, fromAlpha, toAlpha), new DelayModifier(WIN_DURATION));

        card.registerEntityModifier(new LoopEntityModifier(entityModifier, 1, logListener));
    }
}