diff --git a/.idea/dictionaries/bruteus.xml b/.idea/dictionaries/bruteus.xml index cdfafde..b849076 100644 --- a/.idea/dictionaries/bruteus.xml +++ b/.idea/dictionaries/bruteus.xml @@ -3,6 +3,7 @@ bomberman boomerman + insta \ No newline at end of file diff --git a/.idea/dictionaries/krzys.xml b/.idea/dictionaries/krzys.xml index 1816391..648033a 100644 --- a/.idea/dictionaries/krzys.xml +++ b/.idea/dictionaries/krzys.xml @@ -1,6 +1,7 @@ + dropoff gson interp diff --git a/.idea/misc.xml b/.idea/misc.xml index f838eed..0bd50d6 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,12 +8,13 @@ + - + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 42bcbd0..ee70459 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ allprojects { } group 'com.cyberbot.bomberman' - version '1.0.0-alpha' + version '1.0.0-release' ext { appName = "bomberman" diff --git a/client/core/assets/Icon.png b/client/core/assets/Icon.png new file mode 100644 index 0000000..8595413 Binary files /dev/null and b/client/core/assets/Icon.png differ diff --git a/client/core/assets/Texture_Pack.png b/client/core/assets/Texture_Pack.png deleted file mode 100644 index 490047b..0000000 Binary files a/client/core/assets/Texture_Pack.png and /dev/null differ diff --git a/client/core/assets/map/bomberman_main.tmx b/client/core/assets/map/bomberman_main.tmx index 27658b0..d5fdde5 100644 --- a/client/core/assets/map/bomberman_main.tmx +++ b/client/core/assets/map/bomberman_main.tmx @@ -22,24 +22,24 @@ -0,0,0,3,3,3,3,3,3,0,0,0,0,0,0, -0,0,0,0,3,3,3,3,18,0,0,19,0,0,0, -14,0,0,3,3,3,3,17,0,0,0,4,0,0,0, -3,14,0,3,3,16,0,0,0,0,0,25,4,26,0, -3,3,3,17,3,0,0,0,0,0,0,0,0,0,0, -3,3,18,0,0,0,0,0,0,0,0,0,0,0,0, -3,17,3,0,0,0,0,0,0,0,0,0,0,21,4, -3,0,0,0,0,13,3,14,0,0,0,0,27,4,4, -3,0,0,0,0,3,3,3,0,0,0,0,4,4,4, -0,0,0,0,0,15,3,16,0,0,0,19,4,4,4, -0,0,0,0,0,0,0,21,0,21,4,4,4,4,4, -0,0,0,0,0,0,27,4,4,4,4,4,4,4,4, -0,0,0,0,0,0,0,4,4,4,4,4,4,0,4, -0,0,0,0,0,0,27,4,4,4,4,4,0,0,4, -0,0,0,0,0,0,4,4,4,4,4,4,4,4,4 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,27,4,28,0,0,0,0,0,0, +0,0,0,0,0,19,0,4,0,0,0,0,0,0,0, +0,0,0,0,27,4,4,4,28,0,0,0,0,0,0, +0,0,0,19,0,4,0,22,0,0,0,23,0,0,0, +0,0,27,4,4,4,28,0,0,0,13,3,14,0,0, +0,19,0,4,0,22,0,0,0,23,0,3,0,0,0, +0,4,4,4,28,0,0,0,24,3,3,3,3,18,0, +0,22,0,22,0,0,0,0,0,17,0,3,0,0,0, +0,0,0,0,0,0,0,0,0,0,15,3,16,0,0, +0,0,0,0,0,21,0,0,0,0,0,17,0,0,0, +0,0,0,0,27,4,28,0,0,0,0,0,0,0,0, +0,0,0,0,0,4,0,20,0,0,0,0,0,0,0, +0,0,0,0,27,4,4,4,4,4,28,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,10, 7,0,0,5,5,6,5,5,5,5,5,5,0,0,7, diff --git a/client/core/assets/skins/skin.atlas b/client/core/assets/skins/skin.atlas index 7a083ac..37a9d86 100644 --- a/client/core/assets/skins/skin.atlas +++ b/client/core/assets/skins/skin.atlas @@ -6,7 +6,7 @@ filter: Nearest,Nearest repeat: none button_checked rotate: false - xy: 68, 54 + xy: 68, 36 size: 16, 16 split: 3, 3, 3, 3 orig: 16, 16 @@ -28,6 +28,14 @@ button_up orig: 16, 16 offset: 0, 0 index: -1 +label_background + rotate: false + xy: 68, 54 + size: 16, 16 + split: 0, 17, 0, 17 + orig: 16, 16 + offset: 0, 0 + index: -1 placeholder rotate: false xy: 68, 108 @@ -53,7 +61,7 @@ progress_bar_fill index: -1 separator rotate: false - xy: 68, 36 + xy: 68, 18 size: 16, 16 split: 1, 1, 1, 1 orig: 16, 16 diff --git a/client/core/assets/skins/skin.png b/client/core/assets/skins/skin.png index f97e4cd..edb300d 100644 Binary files a/client/core/assets/skins/skin.png and b/client/core/assets/skins/skin.png differ diff --git a/client/core/assets/textures/bomberman.atlas b/client/core/assets/textures/bomberman.atlas index fa51f04..d1c6bac 100644 --- a/client/core/assets/textures/bomberman.atlas +++ b/client/core/assets/textures/bomberman.atlas @@ -1,355 +1,446 @@ bomberman.png -size: 678,54 +size: 211,211 format: RGBA8888 filter: Nearest,Nearest repeat: none ArrowFast rotate: false - xy: 288, 2 + xy: 132, 55 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +Bomb + rotate: false + xy: 132, 3 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 1 +Bomb + rotate: false + xy: 158, 29 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 2 +Bomb + rotate: false + xy: 184, 55 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 3 +BombStatic + rotate: false + xy: 132, 107 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +Boom + rotate: false + xy: 28, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Box1 rotate: false - xy: 392, 28 + xy: 158, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Box2 rotate: false - xy: 392, 2 + xy: 184, 107 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +CDR + rotate: false + xy: 54, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Dynamite rotate: false - xy: 314, 2 + xy: 28, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 - index: 3 + index: 2 Dynamite rotate: false - xy: 366, 28 + xy: 80, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: 1 Dynamite rotate: false - xy: 418, 28 + xy: 80, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 - index: 2 + index: 3 DynamiteStatic rotate: false - xy: 54, 2 + xy: 2, 132 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +FastBoom + rotate: false + xy: 184, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Floor rotate: false - xy: 470, 28 + xy: 158, 55 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +FrozenTint + rotate: false + xy: 132, 81 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +Fryzjer + rotate: false + xy: 106, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice rotate: false - xy: 444, 2 + xy: 132, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice1 rotate: false - xy: 288, 28 + xy: 54, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice2 rotate: false - xy: 652, 28 + xy: 184, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice3 rotate: false - xy: 132, 2 + xy: 106, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice4 rotate: false - xy: 2, 27 + xy: 2, 184 size: 24, 25 orig: 24, 25 offset: 0, 0 index: -1 Ice5 rotate: false - xy: 444, 28 + xy: 132, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice6 rotate: false - xy: 340, 28 + xy: 2, 28 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice7 rotate: false - xy: 522, 28 + xy: 28, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Ice8 rotate: false - xy: 470, 2 + xy: 54, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava rotate: false - xy: 28, 28 + xy: 2, 158 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava1 rotate: false - xy: 496, 2 + xy: 80, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava2 rotate: false - xy: 496, 28 + xy: 106, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava3 rotate: false - xy: 522, 2 + xy: 132, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava4 rotate: false - xy: 366, 2 + xy: 106, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava5 rotate: false - xy: 548, 2 + xy: 2, 2 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava6 rotate: false - xy: 574, 28 + xy: 28, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava7 rotate: false - xy: 574, 2 + xy: 54, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Lava8 rotate: false - xy: 600, 28 + xy: 80, 81 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +Nuke + rotate: false + xy: 80, 55 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 3 +Nuke + rotate: false + xy: 106, 55 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 2 +Nuke + rotate: false + xy: 184, 81 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: 1 +NukeStatic + rotate: false + xy: 106, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_bbb_idle_back rotate: false - xy: 262, 2 + xy: 80, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_bbb_idle_front rotate: false - xy: 600, 2 + xy: 106, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_bbb_idle_left rotate: false - xy: 548, 28 + xy: 158, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_bbb_idle_right rotate: false - xy: 184, 28 + xy: 54, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_brw_idle_back rotate: false - xy: 210, 2 + xy: 2, 54 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_brw_idle_front rotate: false - xy: 210, 28 + xy: 80, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_brw_idle_left rotate: false - xy: 626, 2 + xy: 132, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_brw_idle_right rotate: false - xy: 80, 28 + xy: 80, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wbw_idle_back rotate: false - xy: 28, 2 + xy: 158, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wbw_idle_front rotate: false - xy: 184, 2 + xy: 28, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wbw_idle_left rotate: false - xy: 340, 2 + xy: 106, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wbw_idle_right rotate: false - xy: 54, 28 + xy: 28, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wrb_idle_back rotate: false - xy: 236, 2 + xy: 158, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wrb_idle_front rotate: false - xy: 236, 28 + xy: 158, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wrb_idle_left rotate: false - xy: 262, 28 + xy: 184, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Player_wrb_idle_right rotate: false - xy: 626, 28 + xy: 28, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Shield rotate: false - xy: 418, 2 + xy: 2, 106 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall1 rotate: false - xy: 80, 2 + xy: 158, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall2 rotate: false - xy: 106, 28 + xy: 54, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall3 rotate: false - xy: 106, 2 + xy: 184, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall4 rotate: false - xy: 132, 28 + xy: 28, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall5 rotate: false - xy: 314, 28 + xy: 54, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall6 rotate: false - xy: 158, 28 + xy: 54, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 Wall7 rotate: false - xy: 158, 2 + xy: 2, 80 size: 24, 24 orig: 24, 24 offset: 0, 0 diff --git a/client/core/assets/textures/bomberman.png b/client/core/assets/textures/bomberman.png index 368b873..bee93b6 100644 Binary files a/client/core/assets/textures/bomberman.png and b/client/core/assets/textures/bomberman.png differ diff --git a/client/core/assets/textures/bomberman_player.atlas b/client/core/assets/textures/bomberman_player.atlas deleted file mode 100644 index 71b1e09..0000000 --- a/client/core/assets/textures/bomberman_player.atlas +++ /dev/null @@ -1,69 +0,0 @@ - -bomberman_player.png -size: 216,24 -format: RGBA8888 -filter: Nearest,Nearest -repeat: none -moving_back - rotate: false - xy: 0, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 1 -moving_back - rotate: false - xy: 24, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 2 -moving_front - rotate: false - xy: 48, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 1 -moving_front - rotate: false - xy: 72, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 2 -moving_side - rotate: false - xy: 96, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 1 -moving_side - rotate: false - xy: 120, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: 2 -standing_back - rotate: false - xy: 144, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -standing_front - rotate: false - xy: 168, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -standing_side - rotate: false - xy: 192, 0 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 diff --git a/client/core/assets/textures/bomberman_player.png b/client/core/assets/textures/bomberman_player.png deleted file mode 100644 index 8996e52..0000000 Binary files a/client/core/assets/textures/bomberman_player.png and /dev/null differ diff --git a/client/core/assets/textures/menu_bg.png b/client/core/assets/textures/menu_bg.png index a00c89d..d0225e5 100644 Binary files a/client/core/assets/textures/menu_bg.png and b/client/core/assets/textures/menu_bg.png differ diff --git a/client/core/assets/textures/player.png b/client/core/assets/textures/player.png deleted file mode 100644 index 39e351a..0000000 Binary files a/client/core/assets/textures/player.png and /dev/null differ diff --git a/client/core/build.gradle b/client/core/build.gradle index 04124b8..36e4ef7 100644 --- a/client/core/build.gradle +++ b/client/core/build.gradle @@ -1,7 +1,7 @@ apply plugin: "java" apply plugin: 'org.jetbrains.kotlin.jvm' -sourceCompatibility = 1.8 +sourceCompatibility = 13 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' sourceSets.main.java.srcDirs = [ "src/" ] diff --git a/client/core/src/com/cyberbot/bomberman/Client.java b/client/core/src/com/cyberbot/bomberman/Client.java index 8513750..9f00e59 100644 --- a/client/core/src/com/cyberbot/bomberman/Client.java +++ b/client/core/src/com/cyberbot/bomberman/Client.java @@ -1,25 +1,18 @@ package com.cyberbot.bomberman; import com.badlogic.gdx.Game; -import com.badlogic.gdx.Gdx; import com.cyberbot.bomberman.controllers.ScreenController; public class Client extends Game { - - public static final float V_WIDTH = 100; - public static final float V_HEIGHT = 100; - - private ScreenController gsm; + private ScreenController screenController; @Override public void create() { - final float w = Gdx.graphics.getWidth(); - final float h = Gdx.graphics.getHeight(); - - gsm = new ScreenController(this); + screenController = new ScreenController(this); } - public ScreenController getGsm() { - return gsm; + @Override + public void dispose() { + // TODO: Dispose everything using the ScreenController } } diff --git a/client/core/src/com/cyberbot/bomberman/controllers/InputController.java b/client/core/src/com/cyberbot/bomberman/controllers/InputController.java index 8427701..c8f120f 100644 --- a/client/core/src/com/cyberbot/bomberman/controllers/InputController.java +++ b/client/core/src/com/cyberbot/bomberman/controllers/InputController.java @@ -65,12 +65,4 @@ public void poll() { actionListeners.forEach(it -> it.onActions(actions)); } - - private void handleItem() { - - } - - private void handleMove() { - - } } diff --git a/client/core/src/com/cyberbot/bomberman/controllers/NetworkedGameplayController.java b/client/core/src/com/cyberbot/bomberman/controllers/NetworkedGameplayController.java index 1ff1abf..578c42f 100644 --- a/client/core/src/com/cyberbot/bomberman/controllers/NetworkedGameplayController.java +++ b/client/core/src/com/cyberbot/bomberman/controllers/NetworkedGameplayController.java @@ -1,5 +1,6 @@ package com.cyberbot.bomberman.controllers; +import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.World; @@ -7,6 +8,7 @@ import com.cyberbot.bomberman.core.controllers.LocalWorldController; import com.cyberbot.bomberman.core.models.Updatable; import com.cyberbot.bomberman.core.models.entities.PlayerEntity; +import com.cyberbot.bomberman.core.models.items.Upgrade; import com.cyberbot.bomberman.core.models.net.data.PlayerData; import com.cyberbot.bomberman.core.models.tiles.MapLoadException; import com.cyberbot.bomberman.core.models.tiles.TileMap; @@ -15,6 +17,7 @@ import com.cyberbot.bomberman.models.KeyBinds; import com.cyberbot.bomberman.net.NetService; import com.cyberbot.bomberman.screens.hud.GameHud; +import com.cyberbot.bomberman.utils.Atlas; import java.net.SocketAddress; import java.util.concurrent.ScheduledExecutorService; @@ -23,12 +26,20 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import static com.cyberbot.bomberman.core.utils.Constants.SIM_RATE; -import static com.cyberbot.bomberman.core.utils.Constants.TICK_RATE; - +import static com.cyberbot.bomberman.core.utils.Constants.*; + +/** + * The main orchestrator for a networked gameplay. It schedules input polling and snapshot creation. + * The actual world simulation, interpolation, rollback on other world related actions are handled + * by a corresponding {@link LocalWorldController}. + *

+ * The {@link #update(float)} method can be called with arbitrary period. + *

+ * If the next snapshot creation falls in the middle of world simulation + * the snapshot thread will wait for the simulation to finish. + */ public class NetworkedGameplayController implements Updatable, Drawable, Disposable { private final TextureController textureController; - private final InputController inputController; private final LocalWorldController worldController; private final TileMap map; @@ -38,25 +49,26 @@ public class NetworkedGameplayController implements Updatable, Drawable, Disposa private final ScheduledExecutorService snapshotService; private final ScheduledExecutorService inputPollService; - private final World world; - private final ReentrantLock worldUpdateLock; private final Condition worldUpdatedCondition; - public NetworkedGameplayController(PlayerData player, String mapPath, + private final Sprite frozenTint; + + public NetworkedGameplayController(PlayerData localPlayer, String mapPath, SocketAddress connection, GameHud hud) throws MapLoadException { KeyBinds binds = new KeyBinds(); // TODO: Load from preferences - world = new World(new Vector2(0, 0), false); + World world = new World(new Vector2(0, 0), false); map = TileMapFactory.createTileMap(world, mapPath); textureController = new TextureController(map); - worldController = new LocalWorldController(world, map, TICK_RATE, player); + // TODO: Maybe allow variable tick rate, sim rate via server's JSON configuration + worldController = new LocalWorldController(world, map, TICK_RATE, SIM_RATE, localPlayer); worldController.addListener(textureController, true); worldController.addListener(hud, true); - inputController = new InputController(binds, hud); + InputController inputController = new InputController(binds, hud); inputController.addActionController(worldController); netService = new NetService(connection, worldController); @@ -72,6 +84,10 @@ public NetworkedGameplayController(PlayerData player, String mapPath, inputPollService = new ScheduledThreadPoolExecutor(1); inputPollService.scheduleAtFixedRate(inputController::poll, 0, 1_000_000 / SIM_RATE, TimeUnit.MICROSECONDS); + + frozenTint = new Sprite(Atlas.getInstance().findRegion("FrozenTint")); + frozenTint.setBounds(0, 0, 15 * PPM, 15 * PPM); + frozenTint.setSize(15 * PPM, 15 * PPM); } @Override @@ -85,11 +101,19 @@ public void update(float delta) { } textureController.update(delta); + + if (worldController.getLocalPlayer().isFrozen()) { + frozenTint.setAlpha(worldController.getLocalPlayer().getFreezeTimeLeft() / Upgrade.FREEZER_DURATION); + } } @Override public void draw(SpriteBatch batch) { textureController.draw(batch); + + if (worldController.getLocalPlayer().isFrozen()) { + frozenTint.draw(batch); + } } @Override @@ -100,22 +124,24 @@ public void dispose() { inputPollService.shutdown(); } - public World getWorld() { - return world; - } - private void createAndSendSnapshot() { try { try { worldUpdateLock.lock(); - worldUpdatedCondition.await(); + while (worldController.isWorldLocked()) { + worldUpdatedCondition.await(); + } } finally { worldUpdateLock.unlock(); } netService.sendPlayerSnapshot(worldController.createSnapshot()); - } catch (Exception ignored) { - + } catch (Exception e) { + // Exceptions thrown in the ScheduledExecutorService are caught + // and returned in a Future only when the executor service is stopped. + // This is the simplest way to prevent the service from halting and + // getting any debugging information from the exceptions + e.printStackTrace(); } } diff --git a/client/core/src/com/cyberbot/bomberman/controllers/ScreenController.java b/client/core/src/com/cyberbot/bomberman/controllers/ScreenController.java index 25f8385..25e5bb9 100644 --- a/client/core/src/com/cyberbot/bomberman/controllers/ScreenController.java +++ b/client/core/src/com/cyberbot/bomberman/controllers/ScreenController.java @@ -9,6 +9,8 @@ import com.cyberbot.bomberman.net.ControlService; import com.cyberbot.bomberman.screens.AbstractScreen; import com.cyberbot.bomberman.screens.GameScreen; +import com.cyberbot.bomberman.screens.finish.FinishInteraction; +import com.cyberbot.bomberman.screens.finish.FinishScreen; import com.cyberbot.bomberman.screens.lobby.LobbyInteraction; import com.cyberbot.bomberman.screens.lobby.LobbyScreen; import com.cyberbot.bomberman.screens.login.LoginInteraction; @@ -20,13 +22,15 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.URISyntaxException; +import java.util.stream.Collectors; public final class ScreenController implements MenuInteraction, LobbyInteraction, - LoginInteraction, ClientControlListener { + LoginInteraction, FinishInteraction, ClientControlListener { private final Game game; private final LobbyScreen lobby; private final MenuScreen menu; private final LoginScreen login; + private final FinishScreen finish; private InetSocketAddress serverAddress; private ControlService controlService; private final int defaultPort; @@ -50,6 +54,7 @@ public ScreenController(final Game game, int defaultPort) { this.menu = new MenuScreen(this); this.lobby = new LobbyScreen(this); this.login = new LoginScreen(this); + this.finish = new FinishScreen(this); setScreen(login); } @@ -188,9 +193,18 @@ public void onGameStart(@NotNull GameStart payload) { }); } + @Override + public void onGameEnd(@NotNull GameEnd payload) { + Gdx.app.postRunnable(() -> { + setScreen(finish); + finish.updateFinish(payload.getLeaderboard().stream().map(Client::getNick).collect(Collectors.toList())); + }); + } + @Override public void onError(@NotNull ErrorResponse payload) { Gdx.app.log("ControlService", payload.getError()); + showError(payload.getError()); } private void showError(String message) { @@ -205,4 +219,9 @@ private void setScreen(AbstractScreen screen) { currentScreen = screen; game.setScreen(screen); } + + @Override + public void leaveFinish() { + setScreen(menu); + } } diff --git a/client/core/src/com/cyberbot/bomberman/controllers/TextureController.java b/client/core/src/com/cyberbot/bomberman/controllers/TextureController.java index 56a25b6..91c4454 100644 --- a/client/core/src/com/cyberbot/bomberman/controllers/TextureController.java +++ b/client/core/src/com/cyberbot/bomberman/controllers/TextureController.java @@ -3,13 +3,12 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.cyberbot.bomberman.core.controllers.WorldChangeListener; import com.cyberbot.bomberman.core.models.Updatable; -import com.cyberbot.bomberman.core.models.entities.BombEntity; import com.cyberbot.bomberman.core.models.entities.Entity; import com.cyberbot.bomberman.core.models.tiles.Tile; import com.cyberbot.bomberman.core.models.tiles.TileMap; import com.cyberbot.bomberman.models.Drawable; import com.cyberbot.bomberman.sprites.EntitySprite; -import com.cyberbot.bomberman.sprites.SpriteFactory; +import com.cyberbot.bomberman.sprites.GraphicsFactory; import com.cyberbot.bomberman.sprites.TileSprite; import java.util.ArrayList; @@ -28,9 +27,9 @@ public final class TextureController implements Drawable, Updatable, WorldChange public TextureController(TileMap map) { map.addListener(this); this.entities = new ArrayList<>(); - this.base = SpriteFactory.createTilesFromMapLayer(map.getBase()); - this.floor = SpriteFactory.createTilesFromMapLayer(map.getFloor()); - this.walls = SpriteFactory.createTilesFromMapLayer(map.getWalls()); + this.base = GraphicsFactory.createTilesFromMapLayer(map.getBase()); + this.floor = GraphicsFactory.createTilesFromMapLayer(map.getFloor()); + this.walls = GraphicsFactory.createTilesFromMapLayer(map.getWalls()); } @Override @@ -46,7 +45,6 @@ public void update(float delta) { entities.forEach(sprite -> sprite.update(delta)); } - @Override public void onWallAdded(Tile tile) { walls.add(new TileSprite(tile)); @@ -59,13 +57,8 @@ public void onWallRemoved(Tile tile) { @Override public void onEntityAdded(Entity entity) { - EntitySprite sprite = SpriteFactory.createEntitySprite(entity); - if (entity instanceof BombEntity) { - // Add at the begging to draw under the previous entities (ex. players) - entities.add(0, sprite); - } else { - entities.add(sprite); - } + EntitySprite sprite = GraphicsFactory.createEntitySprite(entity); + entities.add(0, sprite); } @Override diff --git a/client/core/src/com/cyberbot/bomberman/models/KeyBinds.java b/client/core/src/com/cyberbot/bomberman/models/KeyBinds.java index aa008d1..6cc8c96 100644 --- a/client/core/src/com/cyberbot/bomberman/models/KeyBinds.java +++ b/client/core/src/com/cyberbot/bomberman/models/KeyBinds.java @@ -2,6 +2,7 @@ import com.badlogic.gdx.Input; +@SuppressWarnings("CanBeFinal") public class KeyBinds { public int up = Input.Keys.W; public int down = Input.Keys.S; @@ -10,6 +11,6 @@ public class KeyBinds { public int useItem = Input.Keys.SPACE; // Inventory view - public int switchItemUp = Input.Keys.E; - public int switchItemDown = Input.Keys.Q; + public int switchItemUp = Input.Keys.Q; + public int switchItemDown = Input.Keys.E; } diff --git a/client/core/src/com/cyberbot/bomberman/net/ClientControlListener.kt b/client/core/src/com/cyberbot/bomberman/net/ClientControlListener.kt index 90cd7b4..2c380d4 100644 --- a/client/core/src/com/cyberbot/bomberman/net/ClientControlListener.kt +++ b/client/core/src/com/cyberbot/bomberman/net/ClientControlListener.kt @@ -21,4 +21,6 @@ interface ClientControlListener { fun onError(payload: ErrorResponse) fun onRegisterResponse(payload: ClientRegisterResponse) + + fun onGameEnd(payload: GameEnd) } \ No newline at end of file diff --git a/client/core/src/com/cyberbot/bomberman/net/ControlService.kt b/client/core/src/com/cyberbot/bomberman/net/ControlService.kt index 8aa25ca..af80d39 100644 --- a/client/core/src/com/cyberbot/bomberman/net/ControlService.kt +++ b/client/core/src/com/cyberbot/bomberman/net/ControlService.kt @@ -73,6 +73,7 @@ class ControlService(private val address: SocketAddress) : Runnable { is LobbyCreateResponse -> listeners.forEach { it.onLobbyCreate(packet) } is LobbyJoinResponse -> listeners.forEach { it.onLobbyJoin(packet) } is GameStart -> listeners.forEach { it.onGameStart(packet) } + is GameEnd -> listeners.forEach { it.onGameEnd(packet) } is ErrorResponse -> listeners.forEach { it.onError(packet) } } } catch (e: JsonSyntaxException) { diff --git a/client/core/src/com/cyberbot/bomberman/screens/ScreenState.java b/client/core/src/com/cyberbot/bomberman/screens/ScreenState.java index 8b190fd..75ca2e7 100644 --- a/client/core/src/com/cyberbot/bomberman/screens/ScreenState.java +++ b/client/core/src/com/cyberbot/bomberman/screens/ScreenState.java @@ -4,4 +4,5 @@ public enum ScreenState { GAME, MENU, LOBBY, + FINISH, } diff --git a/client/core/src/com/cyberbot/bomberman/screens/finish/FinishInteraction.java b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishInteraction.java new file mode 100644 index 0000000..30869d6 --- /dev/null +++ b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishInteraction.java @@ -0,0 +1,5 @@ +package com.cyberbot.bomberman.screens.finish; + +public interface FinishInteraction { + void leaveFinish(); +} diff --git a/client/core/src/com/cyberbot/bomberman/screens/finish/FinishLayout.java b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishLayout.java new file mode 100644 index 0000000..4b91eda --- /dev/null +++ b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishLayout.java @@ -0,0 +1,110 @@ +package com.cyberbot.bomberman.screens.finish; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.viewport.Viewport; +import com.cyberbot.bomberman.utils.Atlas; + +import java.util.List; + +public class FinishLayout extends Stage { + + final Skin skin; + private final float spaceHeight = 14; + + private final Label[] playerLabels; + private final FinishInteraction delegate; + + private final float worldWidth = getViewport().getWorldWidth(); + private final float worldHeight = getViewport().getWorldHeight(); + private final float tableWidth = worldWidth / 3; + private final Skin skin2; + + public FinishLayout(Viewport viewport, FinishInteraction delegate) { + super(viewport); + this.delegate = delegate; + this.playerLabels = new Label[4]; + skin = new Skin(Gdx.files.internal("skins/clean-crispy/skin/clean-crispy-ui.json")); + + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("skins/8bit_regular.ttf")); + FreeTypeFontGenerator.FreeTypeFontParameter fontParams = new FreeTypeFontGenerator.FreeTypeFontParameter(); + fontParams.size = 20; + BitmapFont font = generator.generateFont(fontParams); + + this.skin2 = new Skin(Atlas.getSkinAtlas()); + skin2.add("default_font", font); + skin2.load(Gdx.files.internal("skins/skin.json")); + } + + public void createFinishUi() { + Table ui = new Table(); + ui.setDebug(false); + + ui.setPosition((worldWidth - tableWidth) / 2, 1); + ui.setWidth(tableWidth); + ui.setHeight(worldHeight); + addActor(ui); + + Label title = new Label("Leaderboard", skin2); + title.setWidth(tableWidth); + title.setAlignment(1); + title.setFontScale(1.5f); + title.setWrap(false); + float playerLabelHeight = 6; + ui.add(title).width(tableWidth).height(playerLabelHeight).row(); + ui.add().height(spaceHeight * 2).row(); + + for (int i = 0; i < 4; i++) { + Label label = new Label("", skin2); + label.setWidth(tableWidth); + label.setAlignment(Align.left); + label.setFontScale(1); + label.setWrap(false); + playerLabels[i] = label; + ui.add(label).width(tableWidth).height(playerLabelHeight).row(); + ui.add().height(spaceHeight).row(); + } + ui.add().height(spaceHeight).row(); + + TextButton leaveFinishButton = new TextButton("Leave", skin2); + leaveFinishButton.getLabel().setFontScale(0.85f); + setupButton(ui, tableWidth, leaveFinishButton); + leaveFinishButton.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + delegate.leaveFinish(); + } + }); + } + + private void setupButton(Table table, float tableWidth, TextButton button) { + float buttonHeight = 30; + table.add(button).width(tableWidth - 10).height(buttonHeight).row(); + table.add().height(spaceHeight).row(); + } + + public void updateScoreTable(List scoreTable) { + for (int i = 0; i < scoreTable.size(); i++) { + playerLabels[i].setText((i + 1) + ". " + scoreTable.get(i)); + } + for (int i = 3; i > scoreTable.size() - 1; i--) { + playerLabels[i].setText(""); + } + } + + public void showError(String msg) { + Dialog dialog = new Dialog("Error", skin); + dialog.text(msg); + dialog.setMovable(false); + dialog.button("Ok"); + dialog.key(Input.Keys.ENTER, true); + dialog.show(this); + } +} diff --git a/client/core/src/com/cyberbot/bomberman/screens/finish/FinishScreen.java b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishScreen.java new file mode 100644 index 0000000..230b982 --- /dev/null +++ b/client/core/src/com/cyberbot/bomberman/screens/finish/FinishScreen.java @@ -0,0 +1,87 @@ +package com.cyberbot.bomberman.screens.finish; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.utils.viewport.FitViewport; +import com.badlogic.gdx.utils.viewport.Viewport; +import com.cyberbot.bomberman.screens.AbstractScreen; + +import java.util.List; + +public class FinishScreen extends AbstractScreen { + private final OrthographicCamera camera; + private final SpriteBatch batch; + private final Viewport viewport; + + private final FinishLayout finishLayout; + + public FinishScreen(FinishInteraction delegate) { + + batch = new SpriteBatch(); + camera = new OrthographicCamera(); + + camera.setToOrtho(false, 384, 216); + viewport = new FitViewport(384, 216); + + finishLayout = new FinishLayout(viewport, delegate); + } + + public void updateFinish(List table) { + finishLayout.updateScoreTable(table); + } + + @Override + public void update(float delta) { + camera.update(); + + batch.setProjectionMatrix(camera.combined); + finishLayout.act(delta); + } + + @Override + public void showError(String msg) { + finishLayout.showError(msg); + } + + @Override + public void show() { + Gdx.input.setInputProcessor(finishLayout); + finishLayout.createFinishUi(); + } + + @Override + public void render(float delta) { + super.render(delta); + + batch.begin(); + batch.end(); + finishLayout.draw(); + } + + @Override + public void resize(int width, int height) { + viewport.update(width, height); + } + + @Override + public void pause() { + + } + + @Override + public void resume() { + + } + + @Override + public void hide() { + finishLayout.clear(); + } + + @Override + public void dispose() { + finishLayout.dispose(); + batch.dispose(); + } +} diff --git a/client/core/src/com/cyberbot/bomberman/screens/hud/GameHud.java b/client/core/src/com/cyberbot/bomberman/screens/hud/GameHud.java index ff70fd6..8b93ebc 100644 --- a/client/core/src/com/cyberbot/bomberman/screens/hud/GameHud.java +++ b/client/core/src/com/cyberbot/bomberman/screens/hud/GameHud.java @@ -127,13 +127,10 @@ public void addToPlayerList(String name, long id) { playerListView.addPlayer(name, id); } - @Override - public void onEntityAdded(Entity entity) { } - @Override public void onEntityRemoved(Entity entity) { - if(entity instanceof PlayerEntity && entity.getId() != localPlayerEntity.getId()) { - playerListView.onPlayerDeath((PlayerEntity) entity); + if (entity instanceof PlayerEntity) { + playerListView.onPlayerDeath((PlayerEntity) entity); // Cast away to hell } } } diff --git a/client/core/src/com/cyberbot/bomberman/screens/hud/HealthBar.java b/client/core/src/com/cyberbot/bomberman/screens/hud/HealthBar.java index c866cf3..ed9b483 100644 --- a/client/core/src/com/cyberbot/bomberman/screens/hud/HealthBar.java +++ b/client/core/src/com/cyberbot/bomberman/screens/hud/HealthBar.java @@ -20,9 +20,9 @@ public class HealthBar extends Actor { private int visiblePlayerHealth; - private final float HP_PER_SECOND = 100; - private final int HEALTH_MEDIUM = 40; - private final int HEALTH_LOW = 10; + private static final float HP_PER_SECOND = 100; + private static final int HEALTH_MEDIUM = 40; + private static final int HEALTH_LOW = 10; private final LinkedList animationQueue; private IntAction currentAnimation; diff --git a/client/core/src/com/cyberbot/bomberman/screens/hud/InventoryButton.java b/client/core/src/com/cyberbot/bomberman/screens/hud/InventoryButton.java index 12be5a1..c992ae9 100644 --- a/client/core/src/com/cyberbot/bomberman/screens/hud/InventoryButton.java +++ b/client/core/src/com/cyberbot/bomberman/screens/hud/InventoryButton.java @@ -1,69 +1,89 @@ package com.cyberbot.bomberman.screens.hud; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; import com.cyberbot.bomberman.core.models.items.ItemType; +import com.cyberbot.bomberman.sprites.GraphicsFactory; import com.cyberbot.bomberman.utils.Atlas; public class InventoryButton extends Actor { - protected ImageButton button; - protected TextureRegionDrawable region; ItemType type; + private int quantity; - public InventoryButton(ItemType type) { + private final Stack mainWidget; + private final Label labelQuantity; + + private final Button button; + private final TextureRegionDrawable region; + + public InventoryButton(ItemType type, Skin skin) { this.type = type; + quantity = 0; region = new TextureRegionDrawable(Atlas.getSkinAtlas().findRegion("placeholder")); - ImageButton.ImageButtonStyle buttonStyle = new ImageButton.ImageButtonStyle(); - buttonStyle.imageUp = region; + Button.ButtonStyle buttonStyle = new Button.ButtonStyle(); buttonStyle.checked = new TextureRegionDrawable(Atlas.getSkinAtlas().findRegion("button_checked")); + button = new Button(buttonStyle); + + Label.LabelStyle style = new Label.LabelStyle(); + style.font = skin.get("default_font", BitmapFont.class); + style.fontColor = skin.get("white", Color.class); + style.background = new TextureRegionDrawable(Atlas.getSkinAtlas().findRegion("label_background")); + + labelQuantity = new Label(null, style); + labelQuantity.setFontScale(0.5f); + + Container