From 66e59057630a062d588733d16560dbb52157a113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20N=C3=B8rup?= Date: Thu, 26 Oct 2023 14:52:02 +0200 Subject: [PATCH 1/4] Added basic support for AI vs. AI --- src/main/java/dk/sdu/mmmi/Main.java | 3 +- .../modulemon/BattleScene/BattleView.java | 3 +- .../BattleSimulation/BattleSimulation.java | 79 ++++++++++++++----- .../IBattleSimulation.java | 7 +- .../CustomBattleView/CustomBattleView.java | 7 +- 5 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/main/java/dk/sdu/mmmi/Main.java b/src/main/java/dk/sdu/mmmi/Main.java index 72533b1c..11d76c76 100644 --- a/src/main/java/dk/sdu/mmmi/Main.java +++ b/src/main/java/dk/sdu/mmmi/Main.java @@ -13,7 +13,6 @@ import dk.sdu.mmmi.modulemon.Monster.MonsterRegistry; import dk.sdu.mmmi.modulemon.NPC.NPCControlSystem; import dk.sdu.mmmi.modulemon.NPC.NPCPlugin; -import dk.sdu.mmmi.modulemon.Player.Player; import dk.sdu.mmmi.modulemon.Player.PlayerControlSystem; import dk.sdu.mmmi.modulemon.Player.PlayerPlugin; import dk.sdu.mmmi.modulemon.Settings.Settings; @@ -37,7 +36,7 @@ public static void main(String[] args) throws IOException, URISyntaxException { var simpleBattleAI = new dk.sdu.mmmi.modulemon.SimpleAI.BattleAIFactory(); // Uncomment for Simple AI var battleSimulation = new BattleSimulation(); - battleSimulation.setAIFactory(battleAI); + battleSimulation.setOpponentAIFactory(battleAI); battleSimulation.setMonsterProcessor(battleMonsterProcessor); var battle = new BattleView(); diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java index bbfa5a8a..91cd4855 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java @@ -155,7 +155,8 @@ private void setBattleAIFactory() { desiredAI = new dk.sdu.mmmi.modulemon.BattleAI.BattleAIFactory(); ((BattleAIFactory) desiredAI).setSettingsService(settings); } - _battleSimulation.setAIFactory(desiredAI); + _battleSimulation.setOpponentAIFactory(desiredAI); + _battleSimulation.setPlayerAIFactory(null); // Null means the human controls the player. } @Override diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleSimulation/BattleSimulation.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleSimulation/BattleSimulation.java index 617469e4..3d1dd5a0 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleSimulation/BattleSimulation.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleSimulation/BattleSimulation.java @@ -16,8 +16,10 @@ public class BattleSimulation implements IBattleSimulation { private IBattleEvent nextEvent; private Runnable onNextEvent; - private IBattleAI AI; - private IBattleAIFactory AIFactory; + private IBattleAI opponentAI; + private IBattleAIFactory opponentAIFactory; + private IBattleAI playerAI; + private IBattleAIFactory playerAIFactory; private IBattleMonsterProcessor monsterProcessor; private ExecutorService AIExecutor = Executors.newFixedThreadPool(1); @@ -53,16 +55,16 @@ public void StartBattle(IBattleParticipant player, IBattleParticipant enemy) { this.battleState = new BattleState(player, enemy); this.battleState.setActiveParticipant(firstToTakeTurn); - if(AIFactory != null) - this.AI = AIFactory.getBattleAI(this, enemy); + if(opponentAIFactory != null) + this.opponentAI = opponentAIFactory.getBattleAI(this, enemy); if (!firstToTakeTurn.isPlayerControlled()) { nextEvent = new InfoBattleEvent("The opponent starts the battle", battleState.clone()); onNextEvent = () -> { battleState.setActiveParticipant(firstToTakeTurn); - if (getAI()!=null) { + if (getOpponentAI()!=null) { AIExecutor.execute(() -> { - getAI().doAction(); + getOpponentAI().doAction(); }); } else { nextEvent = new InfoBattleEvent("Waiting for an AI module", battleState.clone()); @@ -72,25 +74,25 @@ public void StartBattle(IBattleParticipant player, IBattleParticipant enemy) { nextEvent = new InfoBattleEvent("Player starts the battle", battleState.clone()); onNextEvent = () -> { battleState.setActiveParticipant(firstToTakeTurn); + doPlayerMove(); }; } - } private void switchTurns() { if (battleState.isPlayersTurn()) { - if (getAI()!=null) { + if (getOpponentAI()!=null) { battleState.setActiveParticipant(battleState.getEnemy()); AIExecutor.execute(() -> { - getAI().doAction(); + getOpponentAI().doAction(); }); } else { nextEvent = new InfoBattleEvent("Waiting for an AI module", battleState.clone()); } } else { battleState.setActiveParticipant(battleState.getPlayer()); + doPlayerMove(); } - } private String getActiveParticipantTitle() { @@ -123,8 +125,8 @@ public synchronized void doMove(IBattleParticipant battleParticipant, IMonsterMo IBattleParticipant opposingParticipant; if (battleParticipant.equals(battleState.getPlayer())) { - if (getAI()!=null) { - getAI().opposingMonsterUsedMove(source, move); + if (getOpponentAI()!=null) { + getOpponentAI().opposingMonsterUsedMove(source, move); } } @@ -259,14 +261,33 @@ public synchronized IBattleEvent getNextBattleEvent() { return event; } - private IBattleAI getAI() { - if (this.AI==null) { - if (this.AIFactory==null) { + private IBattleAI getOpponentAI() { + if (this.opponentAI ==null) { + if (this.opponentAIFactory ==null) { + return null; + } + this.opponentAI = this.opponentAIFactory.getBattleAI(this, battleState.getEnemy()); + } + return this.opponentAI; + } + + private IBattleAI getPlayerAI() { + if (this.playerAI ==null) { + if (this.playerAIFactory ==null) { return null; } - this.AI = this.AIFactory.getBattleAI(this, battleState.getEnemy()); + this.playerAI = this.playerAIFactory.getBattleAI(this, battleState.getPlayer()); + } + return this.playerAI; + } + + private void doPlayerMove(){ + // If player controlled, do nothing. Otherwise, call the player AI + if (getPlayerAI()!=null) { + AIExecutor.execute(() -> { + getPlayerAI().doAction(); + }); } - return this.AI; } public void setMonsterProcessor(IBattleMonsterProcessor monsterProcessor) { @@ -277,8 +298,26 @@ public void removeMonsterProcessor(IBattleMonsterProcessor monsterProcessor) { this.monsterProcessor = null; } - public void setAIFactory(IBattleAIFactory factory) { - this.AI = null; - this.AIFactory = factory; + public void setOpponentAIFactory(IBattleAIFactory factory) { + this.opponentAI = null; + this.opponentAIFactory = factory; + } + + public void setPlayerAIFactory(IBattleAIFactory factory) { + this.playerAI = null; + this.playerAIFactory = factory; + } + + public IBattleAIFactory getOpponentAIFactory() { + return opponentAIFactory; + } + + public IBattleAIFactory getPlayerAIFactory() { + return playerAIFactory; + } + + @Override + public boolean isPlayerControlledByAI() { + return this.playerAIFactory != null; } } diff --git a/src/main/java/dk/sdu/mmmi/modulemon/CommonBattleSimulation/IBattleSimulation.java b/src/main/java/dk/sdu/mmmi/modulemon/CommonBattleSimulation/IBattleSimulation.java index 86a932e2..1d0c860c 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/CommonBattleSimulation/IBattleSimulation.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/CommonBattleSimulation/IBattleSimulation.java @@ -25,5 +25,10 @@ public interface IBattleSimulation { */ IBattleEvent getNextBattleEvent(); - void setAIFactory(IBattleAIFactory BattleAIFactory); + boolean isPlayerControlledByAI(); + + void setOpponentAIFactory(IBattleAIFactory BattleAIFactory); + IBattleAIFactory getOpponentAIFactory(); + void setPlayerAIFactory(IBattleAIFactory BattleAIFactory); + IBattleAIFactory getPlayerAIFactory(); } diff --git a/src/main/java/dk/sdu/mmmi/modulemon/CustomBattleView/CustomBattleView.java b/src/main/java/dk/sdu/mmmi/modulemon/CustomBattleView/CustomBattleView.java index 2d4c8335..9fff7a49 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/CustomBattleView/CustomBattleView.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/CustomBattleView/CustomBattleView.java @@ -213,7 +213,7 @@ private void startBattle(IGameViewManager gameViewManager){ System.out.println("Using Team A AI: " + teamAAI); System.out.println("Using Team B AI: " + teamBAI); - battleSimulation.setAIFactory(teamBAI); + battleSimulation.setOpponentAIFactory(teamBAI); gameViewManager.setView(battleView.getGameView(), false); // Do not dispose the map customBattleMusic.stop(); @@ -227,7 +227,10 @@ private void startBattle(IGameViewManager gameViewManager){ }); // Set the battle AI after the startBattle method to override the configs. - battleSimulation.setAIFactory(teamBAI); + battleSimulation.setOpponentAIFactory(teamBAI); + if(teamAAI != null) { + battleSimulation.setPlayerAIFactory(teamAAI); + } } private void addToSelectedIndicies(Integer a) { From 5de6ffba7b55b0dd766addd61b09e46b2d6dcd00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20N=C3=B8rup?= Date: Thu, 26 Oct 2023 15:33:35 +0200 Subject: [PATCH 2/4] Added spectacting --- .../BattleScene/BattleSpeedController.java | 30 ++++++++ .../modulemon/BattleScene/BattleView.java | 70 ++++++++++++++++--- .../mmmi/modulemon/BattleScene/MenuState.java | 1 + .../BattleScene/scenes/BattleScene.java | 17 ++++- 4 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleSpeedController.java diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleSpeedController.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleSpeedController.java new file mode 100644 index 00000000..29d6fe79 --- /dev/null +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleSpeedController.java @@ -0,0 +1,30 @@ +package dk.sdu.mmmi.modulemon.BattleScene; + +import dk.sdu.mmmi.modulemon.common.drawing.MathUtils; + +public class BattleSpeedController { + + private static final int incrementAmount = 200; + private int speed = 1000; + + public void increaseSpeed(){ + speed +=incrementAmount; + } + + public void decreaseSpeed(){ + speed = Math.max(0, speed - incrementAmount); + } + + public void setSpeed(int speed){ + this.speed = Math.max(0, speed); + } + + public int getSpeed(){ + return speed; + } + + @Override + public String toString() { + return "Battle delay: " + speed + "ms"; + } +} diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java index 91cd4855..be30a49c 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java @@ -54,6 +54,7 @@ public class BattleView implements IGameViewService, IBattleView { private Sound _winSound; private Sound _loseSound; private MenuState menuState = MenuState.DEFAULT; + private BattleSpeedController forcedAIDelay; private Queue blockingAnimations; private Queue backgroundAnimations; private IMonsterRegistry monsterRegistry; @@ -134,6 +135,7 @@ public void startBattle(List playerMonsters, List enemyMonst _battleMusic.play(); _battleMusic.setLooping(true); menuState = MenuState.DEFAULT; + forcedAIDelay = new BattleSpeedController(); _battleScene.setActionTitle("Your actions:"); _battleScene.setActions(this.defaultActions); @@ -147,11 +149,11 @@ public void startBattle(List playerMonsters, List enemyMonst private void setBattleAIFactory() { IBattleAIFactory desiredAI; - if(settings.getSetting("AI").equals("MCTS")){ + if (settings.getSetting("AI").equals("MCTS")) { desiredAI = new MCTSBattleAIFactory(); - } else if(settings.getSetting("AI").equals("Simple")){ + } else if (settings.getSetting("AI").equals("Simple")) { desiredAI = new dk.sdu.mmmi.modulemon.SimpleAI.BattleAIFactory(); - } else { + } else { desiredAI = new dk.sdu.mmmi.modulemon.BattleAI.BattleAIFactory(); ((BattleAIFactory) desiredAI).setSettingsService(settings); } @@ -221,6 +223,11 @@ public void update(GameData gameData, IGameViewManager gameViewManager) { } stuckSince = 0; // No longer stuck. + var enemyAi = _battleSimulation.getOpponentAIFactory(); + var playerAi = _battleSimulation.getPlayerAIFactory(); + _battleScene.setEnemyControllerName(enemyAi == null ? "No AI" : enemyAi.toString()); + _battleScene.setPlayerControllerName(playerAi == null ? "Your monster" : playerAi.toString()); + if (settings != null) { if (_battleMusic.getVolume() != (int) settings.getSetting(SettingsRegistry.getInstance().getMusicVolumeSetting()) / 100f) { _battleMusic.setVolume((int) settings.getSetting(SettingsRegistry.getInstance().getMusicVolumeSetting()) / 100f); @@ -286,10 +293,12 @@ public void update(GameData gameData, IGameViewManager gameViewManager) { if (event.getUsingParticipant().isPlayerControlled()) { //Player attacked PlayerBattleAttackAnimation battleAnimation = new PlayerBattleAttackAnimation(_battleScene, getAttackSound(event.getMove()), settings); - battleAnimation.setOnEventDone(() -> { - addEmptyAnimation(1000, true); - _battleScene.setTextToDisplay("..."); - }); + if (forcedAIDelay.getSpeed() > 0) { + battleAnimation.setOnEventDone(() -> { + addEmptyAnimation(forcedAIDelay.getSpeed(), true); + _battleScene.setTextToDisplay("..."); + }); + } battleAnimation.start(); blockingAnimations.add(battleAnimation); _battleScene.setHealthIndicatorText(String.format("-%d HP", event.getDamage())); @@ -297,6 +306,12 @@ public void update(GameData gameData, IGameViewManager gameViewManager) { //Enemy attacked EnemyBattleAttackAnimation battleAnimation = new EnemyBattleAttackAnimation(_battleScene, getAttackSound(event.getMove()), settings); battleAnimation.start(); + if (_battleSimulation.isPlayerControlledByAI() && forcedAIDelay.getSpeed() > 0) { + battleAnimation.setOnEventDone(() -> { + addEmptyAnimation(forcedAIDelay.getSpeed(), true); + _battleScene.setTextToDisplay("..."); + }); + } blockingAnimations.add(battleAnimation); _battleScene.setHealthIndicatorText(String.format("-%d HP", event.getDamage())); } @@ -420,11 +435,23 @@ public void draw(GameData gameData) { @Override public void handleInput(GameData gameData, IGameViewManager gameViewManager) { - if (!blockingAnimations.isEmpty() || !_isInitialized || (_battleSimulation != null && _battleSimulation.getState() != null && !_battleSimulation.getState().isPlayersTurn())) { + if (_battleSimulation != null && _battleSimulation.isPlayerControlledByAI()) { + menuState = MenuState.SPECTATOR; + } + + if ( + ( + !blockingAnimations.isEmpty() + || !_isInitialized + || (_battleSimulation != null && _battleSimulation.getState() != null && !_battleSimulation.getState().isPlayersTurn()) + ) + && menuState != MenuState.SPECTATOR // Always show the UI when spectating + ) { //If any blocking animations, don't allow any input. _battleScene.setActionBoxAlpha(0.5f); return; } + _battleScene.setActionBoxAlpha(1f); GameKeys keys = gameData.getKeys(); @@ -524,6 +551,33 @@ public void handleInput(GameData gameData, IGameViewManager gameViewManager) { _battleScene.setTextToDisplay("This monster is already in battle."); } } + } else if (this.menuState == MenuState.SPECTATOR) { + _battleScene.setActionTitle("Spectating"); + IBattleParticipant player = _battleSimulation.getState().getPlayer(); + Object[] menuOptions = new Object[]{ + forcedAIDelay, + "Quit spectating" + }; + + _battleScene.setActions(menuOptions); + + //Get selected monster + Object selectedAction = menuOptions[this.selectedAction % menuOptions.length]; + if (selectedAction instanceof String action) { + if (action.equalsIgnoreCase("Quit spectating")) { + if (keys.isPressed(GameKeys.ACTION)) { + handleBattleEnd(new VictoryBattleEvent("Player runs away", _battleSimulation.getState().getEnemy(), null)); + } + } + } else if (selectedAction instanceof BattleSpeedController speed) { + if (keys.isPressed(GameKeys.RIGHT)) { + speed.increaseSpeed(); + } else if (keys.isPressed(GameKeys.LEFT)) { + speed.decreaseSpeed(); + } else if (keys.isPressed(GameKeys.DELETE)) { + speed.setSpeed(0); + } + } } diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/MenuState.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/MenuState.java index 1d0f8fde..5acb9c0e 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/MenuState.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/MenuState.java @@ -4,5 +4,6 @@ public enum MenuState { DEFAULT, FIGHT, SWITCH, + SPECTATOR, NONE } diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java index cfdc0244..30b9672e 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java @@ -43,11 +43,12 @@ public class BattleScene { private Rectangle _playerHPBoxFillRect; private Rectangle _playerHPBoxBorderRect; private float _actionBoxAlpha = 1; - + private String enemyControllerName; private String enemyMonsterName; private int enemyHP; private float intermediateEnemyHP = 0f; private int maxEnemyHP; + private String playerControllerName; private String playerMonsterName; private int playerHP; private float intermediatePlayerHP = 0f; @@ -80,6 +81,8 @@ public BattleScene() { _enemyHPBoxFillRect = new Rectangle(-100,-100, 0, 0); spriteBatch = new SpriteBatch(); shapeRenderer = new ShapeRenderer(); + playerControllerName = "Your monster"; + enemyControllerName = "Opponent"; resetPositions(); } @@ -170,10 +173,10 @@ public void draw(float dt, OrthographicCamera camera) { spriteBatch.begin(); //Health box - textUtils.drawNormalRoboto(spriteBatch, "Opponent: " + this.enemyMonsterName, Color.BLACK, _enemyHealthBoxPosition.getX() + 10, _enemyHealthBoxPosition.getY() + 85); + textUtils.drawNormalRoboto(spriteBatch, this.enemyControllerName+": " + this.enemyMonsterName, Color.BLACK, _enemyHealthBoxPosition.getX() + 10, _enemyHealthBoxPosition.getY() + 85); textUtils.drawNormalRoboto(spriteBatch, "HP:", Color.BLACK, _enemyHealthBoxPosition.getX() + 10, _enemyHealthBoxPosition.getY() + 55); textUtils.drawNormalRoboto(spriteBatch, this.enemyHP+"/"+this.maxEnemyHP, Color.BLACK, _enemyHealthBoxPosition.getX() + 52, _enemyHealthBoxPosition.getY() + 28); - textUtils.drawNormalRoboto(spriteBatch, "Your monster: " + this.playerMonsterName, Color.BLACK, _playerHealthBoxPosition.getX() + 10, _playerHealthBoxPosition.getY() + 85); + textUtils.drawNormalRoboto(spriteBatch, this.playerControllerName+": " + this.playerMonsterName, Color.BLACK, _playerHealthBoxPosition.getX() + 10, _playerHealthBoxPosition.getY() + 85); textUtils.drawNormalRoboto(spriteBatch, "HP:", Color.BLACK, _playerHealthBoxPosition.getX() + 10, _playerHealthBoxPosition.getY() + 55); textUtils.drawNormalRoboto(spriteBatch, this.playerHP+"/"+this.maxPlayerHP, Color.BLACK, _playerHealthBoxPosition.getX() + 52, _playerHealthBoxPosition.getY() + 28); @@ -279,6 +282,14 @@ public void setEnemyMonsterName(String enemyMonsterName) { this.enemyMonsterName = enemyMonsterName; } + public void setEnemyControllerName(String enemyControllerName) { + this.enemyControllerName = enemyControllerName; + } + + public void setPlayerControllerName(String playerControllerName) { + this.playerControllerName = playerControllerName; + } + public void setEnemyHP(int enemyHP) { this.enemyHP = enemyHP; } From f113e04e00b7ecf651945e412d92ab3bafe23fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20N=C3=B8rup?= Date: Thu, 26 Oct 2023 15:43:32 +0200 Subject: [PATCH 3/4] Make text boxes bigger to hold "Monte-Carlo Tree Search". Maybe just MCTS? --- .../mmmi/modulemon/BattleScene/scenes/BattleScene.java | 2 +- .../modulemon/BattleScene/scenes/BattleSceneDefaults.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java index 30b9672e..9c400e3e 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java @@ -234,7 +234,7 @@ private static void setHpBarDimentions(float hp, int maxHp, Position basePositio float hpBarOffsetX = 58; float hpBarOffsetY = 35; float hpBarHeight = 20; - float hpBarFullWidth = 225; + float hpBarFullWidth = 290; float hpBasedWidth = MathUtils.map(hp, 0, maxHp, 0, hpBarFullWidth); fillRect.setX(basePosition.getX() + hpBarOffsetX); diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleSceneDefaults.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleSceneDefaults.java index 3bca7ee6..6c8fc7aa 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleSceneDefaults.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleSceneDefaults.java @@ -11,11 +11,11 @@ public class BattleSceneDefaults { public static Position enemyBasePosition(){ return new Position(800, 400);} public static Position enemyMonsterPosition(){return new Position(850, 450);} public static Position playerMonsterPosition () {return new Position(320, 100);} - public static Position enemyHealthBoxPosition(){ return new Position(480, 550);} - public static float enemyHealthBoxWidth(){return 300f;} + public static Position enemyHealthBoxPosition(){ return new Position(430, 550);} + public static float enemyHealthBoxWidth(){return 380f;} public static float enemyHealthBoxHeight(){return 100f;} - public static Position playerHealthBoxPosition(){ return new Position(100, 300);} - public static float playerHealthBoxWidth(){return 350f;} + public static Position playerHealthBoxPosition(){ return new Position(60, 300);} + public static float playerHealthBoxWidth(){return 400f;} public static float playerHealthBoxHeight(){return 100f;} public static Position actionBoxPosition(float gameWidth){return new Position(gameWidth - 300, 155); } public static float actionBoxWidth(){return 250f;} From bb231c42bb7b2e0988f5b992f7c34a183d535eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20N=C3=B8rup?= Date: Thu, 26 Oct 2023 16:11:28 +0200 Subject: [PATCH 4/4] Added a crude spinner.. Don't know if I like it... --- .../modulemon/BattleScene/BattleView.java | 13 ++++--- .../BattleScene/scenes/BattleScene.java | 34 ++++++++++++++++++ src/main/resources/battleart/spinner.png | Bin 0 -> 705 bytes 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/battleart/spinner.png diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java index be30a49c..d76cdb38 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/BattleView.java @@ -295,8 +295,9 @@ public void update(GameData gameData, IGameViewManager gameViewManager) { PlayerBattleAttackAnimation battleAnimation = new PlayerBattleAttackAnimation(_battleScene, getAttackSound(event.getMove()), settings); if (forcedAIDelay.getSpeed() > 0) { battleAnimation.setOnEventDone(() -> { - addEmptyAnimation(forcedAIDelay.getSpeed(), true); - _battleScene.setTextToDisplay("..."); + var anim = addEmptyAnimation(forcedAIDelay.getSpeed(), true); + anim.setOnEventDone(() -> _battleScene.setShowEnemySpinner(false)); + _battleScene.setShowEnemySpinner(true); }); } battleAnimation.start(); @@ -308,8 +309,9 @@ public void update(GameData gameData, IGameViewManager gameViewManager) { battleAnimation.start(); if (_battleSimulation.isPlayerControlledByAI() && forcedAIDelay.getSpeed() > 0) { battleAnimation.setOnEventDone(() -> { - addEmptyAnimation(forcedAIDelay.getSpeed(), true); - _battleScene.setTextToDisplay("..."); + var anim = addEmptyAnimation(forcedAIDelay.getSpeed(), true); + anim.setOnEventDone(() -> _battleScene.setShowPlayerSpinner(false)); + _battleScene.setShowPlayerSpinner(true); }); } blockingAnimations.add(battleAnimation); @@ -615,11 +617,12 @@ public void dispose() { this._isInitialized = false; } - private void addEmptyAnimation(int duration, boolean autoStart) { + private EmptyAnimation addEmptyAnimation(int duration, boolean autoStart) { EmptyAnimation emptyAnimation = new EmptyAnimation(duration); if (autoStart) emptyAnimation.start(); blockingAnimations.add(emptyAnimation); + return emptyAnimation; } public void setSettingsService(IGameSettings settings) { diff --git a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java index 9c400e3e..e992ea19 100644 --- a/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java +++ b/src/main/java/dk/sdu/mmmi/modulemon/BattleScene/scenes/BattleScene.java @@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.scenes.scene2d.ui.Image; +import dk.sdu.mmmi.modulemon.BattleScene.BattleView; import dk.sdu.mmmi.modulemon.common.AssetLoader; import dk.sdu.mmmi.modulemon.common.drawing.*; @@ -15,6 +16,11 @@ public class BattleScene { private Image _backdrop; private Image _playerBase; private Image _enemyBase; + private float _spinnerSpeed = -100f; + private Image _playerSpinner; + private Image _enemySpinner; + private boolean _showPlayerSpinner; + private boolean _showEnemySpinner; private String _playerMonsterSpritePath = ""; private String _enemyMonsterSpritePath = ""; private Image _playerMonster; @@ -71,6 +77,8 @@ public BattleScene() { _backdrop = loader.getImageAsset("/battleart/backdrop1.png", this.getClass()); _playerBase = loader.getImageAsset("/battleart/playerbase1.png", this.getClass()); _enemyBase = loader.getImageAsset("/battleart/enemybase1.png", this.getClass()); + _playerSpinner = loader.getImageAsset("/battleart/spinner.png", this.getClass()); + _enemySpinner = loader.getImageAsset("/battleart/spinner.png", BattleView.class); _textBoxRect = new Rectangle(-100,-100, 0,0); // All these values are dynamically calculated anyway _actionBoxRect = new Rectangle(-100,-100, BattleSceneDefaults.actionBoxWidth(), BattleSceneDefaults.actionBoxHeight()); _enemyHealthRect = new Rectangle(-100,-100, BattleSceneDefaults.enemyHealthBoxWidth(), BattleSceneDefaults.enemyHealthBoxHeight()); @@ -99,11 +107,17 @@ public void draw(float dt, OrthographicCamera camera) { _playerMonster.setOrigin(_playerMonster.getImageWidth() / 2, _playerMonster.getImageHeight() / 2); _playerMonster.setRotation(_playerMonsterRotation); _playerMonsterPosition.updatePosition(_playerMonster); + + _playerSpinner.setOrigin(_playerSpinner.getImageWidth() / 2, _playerSpinner.getImageHeight() / 2); + _playerSpinner.setPosition(_playerBasePosition.getX() + _playerBase.getImageWidth()/2f - _playerSpinner.getImageWidth()/2f, _playerBasePosition.getY()+160); } if(_enemyMonster != null) { _enemyMonster.setOrigin(_enemyMonster.getImageWidth() / 2, _enemyMonster.getImageHeight() / 2); _enemyMonster.setRotation(_enemyMonsterRotation); _enemyMonsterPosition.updatePosition(_enemyMonster); + + _enemySpinner.setOrigin(_enemySpinner.getImageWidth() / 2, _enemySpinner.getImageHeight() / 2); + _enemySpinner.setPosition(_enemyBasePosition.getX() + _enemyBase.getImageWidth()/2f - _enemySpinner.getImageWidth()/2f, _enemyBasePosition.getY()+100); } _backdrop.setSize(this.gameWidth, this.gameHeight); @@ -117,6 +131,16 @@ public void draw(float dt, OrthographicCamera camera) { if (_enemyMonster != null) _enemyMonster.draw(spriteBatch, 1); + if(_showPlayerSpinner){ + _playerSpinner.rotateBy(_spinnerSpeed * dt); + _playerSpinner.draw(spriteBatch, 1); + } + + if(_showEnemySpinner){ + _enemySpinner.rotateBy(_spinnerSpeed * dt); + _enemySpinner.draw(spriteBatch, 1); + } + spriteBatch.end(); @@ -523,6 +547,14 @@ public void setTextBoxPosition(Position pos) { this._textBoxPosition = pos; } + public void setShowPlayerSpinner(boolean _showPlayerSpinner) { + this._showPlayerSpinner = _showPlayerSpinner; + } + + public void setShowEnemySpinner(boolean _showEnemySpinner) { + this._showEnemySpinner = _showEnemySpinner; + } + public void resetPositions() { _backdropPosition = BattleSceneDefaults.backdropPosition(); _playerBasePosition = BattleSceneDefaults.playerBasePosition(); @@ -537,5 +569,7 @@ public void resetPositions() { _healthIndicatorColor = BattleSceneDefaults.healthIndicatorColor(); _enemyMonsterRotation = BattleSceneDefaults.enemyMonsterRotation(); _playerMonsterRotation = BattleSceneDefaults.playerMonsterRotation(); + _showEnemySpinner = false; + _showPlayerSpinner = false; } } diff --git a/src/main/resources/battleart/spinner.png b/src/main/resources/battleart/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb17974a39af8c497bbb677443a5c940b6430e0 GIT binary patch literal 705 zcmV;y0zUnTP)%W|d7cL`K3Z#C4eL9I{4TndMWa`1{JX!U3dt)1=y{$BAm0td zRUWIs_|6cna$5n%0iop@2ZRaD(9S~Y>F<@wEH(+Q%F<@vxF<@vx zX}#Y=R>HV5h-NL8E+DhTj+(_}fbC9L)-bu}0RhE`6#qiE%B%x1eI)0UhSxf(FEa<R}71&9AG4v_7WXHa0d<{B7xuz98wp^r{f3i zz##x3k^rH*!Xfp6^j10U7#oeVPUx}-fB=L52tWvc0E7StKnQ>k07(+Bg~3#dS;~u< zBaX4fAz~l_!WdG&$^n8y2!Issu9#)v5ZnO}9D+MO9X|kqLvY7CcK}3WApaeq|5G3N z=lor^tcEYYS8K@VQ!cnaL`;iS5t2#6yI#X8Rab@Ft*S89oUg`It6Xi_V1!S5uY{`3 zz*ZKG?J9hBPIrq>W*g9Iw?r1l6K!()vZ@`%|5T5wb{X4VS8*iRxtR4rm!7=SZ6$p) zK#E_>G!)3|fm{kU-qE(|!N3T54*|;9w%{}%v5AMNC6p0_$?f8bFd#d*B}$`5 zCtPi699?YOA0np3X9~&cmYGH6D}-eMv%=lW?=e(^v*pE-imp)^>trt{R{L nHsYiN^+