Java tutorial
/* ======================================================================= 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.annotation.TargetApi; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; import android.content.res.Resources; import android.opengl.GLES20; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.NavUtils; import android.util.Log; import android.view.KeyEvent; import android.widget.Toast; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.ContactListener; import fr.plnech.igem.R; import fr.plnech.igem.game.managers.ResMan; import fr.plnech.igem.game.model.BaseGame; import fr.plnech.igem.game.model.HUDElement; import fr.plnech.igem.game.model.PhysicalWorldObject; import fr.plnech.igem.game.model.res.FontAsset; import fr.plnech.igem.game.model.res.GFXAsset; import fr.plnech.igem.game.model.res.SoundAsset; import fr.plnech.igem.game.ui.DitheredSprite; import fr.plnech.igem.ui.model.MusicManager; import fr.plnech.igem.utils.FontsOverride; import org.andengine.audio.music.Music; import org.andengine.audio.music.MusicFactory; import org.andengine.audio.sound.Sound; import org.andengine.audio.sound.SoundFactory; import org.andengine.engine.Engine; import org.andengine.engine.camera.SmoothCamera; import org.andengine.engine.handler.timer.ITimerCallback; import org.andengine.engine.handler.timer.TimerHandler; import org.andengine.engine.options.EngineOptions; import org.andengine.entity.Entity; import org.andengine.entity.IEntity; import org.andengine.entity.scene.IOnSceneTouchListener; import org.andengine.entity.scene.Scene; import org.andengine.entity.scene.background.SpriteBackground; import org.andengine.entity.scene.menu.MenuScene; import org.andengine.entity.scene.menu.item.IMenuItem; import org.andengine.entity.scene.menu.item.SpriteMenuItem; import org.andengine.entity.sprite.Sprite; import org.andengine.entity.text.Text; import org.andengine.entity.text.TextOptions; import org.andengine.entity.util.FPSLogger; import org.andengine.extension.physics.box2d.PhysicsWorld; import org.andengine.input.touch.TouchEvent; import org.andengine.opengl.font.Font; import org.andengine.opengl.font.FontFactory; import org.andengine.opengl.font.FontManager; import org.andengine.opengl.font.IFont; import org.andengine.opengl.texture.ITexture; import org.andengine.opengl.texture.TextureManager; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory; import org.andengine.opengl.texture.region.ITextureRegion; import org.andengine.opengl.texture.region.ITiledTextureRegion; import org.andengine.opengl.texture.region.TiledTextureRegion; import org.andengine.opengl.vbo.VertexBufferObjectManager; import org.andengine.ui.activity.SimpleBaseGameActivity; import org.andengine.util.HorizontalAlign; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public abstract class AbstractGameActivity extends SimpleBaseGameActivity implements MenuScene.IOnMenuItemClickListener { private static final String TAG = "BaseGameActivity"; public static final String SUFFIX_UNLOCKED = "_unlocked"; private static final String SUFFIX_SCORE = "_highscore"; private Boolean shouldStartEngine = false; public static final int CAMERA_WIDTH = 480; public static final int CAMERA_HEIGHT = 800; private static final float SPLASH_DURATION = 1.0f; private static final String ASSET_PATH_GFX = "gfx/"; private static final String ASSET_PATH_FONT = "fonts/"; private static final int OPTION_RESET = 0; private static final int OPTION_NEXT = OPTION_RESET + 1; private static final int OPTION_QUIT = OPTION_NEXT + 1; private int profPosition; private final HashMap<CharSequence, ITiledTextureRegion> textureMap = new HashMap<>(); private final HashMap<CharSequence, IFont> fontMap = new HashMap<>(); private final HashMap<CharSequence, Sound> soundMap = new HashMap<>(); private VertexBufferObjectManager vertexBufferObjectManager; protected TextureManager textureManager; private FontManager fontManager; private AssetManager assetManager; private SharedPreferences preferences; private Scene gameScene; private Scene splashScene; private MenuScene pauseScene; private MenuScene winScene; private SpriteMenuItem nextWinMenuItem; private SpriteMenuItem nextPauseMenuItem; private Text gameOverText; private Text winText; SmoothCamera gameCamera; private PhysicsWorld physicsWorld; public static final int LAYER_BACKGROUND = 0; public static final int LAYER_FOREGROUND = LAYER_BACKGROUND + 1; public static final int LAYER_OVERGROUND = LAYER_FOREGROUND + 1; public static final int LAYER_HUD = LAYER_OVERGROUND + 1; public static final int LAYER_HUD_TEXT = LAYER_HUD + 1; public static final int LAYER_COUNT = LAYER_HUD_TEXT + 1; static final float MAX_SPEED_X = 200.0f; static final float MAX_SPEED_Y = 200.0f; static final float MAX_ZOOM_CHANGE = 0.8f; private final ArrayList<PhysicalWorldObject> objectsToDelete = new ArrayList<>(); private final ArrayList<PhysicalWorldObject> objectsToAdd = new ArrayList<>(); private BaseGame currentGame; private SpriteBackground splashBackground; private Music music; private boolean isChangingConfiguration; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/Roboto-Medium.ttf"); isChangingConfiguration = true; if (vertexBufferObjectManager == null) { vertexBufferObjectManager = super.getVertexBufferObjectManager(); } if (textureManager == null) { textureManager = getTextureManager(); } if (fontManager == null) { fontManager = getFontManager(); } if (assetManager == null) { assetManager = getAssets(); } if (preferences == null) { preferences = getSharedPreferences(getString(R.string.app_name), MODE_PRIVATE); } final Intent intent; final Bundle extras; if ((intent = getIntent()) != null && (extras = intent.getExtras()) != null) { try { final int gameId = extras.getInt(BaseGame.KEY_GAME_ID); currentGame = BaseGame.getGameFromTag(gameId, this); Log.d(TAG, "onCreate - Game id: " + gameId); } catch (Exception e) { e.printStackTrace(); } } else { Log.e(TAG, "onCreate - No game given!"); } } @Override public EngineOptions onCreateEngineOptions() { gameCamera = new SmoothCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, MAX_SPEED_X, MAX_SPEED_Y, MAX_ZOOM_CHANGE); final EngineOptions engineOptions = getEngineOptions(); engineOptions.getTouchOptions().setNeedsMultiTouch(true); engineOptions.getAudioOptions().setNeedsMusic(true); engineOptions.getAudioOptions().setNeedsSound(true); return engineOptions; } @Override public Engine onCreateEngine(EngineOptions pEngineOptions) { Engine engine = new Engine(pEngineOptions); if (shouldStartEngine) { Log.v(TAG, "onCreateEngine - Starting engine."); engine.start(); shouldStartEngine = !shouldStartEngine; } else { Log.v(TAG, "onCreateEngine - Not starting engine."); } return engine; } @Override public void onCreateResources() { Log.d(TAG, "onCreateResources - Beginning resource creation."); loadSplashScene(); } @Override public synchronized void onResumeGame() { if (mEngine != null) { super.onResumeGame(); shouldStartEngine = true; Log.v(TAG, "onResumeGame - We have an engine: marked as starting."); } else { Log.v(TAG, "onResumeGame - No engine to start."); } } @Override protected Scene onCreateScene() { this.mEngine.registerUpdateHandler(new FPSLogger()); initSplashScene(); Log.d(TAG, "onCreateScene - Splash Scene created."); loadMenus(); initMenuPause(); initMenuWin(); updateNextStatus(); Log.d(TAG, "onCreateScene - Splash Scene created."); loadGameAsync(); return splashScene; } @Override public boolean onKeyDown(final int pKeyCode, @NonNull final KeyEvent pEvent) { if (gameScene != null && pauseScene != null && pKeyCode == KeyEvent.KEYCODE_MENU && pEvent.getAction() == KeyEvent.ACTION_DOWN) { if (gameScene.hasChildScene()) { // The game is paused music.play(); pauseScene.back(); updateNextStatus(); } else { music.pause(); gameScene.setChildScene(pauseScene, false, true, true); } return true; } else { return super.onKeyDown(pKeyCode, pEvent); } } @Override public boolean onMenuItemClicked(MenuScene pMenuScene, IMenuItem pMenuItem, float pMenuItemLocalX, float pMenuItemLocalY) { switch (pMenuItem.getID()) { case OPTION_QUIT: onQuit(); return true; case OPTION_RESET: currentGame.logLevelEnd(currentGame.getScore(), false); currentGame.logLevelStart(); currentGame.setPlaying(true); currentGame.resetGame(); gameScene.clearChildScene(); music.seekTo(0); music.play(); resetMenus(); return true; case OPTION_NEXT: final Resources resources = getResources(); final int nextGameId = currentGame.getNextGameId(); if (nextGameId != BaseGame.ID_NONE) { final boolean nextGameIsPortrait = BaseGame.isPortrait(nextGameId); if (nextGameIsPortrait == currentGame.isPortrait()) { currentGame = BaseGame.getGameFromTag(nextGameId, this); updateNextStatus(); resetMenus(); loadGameAsync(); mEngine.setScene(splashScene); } else { BaseGame.startGame(this, nextGameId); warnAboutOrientation(); onQuit(); } } else { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), resources.getString(R.string.msg_last_game), Toast.LENGTH_SHORT).show(); } }); NavUtils.navigateUpFromSameTask(AbstractGameActivity.this); } return true; } return false; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public boolean isChangingConfigurations() { if (android.os.Build.VERSION.SDK_INT >= 11) { return super.isChangingConfigurations(); } else { return isChangingConfiguration; } } public IFont getFont(String fontName) { final IFont font = fontMap.get(fontName); if (font != null) { Log.v(TAG, "getFont - returning font " + fontName); } else { Log.v(TAG, "getFont - missing font " + fontName); } return font; } private void putFont(String fontName, IFont font) { fontMap.put(fontName, font); Log.v(TAG, "putFont - Added font " + fontName); } public ITiledTextureRegion getTexture(String textureName) { final ITiledTextureRegion texture = textureMap.get(textureName); if (texture != null) { Log.v(TAG, "getTexture - returning texture " + textureName); } else { Log.v(TAG, "getTexture - missing texture " + textureName); } return texture; } void putTexture(String textureName, ITiledTextureRegion texture) { textureMap.put(textureName, texture); Log.v(TAG, "putTexture - Added texture " + textureName); } public Sound getSound(String soundName) { final Sound sound = soundMap.get(soundName); if (sound != null) { Log.v(TAG, "getSound - returning Sound " + soundName); } else { Log.v(TAG, "getSound - missing Sound " + soundName); } return sound; } public void putSound(String soundName, Sound sound) { soundMap.put(soundName, sound); Log.v(TAG, "putSound - Added Sound " + soundName); } private void loadGFXAssets(BaseGame game) { for (GFXAsset asset : game.getGraphicalAssets()) { loadGFXAsset(asset); } Log.d(TAG, "loadGraphic - Finished loading game assets."); } private String loadGFXAsset(GFXAsset asset) { BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(textureManager, asset.getWidth(), asset.getHeight(), TextureOptions.BILINEAR); final String filename = asset.getFilename(); final int textureX = asset.getTextureX(); final int textureY = asset.getTextureY(); final int tileC = asset.getTileColumns(); final int tileR = asset.getTileRows(); TiledTextureRegion tiledTextureRegion = BitmapTextureAtlasTextureRegionFactory .createTiledFromAsset(textureAtlas, this, filename, textureX, textureY, tileC, tileR); putTexture(filename, tiledTextureRegion); textureAtlas.load(); return filename; } private void loadFonts(BaseGame game) { checkSetFontPath(); for (FontAsset asset : game.getFontAssets()) { Font font = loadFont(asset); font.load(); putFont(asset.toString(), font); } Log.d(TAG, "loadFonts - Finished loading fonts."); } private Font loadFont(FontAsset asset) { final ITexture fontTexture = new BitmapTextureAtlas(textureManager, 256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA); return FontFactory.createFromAsset(fontManager, fontTexture, assetManager, asset.getFilename(), asset.getSize(), asset.isAntialised(), asset.getColor()); } private void loadSounds(BaseGame game) { for (SoundAsset sound : game.getSoundAssets()) { loadSound(sound); } Log.d(TAG, "loadSounds - Finished loading sounds."); } private void loadSound(SoundAsset soundAsset) { try { SoundFactory.setAssetBasePath("mfx/"); Sound sound = SoundFactory.createSoundFromAsset(getEngine().getSoundManager(), getApplicationContext(), soundAsset.getFilename()); sound.setVolume(soundAsset.getVolume(), soundAsset.getVolume()); soundMap.put(soundAsset.getFilename(), sound); } catch (IOException e) { e.printStackTrace(); } } private void loadMusic() { if (music == null) { try { music = MusicFactory.createMusicFromAsset(mEngine.getMusicManager(), this, "mfx/games.mp3"); music.setLooping(true); } catch (IOException e) { e.printStackTrace(); } } } void checkSetGFXPath() { if (!BitmapTextureAtlasTextureRegionFactory.getAssetBasePath().equals(ASSET_PATH_GFX)) { BitmapTextureAtlasTextureRegionFactory.setAssetBasePath(ASSET_PATH_GFX); } } private void checkSetFontPath() { if (!FontFactory.getAssetBasePath().equals(ASSET_PATH_FONT)) { FontFactory.setAssetBasePath(ASSET_PATH_FONT); } } private void loadHUD(BaseGame game) { List<HUDElement> elements = game.getHudElements(); final IEntity layerHUD = gameScene.getChildByIndex(LAYER_HUD); final IEntity layerText = gameScene.getChildByIndex(LAYER_HUD_TEXT); for (HUDElement element : elements) { final Sprite sprite = element.getSprite(); final Text text = element.getText(); sprite.detachSelf(); text.detachSelf(); layerHUD.attachChild(sprite); layerText.attachChild(text); } } private void loadPhysics(BaseGame game) { final ContactListener contactListener = game.getContactListener(); if (contactListener == null) { return; } physicsWorld = new PhysicsWorld(game.getPhysicsVector(), false) { @Override public void onUpdate(float pSecondsElapsed) { super.onUpdate(pSecondsElapsed); if (!physicsWorld.isLocked()) { for (PhysicalWorldObject object : objectsToDelete) { destroyObject(object); } objectsToDelete.clear(); for (PhysicalWorldObject object : objectsToAdd) { createObject(object); } objectsToAdd.clear(); } } private void createObject(final PhysicalWorldObject object) { object.onAddToWorld(); } private void destroyObject(final PhysicalWorldObject object) { Body body = object.getBody(); Sprite sprite = object.getSprite(); body.setActive(false); body.setAwake(false); unregisterPhysicsConnector( physicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(sprite)); body.setActive(false); destroyBody(body); object.onRemoveFromWorld(); } }; physicsWorld.setContactListener(contactListener); gameScene.registerUpdateHandler(physicsWorld); } private void initGameScene() { loadGFXAssets(currentGame); loadFonts(currentGame); loadSounds(currentGame); loadMusic(); setGameScene(); } private void setGameScene() { gameScene = new Scene(); gameScene.setOnAreaTouchTraversalFrontToBack(); final IOnSceneTouchListener sceneTouchListener = currentGame.getOnSceneTouchListener(); if (sceneTouchListener != null) { gameScene.setOnSceneTouchListener(sceneTouchListener); } loadPhysics(currentGame); for (int i = 0; i < LAYER_COUNT; i++) { final Entity layer = new Entity(); layer.setZIndex(i); gameScene.attachChild(layer); } loadHUD(currentGame); loadScene(currentGame); mEngine.setScene(gameScene); MusicManager.pause(); music.play(); } private void warnAboutOrientation() { Resources resources = getResources(); final String message = String.format(resources.getString(R.string.msg_next_game), resources.getString(getOrientationResId())); toastOnUIThread(message, Toast.LENGTH_LONG); Log.d(TAG, "warnAboutOrientation - " + message); } private void loadScene(BaseGame game) { currentGame.setPlaying(true); gameScene = game.prepareScene(); } private void initMenuPause() { pauseScene = new MenuScene(gameCamera, this); final ITextureRegion textureNext = getTexture(ResMan.MENU_NEXT); final ITextureRegion textureReset = getTexture(ResMan.MENU_RESET); final ITextureRegion textureQuit = getTexture(ResMan.MENU_QUIT); nextPauseMenuItem = new SpriteMenuItem(OPTION_NEXT, textureNext, getVBOM()); nextPauseMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); nextPauseMenuItem.setVisible(false); pauseScene.addMenuItem(nextPauseMenuItem); final SpriteMenuItem resetMenuItem = new SpriteMenuItem(OPTION_RESET, textureReset, getVBOM()); resetMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); pauseScene.addMenuItem(resetMenuItem); final SpriteMenuItem quitMenuItem = new SpriteMenuItem(OPTION_QUIT, textureQuit, getVBOM()); quitMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); pauseScene.addMenuItem(quitMenuItem); pauseScene.buildAnimations(); pauseScene.setBackgroundEnabled(false); pauseScene.setOnMenuItemClickListener(this); } private void initMenuWin() { winScene = new MenuScene(gameCamera, this); final ITextureRegion textureNext = getTexture(ResMan.MENU_NEXT); final ITextureRegion textureReset = getTexture(ResMan.MENU_RESET); final ITextureRegion textureQuit = getTexture(ResMan.MENU_QUIT); nextWinMenuItem = new SpriteMenuItem(OPTION_NEXT, textureNext, getVBOM()); nextWinMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); nextWinMenuItem.setVisible(false); winScene.addMenuItem(nextWinMenuItem); final SpriteMenuItem resetMenuItem = new SpriteMenuItem(OPTION_RESET, textureReset, getVBOM()); resetMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); winScene.addMenuItem(resetMenuItem); final SpriteMenuItem quitMenuItem = new SpriteMenuItem(OPTION_QUIT, textureQuit, getVBOM()); quitMenuItem.setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); winScene.addMenuItem(quitMenuItem); winScene.buildAnimations(); winScene.setBackgroundEnabled(false); winScene.setOnMenuItemClickListener(this); } private void loadGameAsync() { loadGameAsync(0, true); } private void loadGameAsync(final int givenPosition, boolean shouldDelay) { Log.d(TAG, "loadGameAsync - Loading with prof position " + givenPosition); profPosition = givenPosition; if (shouldDelay) { MusicManager.start(this, MusicManager.MUSIC_MENU); registerUpdateHandler(SPLASH_DURATION, new ITimerCallback() { public void onTimePassed(final TimerHandler pTimerHandler) { mEngine.unregisterUpdateHandler(pTimerHandler); showProfOrRunGame(); } }); } else { showProfOrRunGame(); } } private void showProfOrRunGame() { final List<GFXAsset> profAssets = currentGame.getProfAssets(); if (profPosition < profAssets.size()) { GFXAsset profAsset = profAssets.get(profPosition); DitheredSprite splash = new DitheredSprite(0, 0, currentGame.getWidth(), currentGame.getHeight(), getTexture(loadGFXAsset(profAsset)), getVBOM()); splashScene.setBackground(new SpriteBackground(splash)); splashScene.setOnSceneTouchListener(new IOnSceneTouchListener() { @Override public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) { if (pSceneTouchEvent.isActionDown()) { Log.d(TAG, "onSceneTouchEvent - Touched splashScene: screen at position " + profPosition); loadGameAsync(++profPosition, false); return true; } return false; } }); } else { splashScene.setBackground(splashBackground); Log.d(TAG, "onTimePassed - Finished prof screens, launching game!"); runCurrentGame(); } } private void runCurrentGame() { initGameScene(); currentGame.logLevelStart(); Log.d(TAG, "runCurrentGame - Game Scene created."); } public void registerUpdateHandler(float duration, ITimerCallback pTimerCallback) { mEngine.registerUpdateHandler(new TimerHandler(duration, pTimerCallback)); } private int getHighScore(BaseGame game) { final String keyHighScore = game.getClass().getSimpleName() + SUFFIX_SCORE; return preferences.getInt(keyHighScore, 0); } public void setPhysicsCoeff(float coeff) { final Vector2 gravity = physicsWorld.getGravity(); final Vector2 physicsVector = currentGame.getPhysicsVector(); final float minCoeff = 0.5f; if (gravity.x < physicsVector.x * minCoeff || gravity.y < physicsVector.y * minCoeff) { return; } physicsWorld.setGravity(gravity.mul(coeff)); } public void markForDeletion(PhysicalWorldObject object) { if (!objectsToDelete.contains(object)) { objectsToDelete.add(object); } } public void markForAddition(PhysicalWorldObject object) { if (!objectsToAdd.contains(object)) { objectsToAdd.add(object); } } private void resetMenus() { pauseScene.detachChild(gameOverText); pauseScene.reset(); winScene.detachChild(winText); winScene.reset(); updateNextStatus(); } public void onLose(int score, float posRatioX, float posRatioY) { music.pause(); final IFont menuFont = getFont(FontAsset.name(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE, ResMan.F_HUD_BIN_COLOR, ResMan.F_HUD_BIN_ANTI)); gameOverText = new Text(0, 0, menuFont, getEndTextAndUpdateHighScore(false, score), 32, new TextOptions(HorizontalAlign.CENTER), getVBOM()); final Vector2 textPosition = spritePosition(gameOverText.getWidth(), gameOverText.getHeight(), posRatioX, posRatioY); gameOverText.setPosition(textPosition.x, textPosition.y); pauseScene.attachChild(gameOverText); currentGame.logLevelEnd(score, false); gameScene.setChildScene(pauseScene, false, true, true); } public void onWin(int score, float posRatioX, float posRatioY) { music.pause(); final IFont menuFont = getFont(FontAsset.name(ResMan.F_HUD_BIN, ResMan.F_HUD_BIN_SIZE, ResMan.F_HUD_BIN_COLOR, ResMan.F_HUD_BIN_ANTI)); winText = new Text(0, 0, menuFont, getEndTextAndUpdateHighScore(true, score), 32, new TextOptions(HorizontalAlign.CENTER), getVBOM()); final Vector2 textPosition = spritePosition(winText.getWidth(), winText.getHeight(), posRatioX, posRatioY); winText.setPosition(textPosition.x, textPosition.y); winScene.attachChild(winText); updateNextGame(); currentGame.logLevelEnd(score, true); gameScene.setChildScene(winScene, false, true, true); } private void onQuit() { this.finish(); } @NonNull private String getEndTextAndUpdateHighScore(boolean win, int score) { final StringBuilder winBuilder = new StringBuilder(); final String keyHighScore = currentGame.getClass().getSimpleName() + SUFFIX_SCORE; final int highScore = preferences.getInt(keyHighScore, 0); final boolean best = score > highScore; if (win) { winBuilder.append("VICTORY!"); } else { winBuilder.append("GAME OVER"); } if (best) { preferences.edit().putInt(keyHighScore, score).apply(); winBuilder.append("\nNew high score: ").append(score); updateNextStatus(); } else { winBuilder.append("\nHigh score: ").append(highScore); } return winBuilder.toString(); } private void updateNextStatus() { final boolean isUnlocked = getHighScore(currentGame) >= 50; Log.d(TAG, "updateNextStatus: " + isUnlocked); updateNextStatus(nextPauseMenuItem, pauseScene, isUnlocked); updateNextStatus(nextWinMenuItem, winScene, isUnlocked); } private void updateNextGame() { int lastUnlockedId = preferences.getInt(BaseGame.KEY_GAME_ID, 0); final int nextGameId = Math.max(currentGame.getNextGameId(), BaseGame.ID_GUT); final SharedPreferences.Editor editor = preferences.edit(); Log.d("DEBUG", "updateNextGame - Unlocking game " + nextGameId); editor.putBoolean(nextGameId + AbstractGameActivity.SUFFIX_UNLOCKED, true); if (nextGameId >= lastUnlockedId) { editor.putInt(BaseGame.KEY_GAME_ID, nextGameId); Log.d("DEBUG", "updateNextGame - New value: " + nextGameId); } editor.apply(); } private void updateNextStatus(SpriteMenuItem item, Scene scene, boolean isUnlocking) { item.setVisible(isUnlocking); if (isUnlocking) { scene.registerTouchArea(item); } else { scene.unregisterTouchArea(item); } } public Vector2 spriteCenter(ITextureRegion textureRegion) { /** * Returns the appropriate coordinates to center the given textureRegion in the game camera. */ return spritePosition(textureRegion, 0.5f, 0.5f); } public Vector2 spritePosition(ITextureRegion textureRegion, float positionRatioX, float positionRatioY, float ratio) { final float widthToRatio = textureRegion.getWidth() * ratio; final float heightToRatio = textureRegion.getHeight() * ratio; return spritePosition(new Vector2(widthToRatio, heightToRatio), new Vector2(positionRatioX, positionRatioY)); } public Vector2 spritePosition(ITextureRegion textureRegion, float positionRatioX, float positionRatioY) { final Vector2 textureDimensions = new Vector2(textureRegion.getWidth(), textureRegion.getHeight()); return spritePosition(textureDimensions, new Vector2(positionRatioX, positionRatioY)); } protected Vector2 spritePosition(ITextureRegion textureRegion, Vector2 positionRatio) { return spritePosition(new Vector2(textureRegion.getWidth(), textureRegion.getHeight()), positionRatio); } public Vector2 spritePosition(float textureDimX, float textureDimY, float posRatioX, float posRatioY) { return spritePosition(new Vector2(textureDimX, textureDimY), new Vector2(posRatioX, posRatioY)); } private Vector2 spritePosition(Vector2 textureDims, Vector2 positionRatio) { return new Vector2(getCamera().getWidth() * positionRatio.x - textureDims.x / 2, getCamera().getHeight() * positionRatio.y - textureDims.y / 2); } void initSplashScene(ITextureRegion splashTexture, int width, int height) { splashScene = new Scene(); DitheredSprite splash = new DitheredSprite(0, 0, width, height, splashTexture, getVBOM()); splashBackground = new SpriteBackground(splash); splashScene.setBackground(splashBackground); } public SmoothCamera getCamera() { return gameCamera; } public BaseGame getCurrentGame() { return currentGame; } public Scene getScene() { return gameScene; } public PhysicsWorld getPhysicsWorld() { return physicsWorld; } public VertexBufferObjectManager getVBOM() { return vertexBufferObjectManager; } protected abstract void loadSplashScene(); protected abstract void loadMenus(); protected abstract void initSplashScene(); protected abstract int getOrientationResId(); protected abstract EngineOptions getEngineOptions(); }