diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index f4e05c7..526ed65 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -28,6 +28,7 @@ import ve.ucv.ciens.ccg.nxtar.states.AutomaticActionSummaryState; import ve.ucv.ciens.ccg.nxtar.states.BaseState; import ve.ucv.ciens.ccg.nxtar.states.CameraCalibrationState; import ve.ucv.ciens.ccg.nxtar.states.InGameState; +import ve.ucv.ciens.ccg.nxtar.states.InstructionsState; import ve.ucv.ciens.ccg.nxtar.states.MainMenuStateBase; import ve.ucv.ciens.ccg.nxtar.states.OuyaMainMenuState; import ve.ucv.ciens.ccg.nxtar.states.ScenarioEndSummaryState; @@ -77,7 +78,7 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ * Valid game states. */ public enum game_states_t { - MAIN_MENU(0), IN_GAME(1), CALIBRATION(2), AUTOMATIC_ACTION(3), AUTOMATIC_ACTION_SUMMARY(4), SCENARIO_END_SUMMARY(5); + MAIN_MENU(0), IN_GAME(1), CALIBRATION(2), AUTOMATIC_ACTION(3), AUTOMATIC_ACTION_SUMMARY(4), SCENARIO_END_SUMMARY(5), HINTS(6); private int value; @@ -90,7 +91,7 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ } public static int getNumStates(){ - return 6; + return 7; } }; @@ -285,6 +286,7 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ states[game_states_t.AUTOMATIC_ACTION_SUMMARY.getValue()] = new AutomaticActionSummaryState(this); states[game_states_t.SCENARIO_END_SUMMARY.getValue()] = new ScenarioEndSummaryState(this); + states[game_states_t.HINTS.getValue()] = new InstructionsState(this); }catch(IllegalArgumentException e){ Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal argument caught creating states: ", e); @@ -426,17 +428,19 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ } // Render the debug overlay. - batch.setProjectionMatrix(pixelPerfectCamera.combined); - batch.begin();{ - // Draw the FPS overlay. - font.draw(batch, String.format("Render FPS: %d", Gdx.graphics.getFramesPerSecond()), overlayX, overlayY); - font.draw(batch, String.format("Total stream FPS: %d", videoThread.getFps()), overlayX, overlayY - font.getCapHeight() - 5); - font.draw(batch, String.format("Lost stream FPS: %d", videoThread.getLostFrames()), overlayX, overlayY - (2 * font.getCapHeight()) - 10); - font.draw(batch, String.format("Light sensor data: %d", sensorThread.getLightSensorReading()), overlayX, overlayY - (3 * font.getCapHeight()) - 15); - font.draw(batch, String.format("Device roll: %f", Gdx.input.getRoll()), overlayX, overlayY - (4 * font.getCapHeight()) - 20); - font.draw(batch, String.format("Device pitch: %f", Gdx.input.getPitch()), overlayX, overlayY - (5 * font.getCapHeight()) - 25); - font.draw(batch, String.format("Device azimuth: %f", Gdx.input.getAzimuth()), overlayX, overlayY - (6 * font.getCapHeight()) - 30); - }batch.end(); + if(ProjectConstants.DEBUG){ + batch.setProjectionMatrix(pixelPerfectCamera.combined); + batch.begin();{ + // Draw the FPS overlay. + font.draw(batch, String.format("Render FPS: %d", Gdx.graphics.getFramesPerSecond()), overlayX, overlayY); + font.draw(batch, String.format("Total stream FPS: %d", videoThread.getFps()), overlayX, overlayY - font.getCapHeight() - 5); + font.draw(batch, String.format("Lost stream FPS: %d", videoThread.getLostFrames()), overlayX, overlayY - (2 * font.getCapHeight()) - 10); + font.draw(batch, String.format("Light sensor data: %d", sensorThread.getLightSensorReading()), overlayX, overlayY - (3 * font.getCapHeight()) - 15); + font.draw(batch, String.format("Device roll: %f", Gdx.input.getRoll()), overlayX, overlayY - (4 * font.getCapHeight()) - 20); + font.draw(batch, String.format("Device pitch: %f", Gdx.input.getPitch()), overlayX, overlayY - (5 * font.getCapHeight()) - 25); + font.draw(batch, String.format("Device azimuth: %f", Gdx.input.getAzimuth()), overlayX, overlayY - (6 * font.getCapHeight()) - 30); + }batch.end(); + } } /** diff --git a/src/ve/ucv/ciens/ccg/nxtar/scenarios/HintsOverlayBase.java b/src/ve/ucv/ciens/ccg/nxtar/scenarios/HintsOverlayBase.java new file mode 100644 index 0000000..2a7d685 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/scenarios/HintsOverlayBase.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.scenarios; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.utils.Disposable; + +/** + *
Base class for hint screens.
+ */ +public abstract class HintsOverlayBase implements Disposable{ + /** + *Renders the overlay.
+ * + * @param batch The {@link SpriteBatch} to use for rendering. + */ + public abstract void render(SpriteBatch batch); +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioGlobals.java b/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioGlobals.java index 474ab02..6670a38 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioGlobals.java +++ b/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioGlobals.java @@ -45,6 +45,7 @@ public abstract class ScenarioGlobals{ private static SummaryOverlayBase automaticActionSummaryOverlay = null; private static PlayerSystemBase playerSystem = null; private static SummaryOverlayBase scenarioSummaryOverlay = null; + private static HintsOverlayBase hintsOverlay = null; public static void init(NxtARCore core) throws IllegalArgumentException, InstantiationException, IllegalAccessException{ if(core == null) @@ -132,6 +133,18 @@ public abstract class ScenarioGlobals{ } } + if(hintsOverlay == null){ + try { + hintsOverlay = (HintsOverlayBase) ScenarioImplementation.hintsOverlayClass.newInstance(); + } catch (InstantiationException e) { + System.out.println("Error instantiating hints overlay."); + throw e; + } catch (IllegalAccessException e) { + System.out.println("Error accessing hints overlay."); + throw e; + } + } + playerSystem.setCore(core); gameWorld.setSystem(new MarkerPositioningSystem()); @@ -165,6 +178,7 @@ public abstract class ScenarioGlobals{ scenarioSummaryOverlay.dispose(); automaticActionSummaryOverlay.dispose(); entityCreator.dispose(); + hintsOverlay.dispose(); entityCreator = null; gameLogicSystem = null; @@ -173,6 +187,7 @@ public abstract class ScenarioGlobals{ automaticActionSummaryOverlay = null; playerSystem = null; scenarioSummaryOverlay = null; + hintsOverlay = null; System.gc(); } @@ -225,4 +240,11 @@ public abstract class ScenarioGlobals{ return scenarioSummaryOverlay; } + + public static HintsOverlayBase getHintsOverlay() throws IllegalStateException{ + if(hintsOverlay == null) + throw new IllegalStateException("Calling getHintsOverlay() before init."); + + return hintsOverlay; + } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioImplementation.java b/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioImplementation.java index 3d50517..62edff3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioImplementation.java +++ b/src/ve/ucv/ciens/ccg/nxtar/scenarios/ScenarioImplementation.java @@ -18,6 +18,7 @@ package ve.ucv.ciens.ccg.nxtar.scenarios; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameAutomaticActionPerformer; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameAutomaticActionSummaryOverlay; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameEntityCreator; +import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameInstructionsOverlay; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameLogicSystem; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGamePlayerSystem; import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameScenarioEndingOverlay; @@ -30,6 +31,7 @@ public final class ScenarioImplementation{ public static final Class automaticActionSummaryOverlay = BombGameAutomaticActionSummaryOverlay.class; public static final Class playerSystemClass = BombGamePlayerSystem.class; public static final Class scenarioSummaryOverlayClass = BombGameScenarioEndingOverlay.class; + public static final Class hintsOverlayClass = BombGameInstructionsOverlay.class; private ScenarioImplementation(){} } diff --git a/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameInstructionsOverlay.java b/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameInstructionsOverlay.java new file mode 100644 index 0000000..52a705c --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameInstructionsOverlay.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame; + +import ve.ucv.ciens.ccg.nxtar.scenarios.HintsOverlayBase; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; +import ve.ucv.ciens.ccg.nxtar.utils.Utils; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; + +public class BombGameInstructionsOverlay extends HintsOverlayBase { + private static final float CANNONICAL_SCREEN_WIDTH = 800.0f; + + private Texture inclinationBombTexture; + private Texture combinationBombTexture; + private Texture wireBombTexture; + private BitmapFont font; + private BitmapFont titleFont; + private Sprite inclinationBomb; + private Sprite combinationBomb; + private Sprite wireBomb; + private float inclinationX; + private float combinationX; + private float wireX; + private float inclinationY; + private float combinationY; + private float wireY; + private float titleWidth; + private float titleHeight; + + public BombGameInstructionsOverlay(){ + FreeTypeFontGenerator fontGenerator; + FreeTypeFontParameter fontParameters; + + inclinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/incl_bomb.png")); + combinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/comb_bomb.png")); + wireBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/wire_bomb.png")); + + inclinationBomb = new Sprite(inclinationBombTexture); + combinationBomb = new Sprite(combinationBombTexture); + wireBomb = new Sprite(wireBombTexture); + + inclinationBomb.setSize(inclinationBomb.getWidth() * 0.5f, inclinationBomb.getHeight() * 0.5f); + combinationBomb.setSize(combinationBomb.getWidth() * 0.5f, combinationBomb.getHeight() * 0.5f); + wireBomb.setSize(wireBomb.getWidth() * 0.5f, wireBomb.getHeight() * 0.5f); + + combinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - combinationBomb.getWidth(), -(combinationBomb.getHeight() / 2.0f)); + inclinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - inclinationBomb.getWidth(), combinationBomb.getY() + combinationBomb.getHeight() + 10.0f); + wireBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - wireBomb.getWidth(), combinationBomb.getY() - wireBomb.getHeight() - 10.0f); + + fontParameters = new FreeTypeFontParameter(); + fontParameters.characters = ProjectConstants.FONT_CHARS; + fontParameters.size = (int)((float)ProjectConstants.MENU_BUTTON_FONT_SIZE * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH)); + fontParameters.flip = false; + fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf")); + + font = fontGenerator.generateFont(fontParameters); + font.setColor(Color.YELLOW); + + fontParameters.size = (int)(90.0f * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH)); + titleFont = fontGenerator.generateFont(fontParameters); + + fontGenerator.dispose(); + + inclinationX = inclinationBomb.getX() + inclinationBomb.getWidth() + 15.0f; + combinationX = combinationBomb.getX() + combinationBomb.getWidth() + 15.0f; + wireX = wireBomb.getX() + wireBomb.getWidth() + 15.0f; + + inclinationY = inclinationBomb.getY() + (inclinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f); + combinationY = combinationBomb.getY() + (combinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f); + wireY = wireBomb.getY() + (wireBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f); + + titleWidth = titleFont.getBounds("Instructions").width; + titleHeight = titleFont.getBounds("Instructions").height; + } + + @Override + public void dispose() { + inclinationBombTexture.dispose(); + combinationBombTexture.dispose(); + wireBombTexture.dispose(); + font.dispose(); + titleFont.dispose(); + } + + @Override + public void render(SpriteBatch batch){ + String inclText = Utils.deviceHasOrientationSensors() ? "Balance your device" : "Always defuses."; + + inclinationBomb.draw(batch); + combinationBomb.draw(batch); + wireBomb.draw(batch); + + font.draw(batch, inclText, inclinationX, inclinationY); + font.draw(batch, "Blue, red, gray and green", combinationX, combinationY); + font.draw(batch, "Cut the blue wire.", wireX, wireY); + + titleFont.draw(batch, "Instructions", -(titleWidth / 2), (Utils.getScreenHeightWithOverscan() / 2) - titleHeight - 10); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameLogicSystem.java b/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameLogicSystem.java index adfdfd1..dfeb62b 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameLogicSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/scenarios/bombgame/BombGameLogicSystem.java @@ -227,10 +227,12 @@ public class BombGameLogicSystem extends GameLogicSystemBase { manager.remove(b, Integer.toString(marker.code)); b.deleteFromWorld(); - if(!Utils.isDeviceRollValid() || (Utils.isDeviceRollValid() && Math.abs(Gdx.input.getRoll()) > ProjectConstants.MAX_ABS_ROLL)){ - Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Inclination bomb exploded."); - createFadeOutEffect(); - reducePlayerLivesByOne(); + if(Utils.deviceHasOrientationSensors()){ + if(!Utils.isDeviceRollValid() || (Utils.isDeviceRollValid() && Math.abs(Gdx.input.getRoll()) > ProjectConstants.MAX_ABS_ROLL)){ + Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Inclination bomb exploded."); + createFadeOutEffect(); + reducePlayerLivesByOne(); + } } // Disable all related entities. @@ -363,7 +365,7 @@ public class BombGameLogicSystem extends GameLogicSystemBase { Gdx.app.log(TAG, CLASS_NAME + ".reducePlayerLivesByOne(): No players found."); } } - + /** *Disables all entities associated with the corresponding marker code.
* diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 798c1b4..2cdae95 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -124,6 +124,7 @@ public class InGameState extends BaseState{ private Texture correctAngleLedOnTexture; private Texture correctAngleLedOffTexture; private Texture orientationSliderTexture; + private Texture hintButtonTexture; // Gui renderable sprites. private Sprite motorAButton; @@ -142,6 +143,7 @@ public class InGameState extends BaseState{ private Sprite correctAngleLedOnSprite; private Sprite correctAngleLedOffSprite; private Sprite orientationSlider; + private Sprite hintButton; // Button touch helper fields. private boolean[] buttonsTouched; @@ -231,6 +233,16 @@ public class InGameState extends BaseState{ if(!Ouya.runningOnOuya) setUpButtons(); + // Set up the hint button. + // Set up the correct angle leds. + hintButtonTexture = new Texture(Gdx.files.internal("data/gfx/gui/help.png")); + hintButton = new Sprite(hintButtonTexture); + hintButton.setSize(hintButton.getWidth() * (Ouya.runningOnOuya ? 0.5f : 0.25f), hintButton.getHeight() * (Ouya.runningOnOuya ? 0.5f : 0.25f)); + if(!Ouya.runningOnOuya) + hintButton.setPosition(-(Gdx.graphics.getWidth() / 2) + 5, (Gdx.graphics.getHeight() / 2) - hintButton.getHeight() - 5); + else + hintButton.setPosition(-(Utils.getScreenWidthWithOverscan() / 2) + 5, -hintButton.getHeight() / 2); + // Set up the game world. gameWorld = ScenarioGlobals.getGameWorld(); @@ -443,6 +455,11 @@ public class InGameState extends BaseState{ }core.batch.end(); } + core.batch.setProjectionMatrix(pixelPerfectOrthographicCamera.combined); + core.batch.begin();{ + hintButton.draw(core.batch); + }core.batch.end(); + fadeEffectRenderingSystem.process(); playerSystem.process(); @@ -484,6 +501,9 @@ public class InGameState extends BaseState{ if(orientationSliderTexture != null) orientationSliderTexture.dispose(); + if(hintButtonTexture != null) + hintButtonTexture.dispose(); + if(backgroundShader != null) backgroundShader.dispose(); @@ -744,17 +764,20 @@ public class InGameState extends BaseState{ buttonPointers[7] = pointer; controlMode = controlMode.getValue() == robot_control_mode_t.WHEEL_CONTROL.getValue() ? robot_control_mode_t.ARM_CONTROL : robot_control_mode_t.WHEEL_CONTROL; + }else if(hintButton.getBoundingRectangle().contains(touchPointWorldCoords)){ + core.nextState = game_states_t.HINTS; }else{ + if(controlMode == robot_control_mode_t.ARM_CONTROL){ + touchPointWorldCoords.set(win2world.x, win2world.y); - touchPointWorldCoords.set(win2world.x, win2world.y); + if(frameBufferSprite != null && frameBufferSprite.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + "touchDown(): Touch point inside framebuffer."); + input = new TouchUserInput(); + robotArmPositioningSystem.setUserInput(input); - if(frameBufferSprite != null && frameBufferSprite.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + "touchDown(): Touch point inside framebuffer."); - input = new TouchUserInput(); - robotArmPositioningSystem.setUserInput(input); - - }else{ - Gdx.app.log(TAG, CLASS_NAME + "touchDown(): Touch point outside framebuffer."); + }else{ + Gdx.app.log(TAG, CLASS_NAME + "touchDown(): Touch point outside framebuffer."); + } } } @@ -1060,6 +1083,9 @@ public class InGameState extends BaseState{ if(keycode == Input.Keys.BACK){ core.nextState = game_states_t.MAIN_MENU; return true; + }else if(keycode == Input.Keys.F1){ + core.nextState = game_states_t.HINTS; + return true; } switch(keycode){ @@ -1223,7 +1249,9 @@ public class InGameState extends BaseState{ robotArmPositioningSystem.setUserInput(userInput); robotArmPositioningSystem.process(); - }else if(buttonCode == Ouya.BUTTON_A){ + }else if(buttonCode == Ouya.BUTTON_U){ + core.nextState = game_states_t.HINTS; + }else if(buttonCode == Ouya.BUTTON_A || buttonCode == Ouya.BUTTON_MENU){ core.nextState = game_states_t.MAIN_MENU; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InstructionsState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InstructionsState.java new file mode 100644 index 0000000..639f99f --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InstructionsState.java @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2013 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.states; + +import ve.ucv.ciens.ccg.nxtar.NxtARCore; +import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t; +import ve.ucv.ciens.ccg.nxtar.scenarios.HintsOverlayBase; +import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; +import ve.ucv.ciens.ccg.nxtar.utils.Utils; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.controllers.Controller; +import com.badlogic.gdx.controllers.mappings.Ouya; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.Texture.TextureWrap; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; +import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; + +public class InstructionsState extends BaseState { + private static final String TAG = "HINTS_STATE"; + private static final String CLASS_NAME = InstructionsState.class.getSimpleName(); + private static final String SHADER_PATH = "shaders/movingBckg/movingBckg"; + + // Helper fields. + private float u_scaling[]; + private float u_displacement; + + // Buttons and other gui components. + private TextButton continueButton; + private Rectangle continueButtonBBox; + private Sprite background; + private Texture backgroundTexture; + private ShaderProgram backgroundShader; + private Texture ouyaOButtonTexture; + private Sprite ouyaOButton; + private boolean oButtonPressed; + + // Graphic data for the start button. + private Texture buttonEnabledTexture; + private Texture buttonDisabledTexture; + private Texture buttonPressedTexture; + private BitmapFont font; + + // Overlay related fields. + HintsOverlayBase hintsOverlay; + + // Button touch helper fields. + private boolean continueButtonTouched; + private int continueButtonTouchPointer; + + public InstructionsState(NxtARCore core) throws IllegalArgumentException{ + TextButtonStyle textButtonStyle; + FreeTypeFontGenerator fontGenerator; + FreeTypeFontParameter fontParameters; + NinePatch buttonEnabled9p; + NinePatch buttonDisabled9p; + NinePatch buttonPressed9p; + + if(core == null) + throw new IllegalArgumentException(CLASS_NAME + ": Core is null."); + + this.core = core; + this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + oButtonPressed = false; + hintsOverlay = ScenarioGlobals.getHintsOverlay(); + + // Create the start button background. + buttonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png")); + buttonEnabled9p = new NinePatch(new TextureRegion(buttonEnabledTexture, 0, 0, buttonEnabledTexture.getWidth(), buttonEnabledTexture.getHeight()), 49, 49, 45, 45); + buttonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png")); + buttonDisabled9p = new NinePatch(new TextureRegion(buttonDisabledTexture, 0, 0, buttonDisabledTexture.getWidth(), buttonDisabledTexture.getHeight()), 49, 49, 45, 45); + buttonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png")); + buttonPressed9p = new NinePatch(new TextureRegion(buttonPressedTexture, 0, 0, buttonPressedTexture.getWidth(), buttonPressedTexture.getHeight()), 49, 49, 45, 45); + + // Create the start button font. + fontParameters = new FreeTypeFontParameter(); + fontParameters.characters = ProjectConstants.FONT_CHARS; + fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE; + fontParameters.flip = false; + fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf")); + font = fontGenerator.generateFont(fontParameters); + fontGenerator.dispose(); + + // Create the contine button. + textButtonStyle = new TextButtonStyle(); + textButtonStyle.font = font; + textButtonStyle.up = new NinePatchDrawable(buttonEnabled9p); + textButtonStyle.checked = new NinePatchDrawable(buttonPressed9p); + textButtonStyle.disabled = new NinePatchDrawable(buttonDisabled9p); + textButtonStyle.fontColor = new Color(Color.BLACK); + textButtonStyle.downFontColor = new Color(Color.WHITE); + textButtonStyle.disabledFontColor = new Color(Color.BLACK); + + continueButton = new TextButton("Continue", textButtonStyle); + continueButton.setText("Continue"); + continueButton.setPosition(-(continueButton.getWidth() / 2), -(Utils.getScreenHeightWithOverscan() / 2) + 10); + continueButtonBBox = new Rectangle(0, 0, continueButton.getWidth(), continueButton.getHeight()); + continueButtonBBox.setPosition(continueButton.getX(), continueButton.getY()); + + // Set OUYA's O button. + if(Ouya.runningOnOuya){ + ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png"); + ouyaOButton = new Sprite(ouyaOButtonTexture); + ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f); + oButtonPressed = false; + }else{ + ouyaOButtonTexture = null; + } + + // Set up the background. + backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png")); + backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); + backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + background = new Sprite(backgroundTexture); + background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); + + backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl")); + if(!backgroundShader.isCompiled()){ + Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader."); + Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); + backgroundShader = null; + } + + u_scaling = new float[2]; + u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f; + u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f; + u_displacement = 1.0f; + + win2world = new Vector3(0.0f, 0.0f, 0.0f); + touchPointWorldCoords = new Vector2(); + continueButtonTouched = false; + continueButtonTouchPointer = -1; + stateActive = false; + } + + @Override + public void render(float delta){ + Gdx.gl.glClearColor(1, 1, 1, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.begin();{ + + // Render background. + core.batch.disableBlending(); + drawBackground(core.batch); + core.batch.enableBlending(); + + hintsOverlay.render(core.batch); + + // Render buttons. + continueButton.draw(core.batch, 1.0f); + if(Ouya.runningOnOuya) + ouyaOButton.draw(core.batch); + + }core.batch.end(); + } + + @Override + public void dispose(){ + buttonEnabledTexture.dispose(); + buttonDisabledTexture.dispose(); + buttonPressedTexture.dispose(); + if(ouyaOButtonTexture != null) + ouyaOButtonTexture.dispose(); + backgroundTexture.dispose(); + if(backgroundShader != null) backgroundShader.dispose(); + font.dispose(); + } + + private void drawBackground(SpriteBatch batch){ + if(backgroundShader != null){ + batch.setShader(backgroundShader); + backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2); + backgroundShader.setUniformf("u_displacement", u_displacement); + } + background.draw(batch); + if(backgroundShader != null) batch.setShader(null); + u_displacement = u_displacement < 0.0f ? 1.0f : u_displacement - 0.0005f; + } + + @Override + public void onStateSet(){ + stateActive = true; + Gdx.input.setInputProcessor(this); + Gdx.input.setCatchBackKey(true); + Gdx.input.setCatchMenuKey(true); + } + + @Override + public void onStateUnset(){ + stateActive = false; + Gdx.input.setInputProcessor(null); + Gdx.input.setCatchBackKey(false); + Gdx.input.setCatchMenuKey(false); + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + unprojectTouch(screenX, screenY); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords)){ + continueButton.setChecked(true); + continueButtonTouched = true; + continueButtonTouchPointer = pointer; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed."); + } + + return true; + } + + @Override + public boolean touchUp(int screenX, int screenY, int pointer, int button){ + unprojectTouch(screenX, screenY); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords) && continueButtonTouched){ + continueButton.setChecked(false); + continueButtonTouched = false; + continueButtonTouchPointer = -1; + core.nextState = game_states_t.IN_GAME; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released."); + } + + return true; + } + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer){ + unprojectTouch(screenX, screenY); + + if(!continueButton.isDisabled() && continueButtonTouched && pointer == continueButtonTouchPointer && !continueButtonBBox.contains(touchPointWorldCoords)){ + continueButtonTouchPointer = -1; + continueButtonTouched = false; + continueButton.setChecked(false); + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released."); + } + + return true; + } + + @Override + public boolean keyDown(int keycode){ + if(keycode == Input.Keys.BACK){ + core.nextState = game_states_t.IN_GAME; + return true; + } + return false; + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; CONTROLLER LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean buttonDown(Controller controller, int buttonCode){ + if(stateActive){ + if(buttonCode == Ouya.BUTTON_O && !continueButton.isDisabled()){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed."); + oButtonPressed = true; + continueButton.setChecked(true); + } + return true; + }else{ + return false; + } + } + + @Override + public boolean buttonUp(Controller controller, int buttonCode){ + if(stateActive){ + if(buttonCode == Ouya.BUTTON_O){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released."); + if(oButtonPressed){ + oButtonPressed = false; + continueButton.setChecked(false); + core.nextState = game_states_t.IN_GAME; + } + } + return true; + }else{ + return false; + } + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/ScenarioEndSummaryState.java b/src/ve/ucv/ciens/ccg/nxtar/states/ScenarioEndSummaryState.java index ced6867..f94d916 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/ScenarioEndSummaryState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/ScenarioEndSummaryState.java @@ -49,8 +49,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; public class ScenarioEndSummaryState extends BaseState { - private static final String TAG = "AUTO_SUMMARY"; - private static final String CLASS_NAME = AutomaticActionSummaryState.class.getSimpleName(); + private static final String TAG = "SCENARIO_SUMMARY"; + private static final String CLASS_NAME = ScenarioEndSummaryState.class.getSimpleName(); private static final String SHADER_PATH = "shaders/movingBckg/movingBckg"; // Helper fields. diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/RobotArmPositioningSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/RobotArmPositioningSystem.java index fc59807..a1ff564 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/RobotArmPositioningSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/RobotArmPositioningSystem.java @@ -31,6 +31,7 @@ import com.artemis.Entity; import com.artemis.annotations.Mapper; import com.artemis.systems.EntityProcessingSystem; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.controllers.mappings.Ouya; import com.badlogic.gdx.math.Vector3; public class RobotArmPositioningSystem extends EntityProcessingSystem { @@ -82,6 +83,8 @@ public class RobotArmPositioningSystem extends EntityProcessingSystem { Gdx.app.log(TAG, CLASS_NAME + ".process(): Started moving from " + Utils.vector2String(auto.startPoint) + " to " + Utils.vector2String(auto.endPoint)); }else autoMove(geometry, auto, collision); + input = null; + }else if(input instanceof GamepadUserInput){ tempGP = (GamepadUserInput) input; @@ -89,12 +92,16 @@ public class RobotArmPositioningSystem extends EntityProcessingSystem { if(!tempGP.oButton){ geometry.position.x += -tempGP.axisLeftY * STEP_SIZE; geometry.position.y += tempGP.axisLeftX * STEP_SIZE; + if(Math.abs(tempGP.axisLeftX) < Ouya.STICK_DEADZONE && Math.abs(tempGP.axisLeftY) < Ouya.STICK_DEADZONE && Math.abs(tempGP.axisRightX) < Ouya.STICK_DEADZONE && Math.abs(tempGP.axisRightY) < Ouya.STICK_DEADZONE) + input = null; }else{ endPoint = new Vector3(geometry.position.x, geometry.position.y, MAX_Z); auto.startPoint.set(geometry.position); auto.endPoint.set(endPoint); auto.moving = true; auto.forward = true; + + input = null; } }else autoMove(geometry, auto, collision); @@ -116,11 +123,11 @@ public class RobotArmPositioningSystem extends EntityProcessingSystem { } }else autoMove(geometry, auto, collision); + input = null; + }else throw new ClassCastException("Input is not a valid UserInput instance."); } - - input = null; } private void autoMove(GeometryComponent geometry, AutomaticMovementComponent auto, CollisionDetectionComponent collision){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index beda501..c8e8470 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -28,14 +28,14 @@ public abstract class ProjectConstants{ public static final int EXIT_SUCCESS = 0; public static final int EXIT_FAILURE = 1; - public static final boolean DEBUG = true; + public static final boolean DEBUG = false; public static final int[] POWERS_OF_2 = {64, 128, 256, 512, 1024, 2048}; public static final float MAX_ABS_ROLL = 60.0f; public static final float OVERSCAN; public static final int MENU_BUTTON_FONT_SIZE; - public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:"; + public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:,"; public static final int MAXIMUM_NUMBER_OF_MARKERS = 5; public static final int CALIBRATION_PATTERN_POINTS = 54; diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/Utils.java b/src/ve/ucv/ciens/ccg/nxtar/utils/Utils.java index 677ab82..68f6bac 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/Utils.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/Utils.java @@ -52,16 +52,25 @@ public abstract class Utils{ return (int)(Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN); } + /** + *Checks if the running device posseses and accelerometer and compass.
+ * + * @return True when the device supports both sensors. False otherwise. + */ + public static boolean deviceHasOrientationSensors(){ + return Gdx.input.isPeripheralAvailable(Peripheral.Accelerometer) && Gdx.input.isPeripheralAvailable(Peripheral.Compass); + } + /** *Checks if the device's orientation is available and wihtin some arbitrary ranges.
* * @return True if the device can detect it's orientation and it's within range. False otherwise. */ public static boolean isDeviceRollValid(){ - boolean rollValid = Gdx.input.isPeripheralAvailable(Peripheral.Accelerometer) && Gdx.input.isPeripheralAvailable(Peripheral.Compass); + boolean rollValid = false; float azimuth, pitch; - if(rollValid){ + if(deviceHasOrientationSensors()){ azimuth = Gdx.input.getAzimuth(); pitch = Gdx.input.getPitch();