diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..38f5d98
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM openjdk:8-slim-buster
+
+COPY . .
+RUN apt update && \
+ apt install -y vim git && \
+ apt install -y libxext6 libxrender1 libxtst6 libfreetype6 libfontconfig1 && \
+ echo "Done!"
+
+# Dev environment:
+# docker run -d --name bom-ai -e DISPLAY="host.docker.internal:0" -v /tmp/.X11-unix:/tmp/.X11-unix -v $HOME:/root openjdk:8-slim-buster sleep 999999999
\ No newline at end of file
diff --git a/res/font/SuperPixel-m2L8j.ttf b/res/font/SuperPixel-m2L8j.ttf
new file mode 100644
index 0000000..f7691c8
Binary files /dev/null and b/res/font/SuperPixel-m2L8j.ttf differ
diff --git a/res/levels/Level1.txt b/res/levels/Level1P_1.txt
similarity index 93%
rename from res/levels/Level1.txt
rename to res/levels/Level1P_1.txt
index 6f00589..75c2936 100644
--- a/res/levels/Level1.txt
+++ b/res/levels/Level1P_1.txt
@@ -4,9 +4,9 @@
# # # #*# # #*#*# # # #*#*#*# #
# x* b** * * * * #
# # # # # #*# # #*#*# # # # #*#
-#f x ** * * #
+# x ** * * #
# # # # # # # # # #*# #*# # # #
-#* * * * * #
+# * * * * #
# # # # #*# # # #*#*# # # # # #
#* ** * * #
# #*# # # # # # #*# # # # # # #
diff --git a/res/levels/Level2.txt b/res/levels/Level1P_2.txt
similarity index 100%
rename from res/levels/Level2.txt
rename to res/levels/Level1P_2.txt
diff --git a/res/levels/Level1P_3.txt b/res/levels/Level1P_3.txt
new file mode 100644
index 0000000..b064569
--- /dev/null
+++ b/res/levels/Level1P_3.txt
@@ -0,0 +1,14 @@
+3 13 31
+###############################
+#p * *3 * ** * * *#
+# # # # #*# # #*# # # # # #*# #
+# * * *** ** # * ** #
+# #*# # # # #4# #b#1# # # # #*#
+# * ** * **#
+# # #*# 3 # # # #*#*#*#*# # # #
+# * * * *x* * 4 #
+# # # # #*# # # # # # #*# #*# #
+# **2* *2 #
+# # # # # # # # # #*# # # # #*#
+# **4 ** * 5 #
+###############################
diff --git a/res/levels/Level2P_1.txt b/res/levels/Level2P_1.txt
new file mode 100644
index 0000000..a551e0c
--- /dev/null
+++ b/res/levels/Level2P_1.txt
@@ -0,0 +1,14 @@
+1 13 31
+###############################
+#p s* * 1 * * * * * #
+# # # #*# # #*#*# # # #*#*#*# #
+# x* b** * * * * #
+# # # # # #*# # #*#*# # # # #*#
+# x ** * * #
+# # # # # # # # # #*# #*# # # #
+# * * * * #
+# # # # #*# # # #*#*# # # # # #
+#* ** * * #
+# #*# # # # # # #*# # # # # # #
+#a * * * #
+###############################
\ No newline at end of file
diff --git a/res/levels/Level2P_2.txt b/res/levels/Level2P_2.txt
new file mode 100644
index 0000000..b88931e
--- /dev/null
+++ b/res/levels/Level2P_2.txt
@@ -0,0 +1,14 @@
+2 13 31
+###############################
+#p * *2 * ** * * *#
+# # # # #*# # #*# # # # # #*# #
+# * * *** ** * ** #
+# #*# # # # #1# #b#1# # # # #*#
+# * ** * **#
+# # #*# # # # # #*#*#*#*# # # #
+# * * * *x* * #
+# # # # #*# # # # # # #*# #*# #
+# **** *1 #
+# # # # # # # # # #*# # # # #*#
+#a ** * * 3 #
+###############################
diff --git a/res/levels/Level2P_3.txt b/res/levels/Level2P_3.txt
new file mode 100644
index 0000000..b29f0ef
--- /dev/null
+++ b/res/levels/Level2P_3.txt
@@ -0,0 +1,14 @@
+3 13 31
+###############################
+#p * *3 * ** * * *#
+# # # # #*# # #*# # # # # #*# #
+# * * *** ** # * ** #
+# #*# # # # #4# #b#1# # # # #*#
+# * ** * **#
+# # #*# 3 # # # #*#*#*#*# # # #
+# * * * *x* * 4 #
+# # # # #*# # # # # # #*# #*# #
+# **2* *2 #
+# # # # # # # # # #*# # # # #*#
+#a**4 ** * 5 #
+###############################
diff --git a/res/menu/7729559.svg b/res/menu/7729559.svg
new file mode 100644
index 0000000..32a2e57
--- /dev/null
+++ b/res/menu/7729559.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/res/menu/9165683_home_house_icon.png b/res/menu/9165683_home_house_icon.png
new file mode 100644
index 0000000..df9e3c5
Binary files /dev/null and b/res/menu/9165683_home_house_icon.png differ
diff --git a/res/menu/f15591389f71a57ec5e54ba0f48ed385.jpg b/res/menu/f15591389f71a57ec5e54ba0f48ed385.jpg
new file mode 100644
index 0000000..49189ad
Binary files /dev/null and b/res/menu/f15591389f71a57ec5e54ba0f48ed385.jpg differ
diff --git a/res/menu/forest_by_forheksed_d9q4k94-fullview 1.png b/res/menu/forest_by_forheksed_d9q4k94-fullview 1.png
new file mode 100644
index 0000000..b7fe19d
Binary files /dev/null and b/res/menu/forest_by_forheksed_d9q4k94-fullview 1.png differ
diff --git a/res/menu/gameover.png b/res/menu/gameover.png
new file mode 100644
index 0000000..1020913
Binary files /dev/null and b/res/menu/gameover.png differ
diff --git a/res/menu/icons8-menu-50.png b/res/menu/icons8-menu-50.png
new file mode 100644
index 0000000..5a897f7
Binary files /dev/null and b/res/menu/icons8-menu-50.png differ
diff --git a/res/menu/icons8-restart-50.png b/res/menu/icons8-restart-50.png
new file mode 100644
index 0000000..a206a9b
Binary files /dev/null and b/res/menu/icons8-restart-50.png differ
diff --git a/res/menu/restart.png b/res/menu/restart.png
new file mode 100644
index 0000000..d4b6a8c
Binary files /dev/null and b/res/menu/restart.png differ
diff --git a/res/sprites/fireIcon.png b/res/sprites/fireIcon.png
new file mode 100644
index 0000000..2b2f529
Binary files /dev/null and b/res/sprites/fireIcon.png differ
diff --git a/res/sprites/player2_down.png b/res/sprites/player2_down.png
new file mode 100644
index 0000000..2735443
Binary files /dev/null and b/res/sprites/player2_down.png differ
diff --git a/res/sprites/player2_down_1.png b/res/sprites/player2_down_1.png
new file mode 100644
index 0000000..8eddb58
Binary files /dev/null and b/res/sprites/player2_down_1.png differ
diff --git a/res/sprites/player2_down_2.png b/res/sprites/player2_down_2.png
new file mode 100644
index 0000000..46092ac
Binary files /dev/null and b/res/sprites/player2_down_2.png differ
diff --git a/res/sprites/player2_left.png b/res/sprites/player2_left.png
new file mode 100644
index 0000000..e0b74d4
Binary files /dev/null and b/res/sprites/player2_left.png differ
diff --git a/res/sprites/player2_left_1.png b/res/sprites/player2_left_1.png
new file mode 100644
index 0000000..e8c99b2
Binary files /dev/null and b/res/sprites/player2_left_1.png differ
diff --git a/res/sprites/player2_left_2.png b/res/sprites/player2_left_2.png
new file mode 100644
index 0000000..8d68f29
Binary files /dev/null and b/res/sprites/player2_left_2.png differ
diff --git a/res/sprites/player2_right.png b/res/sprites/player2_right.png
new file mode 100644
index 0000000..6589405
Binary files /dev/null and b/res/sprites/player2_right.png differ
diff --git a/res/sprites/player2_right_1.png b/res/sprites/player2_right_1.png
new file mode 100644
index 0000000..bb03279
Binary files /dev/null and b/res/sprites/player2_right_1.png differ
diff --git a/res/sprites/player2_right_2.png b/res/sprites/player2_right_2.png
new file mode 100644
index 0000000..da73c79
Binary files /dev/null and b/res/sprites/player2_right_2.png differ
diff --git a/res/sprites/player2_up.png b/res/sprites/player2_up.png
new file mode 100644
index 0000000..38dd3ab
Binary files /dev/null and b/res/sprites/player2_up.png differ
diff --git a/res/sprites/player2_up_1.png b/res/sprites/player2_up_1.png
new file mode 100644
index 0000000..a1f927a
Binary files /dev/null and b/res/sprites/player2_up_1.png differ
diff --git a/res/sprites/player2_up_2.png b/res/sprites/player2_up_2.png
new file mode 100644
index 0000000..df6d5d0
Binary files /dev/null and b/res/sprites/player2_up_2.png differ
diff --git a/res/textures/classic.png b/res/textures/classic.png
index 33db1e3..e93685c 100644
Binary files a/res/textures/classic.png and b/res/textures/classic.png differ
diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java
index 4130228..34b6e68 100644
--- a/src/uet/oop/bomberman/Board.java
+++ b/src/uet/oop/bomberman/Board.java
@@ -1,358 +1,131 @@
package uet.oop.bomberman;
-import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.Message;
-import uet.oop.bomberman.entities.bomb.Bomb;
-import uet.oop.bomberman.entities.bomb.FlameSegment;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.agent.Agent;
+import uet.oop.bomberman.base.Copyable;
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.base.IGameInfoManager;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.exceptions.CharacterActionException;
import uet.oop.bomberman.exceptions.LoadLevelException;
import uet.oop.bomberman.graphics.IRender;
import uet.oop.bomberman.graphics.Screen;
-import uet.oop.bomberman.input.Keyboard;
import uet.oop.bomberman.level.FileLevelLoader;
import uet.oop.bomberman.level.LevelLoader;
+import uet.oop.bomberman.manager.EntityManager;
+import uet.oop.bomberman.manager.GameInfoManager;
+import uet.oop.bomberman.utils.Global;
-import java.awt.*;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
/**
* Quản lý thao tác điều khiển, load level, render các màn hình của game
*/
-public class Board implements IRender {
+public class Board implements Copyable, IRender {
protected LevelLoader _levelLoader;
protected Game _game;
- protected Keyboard _input;
protected Screen _screen;
-
- public Entity[] _entities;
- public List _characters = new ArrayList<>();
- protected List _bombs = new ArrayList<>();
- private List _messages = new ArrayList<>();
-
- private int _screenToShow = -1; //1:endgame, 2:changelevel, 3:paused
-
- private int _time = Game.TIME;
- private int _points = Game.POINTS;
-
- public Board(Game game, Keyboard input, Screen screen) {
+
+ private List agents = new ArrayList<>();
+
+ private IEntityManager entityManager;
+ private IGameInfoManager gameInfoManager;
+
+ public Board(Game game, Screen screen) {
_game = game;
- _input = input;
_screen = screen;
-
- loadLevel(1); //start in level 1
+
+ loadLevel(Global.gameLevel); // start in level 1
+ }
+
+ private void snapCameraToPlayer() {
+ int xScroll = Screen.calculateXOffset(this, entityManager.getPlayer());
+ Screen.setOffset(xScroll, 0);
}
-
+
@Override
public void update() {
- if( _game.isPaused() ) return;
-
- updateEntities();
- updateCharacters();
- updateBombs();
- updateMessages();
- detectEndGame();
-
- for (int i = 0; i < _characters.size(); i++) {
- Character a = _characters.get(i);
- if(a.isRemoved()) _characters.remove(i);
+ if (gameInfoManager.isPaused())
+ return;
+
+ entityManager.update();
+ gameInfoManager.update();
+
+ processAgentAction();
+
+ snapCameraToPlayer();
+ }
+
+ private void clearAgents() {
+ agents.clear();
+ }
+
+ public void addAgent(Agent agent) {
+ agents.add(agent);
+ }
+
+ private void processAgentAction() {
+
+ for (Agent agent : agents) {
+ List actions = agent.getNextActions();
+ for (Action action : actions) {
+ try {
+ agent.getCharacter().performAction(action);
+ } catch (CharacterActionException ignored) {
+ }
+ }
}
}
@Override
public void render(Screen screen) {
- if( _game.isPaused() ) return;
-
- //only render the visible part of screen
- int x0 = Screen.xOffset >> 4; //tile precision, -> left X
- int x1 = (Screen.xOffset + screen.getWidth() + Game.TILES_SIZE) / Game.TILES_SIZE; // -> right X
- int y0 = Screen.yOffset >> 4;
- int y1 = (Screen.yOffset + screen.getHeight()) / Game.TILES_SIZE; //render one tile plus to fix black margins
-
- for (int y = y0; y < y1; y++) {
- for (int x = x0; x < x1; x++) {
- _entities[x + y * _levelLoader.getWidth()].render(screen);
- }
- }
-
- renderBombs(screen);
- renderCharacter(screen);
-
+ if (gameInfoManager.isPaused())
+ return;
+ entityManager.render(screen);
}
-
+
public void nextLevel() {
- Game.setBombRadius(1);
- Game.setBombRate(1);
- Game.setBomberSpeed(1.0);
loadLevel(_levelLoader.getLevel() + 1);
}
-
+
public void loadLevel(int level) {
- _time = Game.TIME;
- _screenToShow = 2;
- _game.resetScreenDelay();
- _game.pause();
- _characters.clear();
- _bombs.clear();
- _messages.clear();
-
try {
+ clearAgents();
_levelLoader = new FileLevelLoader(this, level);
- _entities = new Entity[_levelLoader.getHeight() * _levelLoader.getWidth()];
-
+ gameInfoManager = new GameInfoManager(_game);
+ entityManager = new EntityManager(_levelLoader, gameInfoManager);
+ gameInfoManager.setEntityManager(entityManager);
+ gameInfoManager.pause();
+
_levelLoader.createEntities();
} catch (LoadLevelException e) {
- endGame();
+ e.printStackTrace();
}
- }
-
- protected void detectEndGame() {
- if(_time <= 0)
- endGame();
- }
-
- public void endGame() {
- _screenToShow = 1;
- _game.resetScreenDelay();
- _game.pause();
- }
-
- public boolean detectNoEnemies() {// phat hien enemies
- int total = 0;
- for (int i = 0; i < _characters.size(); i++) {
- if(_characters.get(i) instanceof Bomber == false)
- ++total;
- }
-
- return total == 0;
- }
-
- public void drawScreen(Graphics g) {
- switch (_screenToShow) {
- case 1:
- _screen.drawEndGame(g, _points);
- break;
- case 2:
- _screen.drawChangeLevel(g, _levelLoader.getLevel());
- break;
- case 3:
- _screen.drawPaused(g);
- break;
- }
- }
-
- public Entity getEntity(double x, double y, Character m) {
-
- Entity res = null;
-
- res = getFlameSegmentAt((int)x, (int)y);
- if( res != null) return res;
-
- res = getBombAt(x, y);
- if( res != null) return res;
-
- res = getCharacterAtExcluding((int)x, (int)y, m);
- if( res != null) return res;
-
- res = getEntityAt((int)x, (int)y);
-
- return res;
- }
-
- public List getBombs() {
- return _bombs;
- }
-
- public Bomb getBombAt(double x, double y) {
- Iterator bs = _bombs.iterator();
- Bomb b;
- while(bs.hasNext()) {
- b = bs.next();
- if(b.getX() == (int)x && b.getY() == (int)y)
- return b;
- }
-
- return null;
- }
- public Bomber getBomber() {
- Iterator itr = _characters.iterator();
-
- Character cur;
- while(itr.hasNext()) {
- cur = itr.next();
-
- if(cur instanceof Bomber)
- return (Bomber) cur;
- }
-
- return null;
- }
-
- public Character getCharacterAtExcluding(int x, int y, Character a) {
- Iterator itr = _characters.iterator();
-
- Character cur;
- while(itr.hasNext()) {
- cur = itr.next();
- if(cur == a) {
- continue;
- }
-
- if(cur.getXTile() == x && cur.getYTile() == y) {
- return cur;
- }
-
- }
-
- return null;
- }
-
- public FlameSegment getFlameSegmentAt(int x, int y) {
- Iterator bs = _bombs.iterator();
- Bomb b;
- while(bs.hasNext()) {
- b = bs.next();
-
- FlameSegment e = b.flameAt(x, y);
- if(e != null) {
- return e;
- }
- }
-
- return null;
- }
-
- public Entity getEntityAt(double x, double y) {
- return _entities[(int)x + (int)y * _levelLoader.getWidth()];
- }
-
- public void addEntity(int pos, Entity e) {
- _entities[pos] = e;
- }
-
- public void addCharacter(Character e) {
- _characters.add(e);
- }
-
- public void addBomb(Bomb e) {
- _bombs.add(e);
- }
-
- public void addMessage(Message e) {
- _messages.add(e);
- }
-
- protected void renderCharacter(Screen screen) {
- Iterator itr = _characters.iterator();
-
- while(itr.hasNext())
- itr.next().render(screen);
- }
-
- protected void renderBombs(Screen screen) {
- Iterator itr = _bombs.iterator();
-
- while(itr.hasNext())
- itr.next().render(screen);
- }
-
- public void renderMessages(Graphics g) {
- Message m;
- for (int i = 0; i < _messages.size(); i++) {
- m = _messages.get(i);
-
- g.setFont(new Font("Arial", Font.PLAIN, m.getSize()));
- g.setColor(m.getColor());
- g.drawString(m.getMessage(), (int)m.getX() - Screen.xOffset * Game.SCALE, (int)m.getY());
- }
- }
-
- protected void updateEntities() {
- if( _game.isPaused() ) return;
- for (int i = 0; i < _entities.length; i++) {
- _entities[i].update();
- }
- }
-
- protected void updateCharacters() {
- if( _game.isPaused() ) return;
- Iterator itr = _characters.iterator();
-
- while(itr.hasNext() && !_game.isPaused())
- itr.next().update();
- }
-
- protected void updateBombs() {
- if( _game.isPaused() ) return;
- Iterator itr = _bombs.iterator();
-
- while(itr.hasNext())
- itr.next().update();
- }
-
- protected void updateMessages() {
- if( _game.isPaused() ) return;
- Message m;
- int left;
- for (int i = 0; i < _messages.size(); i++) {
- m = _messages.get(i);
- left = m.getDuration();
-
- if(left > 0)
- m.setDuration(--left);
- else
- _messages.remove(i);
- }
- }
-
- public int subtractTime() {
- if(_game.isPaused())
- return this._time;
- else
- return this._time--;
- }
-
- public Keyboard getInput() {
- return _input;
- }
-
- public LevelLoader getLevel() {
- return _levelLoader;
- }
-
- public Game getGame() {
- return _game;
+ _game.setScreenToShow(2);
+ _game.resetScreenDelay();
}
- public int getShow() {
- return _screenToShow;
+ public int getWidth() {
+ return _levelLoader.getWidth();
}
- public void setShow(int i) {
- _screenToShow = i;
+ public int getHeight() {
+ return _levelLoader.getHeight();
}
- public int getTime() {
- return _time;
+ public IEntityManager getEntityManager() {
+ return entityManager;
}
- public int getPoints() {
- return _points;
+ public IGameInfoManager getGameInfoManager() {
+ return gameInfoManager;
}
- public void addPoints(int points) {
- this._points += points;
- }
-
- public int getWidth() {
- return _levelLoader.getWidth();
+ @Override
+ public Board copy() {
+ // TODO Auto-generated method stub
+ return null;
}
- public int getHeight() {
- return _levelLoader.getHeight();
- }
-
}
diff --git a/src/uet/oop/bomberman/BombermanGame.java b/src/uet/oop/bomberman/BombermanGame.java
index 0000736..959fb1c 100644
--- a/src/uet/oop/bomberman/BombermanGame.java
+++ b/src/uet/oop/bomberman/BombermanGame.java
@@ -4,9 +4,9 @@
import uet.oop.bomberman.sound.Sound;
public class BombermanGame {
-
+
public static void main(String[] args) {
- Sound.play("soundtrack");
+ Sound.play("soundtrack");
new Frame();
}
}
diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java
index 53e5c53..a1d00ae 100644
--- a/src/uet/oop/bomberman/Game.java
+++ b/src/uet/oop/bomberman/Game.java
@@ -1,13 +1,20 @@
package uet.oop.bomberman;
+import uet.oop.bomberman.base.IGameInfoManager;
import uet.oop.bomberman.graphics.Screen;
import uet.oop.bomberman.gui.Frame;
import uet.oop.bomberman.input.Keyboard;
+import uet.oop.bomberman.screen.SelectGameModeScreen;
+import uet.oop.bomberman.screen.DeadScreen;
+import uet.oop.bomberman.screen.SelectLevelScreen;
+import uet.oop.bomberman.utils.EScreenName;
+import uet.oop.bomberman.utils.Global;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
+import java.util.Optional;
/**
* Tạo vòng lặp cho game, lưu trữ một vài tham số cấu hình toàn cục,
@@ -15,171 +22,215 @@
*/
public class Game extends Canvas {
-
-
public static final int TILES_SIZE = 16,
- WIDTH = TILES_SIZE * (31 / 2),
- HEIGHT = 13 * TILES_SIZE;
+ WIDTH = TILES_SIZE * (31 / 2),
+ HEIGHT = 13 * TILES_SIZE;
public static int SCALE = 3;
-
+
public static final String TITLE = "BombermanGame";
-
- private static final int BOMBRATE = 1;
- private static final int BOMBRADIUS = 1;
- private static final double BOMBERSPEED = 1.0;//toc do bomber
-
+ public static final int TICKS_PER_SECOND = 60;
+
+ public static final int BOMBRATE = 1;
+ public static final int BOMBRADIUS = 1;
+ public static final double BOMBERSPEED = 3.0;// toc do bomber
+
public static final int TIME = 200;
public static final int POINTS = 0;
-
+
protected static int SCREENDELAY = 3;
- protected static int bombRate = BOMBRATE;
- protected static int bombRadius = BOMBRADIUS;
- protected static double bomberSpeed = BOMBERSPEED;
-
-
protected int _screenDelay = SCREENDELAY;
-
- private Keyboard _input;
+
private boolean _running = false;
- private boolean _paused = true;
-
private Board _board;
private Screen screen;
private Frame _frame;
-
+
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
- private int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
-
+ private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+
+ // game variable
+ private int frames;
+ private int updates;
+ private long timer;
+
+ // game screens
+ public SelectLevelScreen selectLevelScreen;
+ private SelectGameModeScreen selectGameModeScreen;
+ public DeadScreen deadScreen;
+
+ private int _screenToShow = -1; // 1:endgame, 2:changelevel, 3:paused
+
public Game(Frame frame) {
_frame = frame;
_frame.setTitle(TITLE);
-
+
screen = new Screen(WIDTH, HEIGHT);
- _input = new Keyboard();
-
- _board = new Board(this, _input, screen);
- addKeyListener(_input);
+
+ _board = new Board(this, screen);
+ addKeyListener(Keyboard.i());
+
+ initScreen();
+
}
-
-
- private void renderGame() {
- BufferStrategy bs = getBufferStrategy();
- if(bs == null) {
- createBufferStrategy(3);
- return;
- }
-
+
+ private void renderGame(Graphics g) {
screen.clear();
-
+
_board.render(screen);
-
+
for (int i = 0; i < pixels.length; i++) {
pixels[i] = screen._pixels[i];
}
-
- Graphics g = bs.getDrawGraphics();
-
+
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
- _board.renderMessages(g);
-
- g.dispose();
- bs.show();
+ _board.getGameInfoManager().render(screen, g);
}
-
- private void renderScreen() {
+
+ private void renderScreen(Graphics g) {
+ screen.clear();
+ drawScreen(g);
+ }
+
+ private void drawScreen(Graphics g) {
+ switch (getScreenToShow()) {
+ case 1:
+ screen.drawEndGame(g, _board.getGameInfoManager().getPoints());
+ break;
+ case 2:
+ screen.drawChangeLevel(g, _board._levelLoader.getLevel());
+ break;
+ case 3:
+ screen.drawPaused(g);
+ break;
+ }
+ }
+
+ private void initScreen() {
+ Global.currentScreen = EScreenName.SELECT_GAME_MODE;
+ this.selectGameModeScreen = new SelectGameModeScreen();
+ this.selectLevelScreen = new SelectLevelScreen(_board);
+ this.deadScreen = new DeadScreen(this);
+ }
+
+ private void update() {
+ Keyboard.i().update();
+ switch (Global.currentScreen) {
+ case GAME_PLAY_SCREEN:
+ _board.update();
+ if (Keyboard.i().pause) { // Kiểm tra nếu phím "p" được nhấn
+ _screenToShow = 3; // Hiển thị màn hình tạm dừng
+ _board.getGameInfoManager().pause(); // Đặt trạng thái game là tạm dừng
+ return;
+ }
+ break;
+ case SELECT_LEVEL_SCREEN:
+ selectLevelScreen.update();
+ break;
+ case SELECT_GAME_MODE:
+ selectGameModeScreen.update();
+ break;
+ case END_GAME_SCREEN:
+ deadScreen.update();
+ break;
+ }
+
+ }
+
+ private void showScreen() {
BufferStrategy bs = getBufferStrategy();
- if(bs == null) {
+ if (bs == null) {
createBufferStrategy(3);
return;
}
-
- screen.clear();
-
Graphics g = bs.getDrawGraphics();
-
- _board.drawScreen(g);
+
+ IGameInfoManager gameInfoManager = _board.getGameInfoManager();
+ switch (Global.currentScreen) {
+ case GAME_PLAY_SCREEN:
+ Keyboard.i().keyboardInputCallback = Optional.empty();
+ if (gameInfoManager.isPaused()) {
+ if (_screenDelay <= 0) {
+ _screenToShow = -1;
+ gameInfoManager.unpause();
+ }
+
+ renderScreen(g);
+ } else {
+ renderGame(g);
+ }
+
+ if (Keyboard.i().resume) {
+ gameInfoManager.unpause();
+ _screenToShow = -1;
+ _screenDelay = 0;
+ }
+ frames++;
+ if (System.currentTimeMillis() - timer > 1000) {
+ _frame.setTime(gameInfoManager.subtractTime());
+ _frame.setPoints(gameInfoManager.getPoints());
+ _frame.renderItemTime();
+ timer += 1000;
+ _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps");
+ updates = 0;
+ frames = 0;
+
+ if (_screenToShow == 2)
+ --_screenDelay;
+ }
+ break;
+ case SELECT_LEVEL_SCREEN:
+ // TODO: render select level screen
+ selectLevelScreen.setInput(Keyboard.i());
+ selectLevelScreen.drawScreen(g);
+ break;
+ case SELECT_GAME_MODE:
+ selectGameModeScreen.setInput(Keyboard.i());
+ selectGameModeScreen.drawScreen(g);
+ break;
+ case END_GAME_SCREEN:
+ deadScreen.setInput();
+ deadScreen.drawScreen(g);
+ break;
+ }
g.dispose();
bs.show();
}
- private void update() {
- _input.update();
- _board.update();
+ private void initGame() {
+ this.timer = System.currentTimeMillis();
+ this.frames = 0;
+ this.updates = 0;
}
-
+
public void start() {
_running = true;
-
- long lastTime = System.nanoTime();
- long timer = System.currentTimeMillis();
- final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second
+
+ initGame();
+
+ long lastTime = System.nanoTime();
+ final double ns = 1000000000.0 / 60.0; // nanosecond, 60 frames per second
double delta = 0;
- int frames = 0;
- int updates = 0;
requestFocus();
- while(_running) {
+ while (_running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
- while(delta >= 1) {
- update();
+ while (delta >= 1) {
+ synchronized (_board) {
+ update();
+ }
updates++;
delta--;
}
-
- if(_paused) {
- if(_screenDelay <= 0) {
- _board.setShow(-1);
- _paused = false;
- }
-
- renderScreen();
- } else {
- renderGame();
- }
-
-
- frames++;
- if(System.currentTimeMillis() - timer > 1000) {
- _frame.setTime(_board.subtractTime());
- _frame.setPoints(_board.getPoints());
- timer += 1000;
- _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps");
- updates = 0;
- frames = 0;
-
- if(_board.getShow() == 2)
- --_screenDelay;
+
+ synchronized (_board) {
+ showScreen();
}
}
}
-
- public static double getBomberSpeed() {
- return bomberSpeed;
- }
-
- public static int getBombRate() {
- return bombRate;
- }
-
- public static int getBombRadius() {
- return bombRadius;
- }
-
- public static void addBomberSpeed(double i) {
- bomberSpeed += i;
- }
-
- public static void addBombRadius(int i) {
- bombRadius += i;
- }
-
- public static void addBombRate(int i) {
- bombRate += i;
- }
public void resetScreenDelay() {
_screenDelay = SCREENDELAY;
@@ -189,22 +240,23 @@ public Board getBoard() {
return _board;
}
- public boolean isPaused() {
- return _paused;
+ public void restartGame() {
+ Global.currentScreen = EScreenName.GAME_PLAY_SCREEN;
+ synchronized (_board) {
+ _board.loadLevel(_board._levelLoader.getLevel());
+ }
+ }
+
+ public void startNewGame() {
+ Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN;
}
-
- public void pause() {
- _paused = true;
+
+ public int getScreenToShow() {
+ return _screenToShow;
}
- public static void setBombRate(int bombRate) {
- Game.bombRate = bombRate;
- }
- public static void setBombRadius(int bombRadius) {
- Game.bombRadius = bombRadius;
- }
+ public void setScreenToShow(int screenToShow) {
+ this._screenToShow = screenToShow;
+ }
- public static void setBomberSpeed(double bomberSpeed) {
- Game.bomberSpeed = bomberSpeed;
- }
}
diff --git a/src/uet/oop/bomberman/agent/Agent.java b/src/uet/oop/bomberman/agent/Agent.java
new file mode 100644
index 0000000..9bad770
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/Agent.java
@@ -0,0 +1,17 @@
+package uet.oop.bomberman.agent;
+
+import uet.oop.bomberman.entities.character.Character;
+
+public abstract class Agent implements IAgent {
+
+ protected Character character;
+
+ public Agent(Character character) {
+ this.character = character;
+ }
+
+ public Character getCharacter() {
+ return character;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/agent/IAgent.java b/src/uet/oop/bomberman/agent/IAgent.java
new file mode 100644
index 0000000..8f5ffd2
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/IAgent.java
@@ -0,0 +1,11 @@
+package uet.oop.bomberman.agent;
+
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.action.Action;
+
+public interface IAgent {
+
+ public List getNextActions();
+
+}
diff --git a/src/uet/oop/bomberman/agent/KeyboardAgent.java b/src/uet/oop/bomberman/agent/KeyboardAgent.java
new file mode 100644
index 0000000..77a1e3d
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/KeyboardAgent.java
@@ -0,0 +1,50 @@
+package uet.oop.bomberman.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.Bomber;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.action.ActionMove;
+import uet.oop.bomberman.input.Keyboard;
+
+public class KeyboardAgent extends Agent {
+
+ public KeyboardAgent(Character character) {
+ super(character);
+ }
+
+ @Override
+ public List getNextActions() {
+ List actions = getMoveActions();
+
+ if (character instanceof Bomber) {
+ if (Keyboard.i().space) {
+ actions.add(ActionConstants.PLACE_BOMB);
+ }
+ }
+ return actions;
+ }
+
+ private List getMoveActions() {
+ int xa = 0, ya = 0;
+ if (Keyboard.i().up)
+ ya--;
+ if (Keyboard.i().down)
+ ya++;
+ if (Keyboard.i().left)
+ xa--;
+ if (Keyboard.i().right)
+ xa++;
+
+ List actions = new ArrayList<>();
+ if (xa != 0 || ya != 0) {
+ ActionMove actionMove = new ActionMove(xa, ya);
+ actions.add(actionMove);
+ }
+ return actions;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/agent/KeyboardAgentPlayer1.java b/src/uet/oop/bomberman/agent/KeyboardAgentPlayer1.java
new file mode 100644
index 0000000..5e95761
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/KeyboardAgentPlayer1.java
@@ -0,0 +1,51 @@
+package uet.oop.bomberman.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.Bomber;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.action.ActionMove;
+import uet.oop.bomberman.input.Keyboard;
+
+public class KeyboardAgentPlayer1 extends KeyboardAgent {
+ // biến
+
+ public KeyboardAgentPlayer1(Character character) {
+ super(character);
+ }
+
+ @Override
+ public List getNextActions() {
+ List actions = getMoveActions();
+
+ if (character instanceof Bomber) {
+ if (Keyboard.i().player1_bomb) {
+ actions.add(ActionConstants.PLACE_BOMB);
+ }
+ }
+ return actions;
+ }
+
+ private List getMoveActions() {
+ int xa = 0, ya = 0;
+ if (Keyboard.i().player1_up)
+ ya--;
+ if (Keyboard.i().player1_down)
+ ya++;
+ if (Keyboard.i().player1_left)
+ xa--;
+ if (Keyboard.i().player1_right)
+ xa++;
+
+ List actions = new ArrayList<>();
+ if (xa != 0 || ya != 0) {
+ ActionMove actionMove = new ActionMove(xa, ya);
+ actions.add(actionMove);
+ }
+ return actions;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/agent/KeyboardAgentPlayer2.java b/src/uet/oop/bomberman/agent/KeyboardAgentPlayer2.java
new file mode 100644
index 0000000..1724ced
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/KeyboardAgentPlayer2.java
@@ -0,0 +1,51 @@
+package uet.oop.bomberman.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.Bomber;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.action.ActionMove;
+import uet.oop.bomberman.input.Keyboard;
+
+public class KeyboardAgentPlayer2 extends KeyboardAgent {
+
+ public KeyboardAgentPlayer2(Character character) {
+ super(character);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public List getNextActions() {
+ List actions = getMoveActions();
+
+ if (character instanceof Bomber) {
+ if (Keyboard.i().player2_bomb) {
+ actions.add(ActionConstants.PLACE_BOMB);
+ }
+ }
+ return actions;
+ }
+
+ private List getMoveActions() {
+ int xa = 0, ya = 0;
+ if (Keyboard.i().player2_up)
+ ya--;
+ if (Keyboard.i().player2_down)
+ ya++;
+ if (Keyboard.i().player2_left)
+ xa--;
+ if (Keyboard.i().player2_right)
+ xa++;
+
+ List actions = new ArrayList<>();
+ if (xa != 0 || ya != 0) {
+ ActionMove actionMove = new ActionMove(xa, ya);
+ actions.add(actionMove);
+ }
+ return actions;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/agent/MovingAgent.java b/src/uet/oop/bomberman/agent/MovingAgent.java
new file mode 100644
index 0000000..0f4e6c2
--- /dev/null
+++ b/src/uet/oop/bomberman/agent/MovingAgent.java
@@ -0,0 +1,43 @@
+package uet.oop.bomberman.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.enemy.ai.AI;
+
+public class MovingAgent extends Agent {
+
+ private AI ai;
+
+ public MovingAgent(Character character, AI ai) {
+ super(character);
+ this.ai = ai;
+ }
+
+ public Action getNextAction() {
+ int direction = ai.calculateDirection();
+ switch (direction) {
+ case 0:
+ return ActionConstants.MOVE_UP;
+ case 1:
+ return ActionConstants.MOVE_RIGHT;
+ case 2:
+ return ActionConstants.MOVE_DOWN;
+ case 3:
+ return ActionConstants.MOVE_LEFT;
+ default:
+ return ActionConstants.DO_NOTHING;
+ }
+ }
+
+ @Override
+ public List getNextActions() {
+ List actions = new ArrayList<>();
+ actions.add(getNextAction());
+ return actions;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/base/Copyable.java b/src/uet/oop/bomberman/base/Copyable.java
new file mode 100644
index 0000000..bd9721e
--- /dev/null
+++ b/src/uet/oop/bomberman/base/Copyable.java
@@ -0,0 +1,7 @@
+package uet.oop.bomberman.base;
+
+public interface Copyable {
+
+ public Copyable copy();
+
+}
diff --git a/src/uet/oop/bomberman/base/IBombManager.java b/src/uet/oop/bomberman/base/IBombManager.java
new file mode 100644
index 0000000..24e321d
--- /dev/null
+++ b/src/uet/oop/bomberman/base/IBombManager.java
@@ -0,0 +1,16 @@
+package uet.oop.bomberman.base;
+
+import java.util.List;
+
+import uet.oop.bomberman.entities.bomb.Bomb;
+import uet.oop.bomberman.entities.bomb.FlameSegment;
+import uet.oop.bomberman.graphics.IRender;
+
+public interface IBombManager extends IRender {
+
+ public List getBombs();
+ public Bomb getBombAt(double x, double y);
+ public void addBomb(Bomb e);
+ public FlameSegment getFlameSegmentAt(int x, int y);
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/base/ICharacterManager.java b/src/uet/oop/bomberman/base/ICharacterManager.java
new file mode 100644
index 0000000..7f457bb
--- /dev/null
+++ b/src/uet/oop/bomberman/base/ICharacterManager.java
@@ -0,0 +1,27 @@
+package uet.oop.bomberman.base;
+
+import java.util.List;
+
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.graphics.IRender;
+
+public interface ICharacterManager extends IRender {
+
+ public List getCharacters();
+
+ public Character getCharacterAtExcluding(int x, int y, Character a);
+
+ public void addCharacter(Character e);
+
+ public void setPlayer(Character character);
+
+ public Character getPlayer();
+
+ public void handleOnDeath(Character character, Character killer);
+
+ public void handleAfterDeath(Character character);
+
+ public void addPlayer(Character e);
+
+ public List getPlayers();
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/base/IEntityManager.java b/src/uet/oop/bomberman/base/IEntityManager.java
new file mode 100644
index 0000000..eaf805d
--- /dev/null
+++ b/src/uet/oop/bomberman/base/IEntityManager.java
@@ -0,0 +1,29 @@
+package uet.oop.bomberman.base;
+
+import java.util.List;
+
+import uet.oop.bomberman.entities.Entity;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.graphics.IRender;
+
+public interface IEntityManager extends IRender {
+
+ public Entity getEntityAtExcluding(double x, double y, Character m);
+
+ public default Entity getEntityAt(double x, double y) {
+ return getEntityAtExcluding(x, y, null);
+ };
+
+ public boolean isEnemyCleared();
+
+ public Character getPlayer();
+
+ public List getPlayers();
+
+ public ITileManager getTileManager();
+
+ public ICharacterManager getCharacterManager();
+
+ public IBombManager getBombManager();
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/base/IGameInfoManager.java b/src/uet/oop/bomberman/base/IGameInfoManager.java
new file mode 100644
index 0000000..1f053e1
--- /dev/null
+++ b/src/uet/oop/bomberman/base/IGameInfoManager.java
@@ -0,0 +1,34 @@
+package uet.oop.bomberman.base;
+
+import java.awt.Graphics;
+import java.util.List;
+
+import uet.oop.bomberman.entities.tile.item.Item;
+import uet.oop.bomberman.graphics.IRender;
+import uet.oop.bomberman.graphics.Screen;
+
+public interface IGameInfoManager extends IMessageManager, IRender {
+
+ public int subtractTime();
+
+ public int getTime();
+
+ public int getPoints();
+
+ public void addPoints(int points);
+
+ public boolean isPaused();
+
+ public void pause();
+
+ public void unpause();
+
+ public void endGame();
+
+ public List- getPlayerActiveItems();
+
+ public void setEntityManager(IEntityManager entityManager);
+
+ public void render(Screen screen, Graphics g);
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/base/IMessageManager.java b/src/uet/oop/bomberman/base/IMessageManager.java
new file mode 100644
index 0000000..ec01310
--- /dev/null
+++ b/src/uet/oop/bomberman/base/IMessageManager.java
@@ -0,0 +1,9 @@
+package uet.oop.bomberman.base;
+
+import uet.oop.bomberman.entities.Message;
+
+public interface IMessageManager {
+
+ public void addMessage(Message e);
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/base/ITileManager.java b/src/uet/oop/bomberman/base/ITileManager.java
new file mode 100644
index 0000000..5b74d39
--- /dev/null
+++ b/src/uet/oop/bomberman/base/ITileManager.java
@@ -0,0 +1,11 @@
+package uet.oop.bomberman.base;
+
+import uet.oop.bomberman.entities.tile.Tile;
+import uet.oop.bomberman.graphics.IRender;
+
+public interface ITileManager extends IRender {
+
+ public Tile getTileAt(double x, double y);
+ public void addTile(int pos, Tile e);
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/entities/Entity.java b/src/uet/oop/bomberman/entities/Entity.java
index c1021cb..c7ad8c8 100644
--- a/src/uet/oop/bomberman/entities/Entity.java
+++ b/src/uet/oop/bomberman/entities/Entity.java
@@ -40,13 +40,27 @@ public Sprite getSprite() {
return _sprite;
}
+ public double getCenterX() {
+ return _x + _sprite.SIZE / 2;
+ }
+
+ public double getCenterY() {
+ return _y - _sprite.SIZE / 2;
+ }
+
/**
* Phương thức này được gọi để xử lý khi hai entity va chạm vào nhau
* @param e
* @return
*/
public abstract boolean collide(Entity e);
- //xu li 2 entity va cham
+
+ /**
+ * Check if other Entity can pass through this
+ * @param other
+ * @return
+ */
+ public abstract boolean canBePassedThroughBy(Entity other);
public double getX() {
return _x;
@@ -57,11 +71,11 @@ public double getY() {
}
public int getXTile() {
- return Coordinates.pixelToTile(_x + _sprite.SIZE / 2);
+ return Coordinates.pixelToTile(getCenterX());
}
public int getYTile() {
- return Coordinates.pixelToTile(_y - _sprite.SIZE / 2);
+ return Coordinates.pixelToTile(getCenterY());
}
diff --git a/src/uet/oop/bomberman/entities/LayeredEntity.java b/src/uet/oop/bomberman/entities/LayeredEntity.java
index e183f24..7d824a3 100644
--- a/src/uet/oop/bomberman/entities/LayeredEntity.java
+++ b/src/uet/oop/bomberman/entities/LayeredEntity.java
@@ -1,5 +1,6 @@
package uet.oop.bomberman.entities;
+import uet.oop.bomberman.entities.tile.Tile;
import uet.oop.bomberman.entities.tile.destroyable.DestroyableTile;
import uet.oop.bomberman.graphics.Screen;
@@ -9,11 +10,12 @@
* Chứa và quản lý nhiều Entity tại cùng một vị trí
* Ví dụ: tại vị trí dấu Item, có 3 Entity [Grass, Item, Brick]
*/
-public class LayeredEntity extends Entity {
+public class LayeredEntity extends Tile {
- protected LinkedList _entities = new LinkedList<>();
+ protected LinkedList _entities = new LinkedList<>();
- public LayeredEntity(int x, int y, Entity ... entities) {
+ public LayeredEntity(int x, int y, Tile ... entities) {
+ super(x, y, null);
_x = x;
_y = y;
@@ -38,7 +40,7 @@ public void render(Screen screen) {
getTopEntity().render(screen);
}
- public Entity getTopEntity() {
+ public Tile getTopEntity() {
return _entities.getLast();
}
@@ -51,15 +53,24 @@ private void clearRemoved() {
}
}
- public void addBeforeTop(Entity e) {
+ public void addBeforeTop(Tile e) {
_entities.add(_entities.size() - 1, e);
}
@Override
public boolean collide(Entity e) {
// TODO: lấy entity trên cùng ra để xử lý va chạm
-
return getTopEntity().collide(e);
}
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return getTopEntity().canBePassedThroughBy(other);
+ }
+
+ @Override
+ public boolean isDestroyable() {
+ return getTopEntity().isDestroyable();
+ }
+
}
diff --git a/src/uet/oop/bomberman/entities/Message.java b/src/uet/oop/bomberman/entities/Message.java
index 1e743e7..74cc779 100644
--- a/src/uet/oop/bomberman/entities/Message.java
+++ b/src/uet/oop/bomberman/entities/Message.java
@@ -1,5 +1,6 @@
package uet.oop.bomberman.entities;
+import uet.oop.bomberman.Game;
import uet.oop.bomberman.graphics.Screen;
import java.awt.*;
@@ -27,7 +28,7 @@ public Message(String message, double x, double y, int duration, Color color, in
_x =x;
_y = y;
_message = message;
- _duration = duration * 60; //seconds
+ _duration = duration * Game.TICKS_PER_SECOND; //seconds
_color = color;
_size = size;
}
@@ -64,6 +65,11 @@ public void render(Screen screen) {
public boolean collide(Entity e) {
return true;
}
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return true;
+ }
}
diff --git a/src/uet/oop/bomberman/entities/bomb/Bomb.java b/src/uet/oop/bomberman/entities/bomb/Bomb.java
index 34e1a20..6ad7436 100644
--- a/src/uet/oop/bomberman/entities/bomb/Bomb.java
+++ b/src/uet/oop/bomberman/entities/bomb/Bomb.java
@@ -1,7 +1,7 @@
package uet.oop.bomberman.entities.bomb;
-import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.entities.AnimatedEntitiy;
import uet.oop.bomberman.entities.Entity;
import uet.oop.bomberman.entities.character.Bomber;
@@ -10,120 +10,136 @@
import uet.oop.bomberman.entities.character.Character;
import uet.oop.bomberman.level.Coordinates;
import uet.oop.bomberman.sound.Sound;
+
public class Bomb extends AnimatedEntitiy {
- protected double _timeToExplode = 120; //2 seconds - thoi gian phat no
+ protected double _timeToExplode = 120; // 2 seconds - thoi gian phat no
public int _timeAfter = 20;// thoi gian de no
-
- protected Board _board;
+
+ protected IEntityManager _board;
protected Flame[] _flames;
protected boolean _exploded = false;
protected boolean _allowedToPassThru = true;
-
- public Bomb(int x, int y, Board board) {
+
+ private final int bombRadius;
+
+ public Bomb(int x, int y, int bombRadius, IEntityManager board) {
_x = x;
_y = y;
_board = board;
_sprite = Sprite.bomb;
+ this.bombRadius = bombRadius;
}
-
+
@Override
public void update() {
- if(_timeToExplode > 0)
+ if (_timeToExplode > 0)
_timeToExplode--;
else {
- if(!_exploded)
+ if (!_exploded)
explode();
else
updateFlames();
-
- if(_timeAfter > 0)
+
+ if (_timeAfter > 0)
_timeAfter--;
else
remove();
}
-
+
animate();
}
-
+
@Override
public void render(Screen screen) {
- if(_exploded) {
- _sprite = Sprite.bomb_exploded2;
+ if (_exploded) {
+ _sprite = Sprite.bomb_exploded2;
renderFlames(screen);
} else
- _sprite = Sprite.movingSprite(Sprite.bomb, Sprite.bomb_1, Sprite.bomb_2, _animate, 60);
-
- int xt = (int)_x << 4;
- int yt = (int)_y << 4;
-
- screen.renderEntity(xt, yt , this);
+ _sprite = Sprite.movingSprite(Sprite.bomb, Sprite.bomb_1, Sprite.bomb_2, _animate, Game.TICKS_PER_SECOND);
+
+ int xt = (int) _x << 4;
+ int yt = (int) _y << 4;
+
+ screen.renderEntity(xt, yt, this);
}
-
+
public void renderFlames(Screen screen) {
for (int i = 0; i < _flames.length; i++) {
_flames[i].render(screen);
}
}
-
+
public void updateFlames() {
for (int i = 0; i < _flames.length; i++) {
_flames[i].update();
}
}
- /**
- * Xử lý Bomb nổ
- */
- protected void explode() {//nổ
+ /**
+ * Xử lý Bomb nổ
+ */
+ protected void explode() {// nổ
_exploded = true;
_allowedToPassThru = true;
// TODO: xử lý khi Character đứng tại vị trí Bomb
- Character x = _board.getCharacterAtExcluding((int)_x, (int)_y, null);
- if(x != null){
- x.kill();
- }
+ Character x = _board.getCharacterManager().getCharacterAtExcluding((int) _x, (int) _y, null);
+ if (x != null) {
+ x.handleOnDeath();
+ }
// TODO: tạo các Flame
- _flames = new Flame[4];
- for (int i = 0; i < _flames.length; i++) {
- _flames[i] = new Flame((int) _x, (int) _y, i, Game.getBombRadius(), _board);
- }
- Sound.play("BOM_11_M");
+ _flames = new Flame[4];
+ for (int i = 0; i < _flames.length; i++) {
+ _flames[i] = new Flame((int) _x, (int) _y, i, bombRadius, _board);
+ }
+ Sound.play("BOM_11_M");
}
- public void time_explode() {
+
+ public void handleChainExplode() {
_timeToExplode = 0;
}
+
public FlameSegment flameAt(int x, int y) {
- if(!_exploded) return null;
-
+ if (!_exploded)
+ return null;
+
for (int i = 0; i < _flames.length; i++) {
- if(_flames[i] == null) return null;
+ if (_flames[i] == null)
+ return null;
FlameSegment e = _flames[i].flameSegmentAt(x, y);
- if(e != null) return e;
+ if (e != null)
+ return e;
}
-
+
return null;
}
@Override
public boolean collide(Entity e) {
- // TODO: xử lý khi Bomber đi ra sau khi vừa đặt bom (_allowedToPassThru)
-
- if(e instanceof Bomber) {
- double diffX = e.getX() - Coordinates.tileToPixel(getX());
- double diffY = e.getY() - Coordinates.tileToPixel(getY());
-
- if(!(diffX >= -10 && diffX < 16 && diffY >= 1 && diffY <= 28)) { // differences to see if the player has moved out of the bomb, tested values
+ // Xử lý va chạm với Flame của Bomb khác: chain explosion
+ if (e instanceof Flame) {
+ handleChainExplode();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ // Xử lý khi Bomber đi ra sau khi vừa đặt bom (_allowedToPassThru)
+ if (other instanceof Bomber) {
+ double diffX = other.getX() - Coordinates.tileToPixel(getX());
+ double diffY = other.getY() - Coordinates.tileToPixel(getY());
+
+ if (!(diffX >= -10 && diffX < 16 && diffY >= 1 && diffY <= 28)) { // differences to see if the player has
+ // moved out of the bomb, tested values
_allowedToPassThru = false;
}
-
+
return _allowedToPassThru;
}
- // TODO: xử lý va chạm với Flame của Bomb khác
- if(e instanceof Flame ) {
- time_explode();
- return true;
- }
+
return false;
}
+
}
diff --git a/src/uet/oop/bomberman/entities/bomb/Flame.java b/src/uet/oop/bomberman/entities/bomb/Flame.java
index 721bc25..bf25642 100644
--- a/src/uet/oop/bomberman/entities/bomb/Flame.java
+++ b/src/uet/oop/bomberman/entities/bomb/Flame.java
@@ -1,14 +1,14 @@
package uet.oop.bomberman.entities.bomb;
-import uet.oop.bomberman.Board;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.character.enemy.Enemy;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.tile.Tile;
import uet.oop.bomberman.graphics.Screen;
public class Flame extends Entity {
- protected Board _board;
+ protected IEntityManager entityManager;
protected int _direction;
private int _radius;
protected int xOrigin, yOrigin;
@@ -21,14 +21,14 @@ public class Flame extends Entity {
* @param direction là hướng của Flame
* @param radius độ dài cực đại của Flame
*/
- public Flame(int x, int y, int direction, int radius, Board board) {
+ public Flame(int x, int y, int direction, int radius, IEntityManager entityManager) {
xOrigin = x;
yOrigin = y;
_x = x;
_y = y;
_direction = direction;
_radius = radius;
- _board = board;
+ this.entityManager = entityManager;
createFlameSegments();
}
@@ -60,6 +60,10 @@ private void createFlameSegments() {
case 3: x--; break;
}
_flameSegments[i] = new FlameSegment(x, y, _direction, last);
+ Entity entity = entityManager.getEntityAt(x, y);
+ if (entity!=null) {
+ entity.collide(this);
+ }
}
}
@@ -78,17 +82,32 @@ private int calculatePermitedDistance() {
if(_direction == 2) y++;
if(_direction == 3) x--;
- Entity a = _board.getEntity(x, y, null);
+ Entity a = entityManager.getEntityAt(x, y);
if(a instanceof Bomb) ++radius; //explosion has to be below the bom
- if(a.collide(this) == false) //cannot pass thru
+ if(!canSpawnFlameOn(a)) {
break;
+ }
++radius;
+
+ // Stop if encounter brick
+ if (!a.canBePassedThroughBy(this)) {
+ break;
+ }
}
return radius;
}
+
+ private boolean canSpawnFlameOn(Entity entity) {
+ if (entity.canBePassedThroughBy(this)) return true;
+ if (entity instanceof Tile) {
+ Tile tile = (Tile) entity;
+ if (tile.isDestroyable()) return true;
+ }
+ return false;
+ }
public FlameSegment flameSegmentAt(int x, int y) {
for (int i = 0; i < _flameSegments.length; i++) {
@@ -110,9 +129,15 @@ public void render(Screen screen) {
@Override
public boolean collide(Entity e) {
- // TODO: xử lý va chạm với Bomber, Enemy. Chú ý đối tượng này có vị trí chính là vị trí của Bomb đã nổ
- if(e instanceof Bomber) ((Bomber) e).kill();
- if(e instanceof Enemy) ((Enemy) e).kill();
- return true;
+ if (e instanceof Character) {
+ ((Character)e).handleOnDeath();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return true;
}
+
}
diff --git a/src/uet/oop/bomberman/entities/bomb/FlameSegment.java b/src/uet/oop/bomberman/entities/bomb/FlameSegment.java
index 8a28539..cbbb2a5 100644
--- a/src/uet/oop/bomberman/entities/bomb/FlameSegment.java
+++ b/src/uet/oop/bomberman/entities/bomb/FlameSegment.java
@@ -1,8 +1,7 @@
package uet.oop.bomberman.entities.bomb;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.character.enemy.Enemy;
+import uet.oop.bomberman.entities.character.Character;
import uet.oop.bomberman.graphics.Screen;
import uet.oop.bomberman.graphics.Sprite;
@@ -69,11 +68,13 @@ public void update() {}
@Override
public boolean collide(Entity e) {
- // TODO: xử lý khi FlameSegment va chạm với Character
- if(e instanceof Bomber) ((Bomber) e).kill();
- if(e instanceof Enemy) ((Enemy) e).kill();
+ if (e instanceof Character) ((Character)e).handleOnDeath();
+ return true;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
return true;
}
-
}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java
index bcc797d..a292697 100644
--- a/src/uet/oop/bomberman/entities/character/Bomber.java
+++ b/src/uet/oop/bomberman/entities/character/Bomber.java
@@ -1,64 +1,61 @@
package uet.oop.bomberman.entities.character;
import java.util.ArrayList;
-import uet.oop.bomberman.Board;
-import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.entities.Entity;
import uet.oop.bomberman.entities.bomb.Bomb;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.action.ActionPlaceBomb;
+import uet.oop.bomberman.entities.character.exceptions.ActionOnCooldownException;
+import uet.oop.bomberman.entities.character.exceptions.BombQuotaReachedException;
+import uet.oop.bomberman.entities.character.exceptions.CannotPerformActionException;
+import uet.oop.bomberman.entities.character.exceptions.InvalidActionException;
import uet.oop.bomberman.graphics.Screen;
import uet.oop.bomberman.graphics.Sprite;
-import uet.oop.bomberman.input.Keyboard;
-import java.util.Iterator;
import java.util.List;
-import uet.oop.bomberman.entities.LayeredEntity;
-import uet.oop.bomberman.entities.bomb.Flame;
-import uet.oop.bomberman.entities.character.enemy.Enemy;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import uet.oop.bomberman.entities.tile.item.BombItem;
+import uet.oop.bomberman.entities.tile.item.FlameItem;
import uet.oop.bomberman.entities.tile.item.Item;
+import uet.oop.bomberman.entities.tile.item.SpeedItem;
import uet.oop.bomberman.level.Coordinates;
import uet.oop.bomberman.sound.Sound;
-public class Bomber extends Character {
-
- private List _bombs;
- protected Keyboard _input;
- public static List
- _items = new ArrayList
- ();//xu li Item
- /**
- * nếu giá trị này < 0 thì cho phép đặt đối tượng Bomb tiếp theo,
- * cứ mỗi lần đặt 1 Bomb mới, giá trị này sẽ được reset về 0 và giảm dần trong mỗi lần update()
- */
- protected int _timeBetweenPutBombs = 0;
-
- public Bomber(int x, int y, Board board) {
- super(x, y, board);
- _bombs = _board.getBombs();
- _input = _board.getInput();
+public class Bomber extends Character implements CanUseItem {
+
+ private List _bombs = new ArrayList<>();
+ private List
- activeItems = new ArrayList<>();
+
+ private final int baseBombLimit;
+ protected int bombCooldown = 0;
+
+ private final int baseBombRadius;
+
+ public Bomber(int x, int y, double baseSpeed, int baseBombLimit, int baseBombRadius, IEntityManager entityManager) {
+ super(x, y, baseSpeed, entityManager);
+ this.baseBombLimit = baseBombLimit;
+ this.baseBombRadius = baseBombRadius;
_sprite = Sprite.player_right;
}
@Override
- public void update() {
- clearBombs();
- if (!_alive) {
- afterKill();
- return;
- }
-
- if (_timeBetweenPutBombs < -7500) _timeBetweenPutBombs = 0;
- else _timeBetweenPutBombs--;
-
+ public void handleUpdate() {
+ clearExpiredBombs();
+ if (bombCooldown < -7500)
+ bombCooldown = 0;
+ else
+ bombCooldown--;
animate();
- calculateMove();
-
- detectPlaceBomb();
}
@Override
public void render(Screen screen) {
- calculateXOffset();
-
- if (_alive)
+ if (isAlive())
chooseSprite();
else
_sprite = Sprite.player_dead1;
@@ -66,170 +63,151 @@ public void render(Screen screen) {
screen.renderEntity((int) _x, (int) _y - _sprite.SIZE, this);
}
- public void calculateXOffset() {
- int xScroll = Screen.calculateXOffset(_board, this);
- Screen.setOffset(xScroll, 0);
- }
-
- /**
- * Kiểm tra xem có đặt được bom hay không? nếu có thì đặt bom tại vị trí hiện tại của Bomber
- */
- private void detectPlaceBomb() {
- // TODO: kiểm tra xem phím điều khiển đặt bom có được gõ và giá trị _timeBetweenPutBombs, Game.getBombRate() có thỏa mãn hay không
- // TODO: Game.getBombRate() sẽ trả về số lượng bom có thể đặt liên tiếp tại thời điểm hiện tại
- // TODO: _timeBetweenPutBombs dùng để ngăn chặn Bomber đặt 2 Bomb cùng tại 1 vị trí trong 1 khoảng thời gian quá ngắn
- // TODO: nếu 3 điều kiện trên thỏa mãn thì thực hiện đặt bom bằng placeBomb()
- // TODO: sau khi đặt, nhớ giảm số lượng Bomb Rate và reset _timeBetweenPutBombs về 0
- if(_input.space && Game.getBombRate() > 0 && _timeBetweenPutBombs < 0) {
-
- int xt = Coordinates.pixelToTile(_x + _sprite.getSize() / 2);
- int yt = Coordinates.pixelToTile( (_y + _sprite.getSize() / 2) - _sprite.getSize() ); //subtract half player height and minus 1 y position
-
- placeBomb(xt,yt);
- Game.addBombRate(-1);
-
- _timeBetweenPutBombs = 30;
- }
- }
-
- protected void placeBomb(int x, int y) {
- // TODO: thực hiện tạo đối tượng bom, đặt vào vị trí (x, y)
- Bomb b = new Bomb(x, y, _board);
- _board.addBomb(b);
- Sound.play("BOM_SET");
+ public int getBombLimit() {
+ int countActiveItem = (int) getActiveItems().filter(item -> item instanceof BombItem).count();
+ int bombLimitBonus = countActiveItem * BombItem.BOMB_LIMIT_BONUS;
+ return this.baseBombLimit + bombLimitBonus;
}
- private void clearBombs() {
- Iterator bs = _bombs.iterator();
-
- Bomb b;
- while (bs.hasNext()) {
- b = bs.next();
- if (b.isRemoved()) {
- bs.remove();
- Game.addBombRate(1);
- }
- }
-
+ public int getBombRemainingQuota() {
+ return getBombLimit() - _bombs.size();
}
- @Override
- public void kill() {
- if (!_alive) return;
- _alive = false;
- Sound.play("endgame3");
+ public int getBombRadius() {
+ int countActiveItem = (int) getActiveItems().filter(item -> item instanceof FlameItem).count();
+ int bombRadiusBonus = countActiveItem * FlameItem.BOMB_RADIUS_BONUS;
+ return this.baseBombRadius + bombRadiusBonus;
}
- @Override
- protected void afterKill() {
- if (_timeAfter > 0) --_timeAfter;
- else {
- _board.endGame();
- }
+ public int getBombCooldown() {
+ return bombCooldown;
}
- @Override
- protected void calculateMove() {
- // TODO: xử lý nhận tín hiệu điều khiển hướng đi từ _input và gọi move() để thực hiện di chuyển
- // TODO: nhớ cập nhật lại giá trị cờ _moving khi thay đổi trạng thái di chuyển
- int xa = 0, ya = 0;
- if(_input.up) ya--;
- if(_input.down) ya++;
- if(_input.left) xa--;
- if(_input.right) xa++;
-
- if(xa != 0 || ya != 0) {
- move(xa * Game.getBomberSpeed(), ya * Game.getBomberSpeed());
- _moving = true;
- } else {
- _moving = false;
- }
+ public boolean placeBomb() {
+ if (getBombRemainingQuota() > 0 && bombCooldown < 0) {
+
+ int xt = Coordinates.pixelToTile(_x + _sprite.getSize() / 2);
+ int yt = Coordinates.pixelToTile((_y + _sprite.getSize() / 2) - _sprite.getSize()); // subtract half player
+ // height and minus 1 y
+ // position
+
+ placeBomb(xt, yt);
+
+ bombCooldown = 30;
+ return true;
+ }
+ return false;
}
- @Override
- public boolean canMove(double x, double y) {
- // TODO: kiểm tra có đối tượng tại vị trí chuẩn bị di chuyển đến và có thể di chuyển tới đó hay không
- for (int c = 0; c < 4; c++) { //colision detection for each corner of the player
- double xt = ((_x + x) + c % 2 * 9) / Game.TILES_SIZE; //divide with tiles size to pass to tile coordinate
- double yt = ((_y + y) + c / 2 * 10 - 13) / Game.TILES_SIZE; //these values are the best from multiple tests
-
- Entity a = _board.getEntity(xt, yt, this);
-
- if(!a.collide(this))
- return false;
- }
-
- return true;
- //return false;
+ public void placeBomb(int x, int y) {
+ Bomb b = new Bomb(x, y, getBombRadius(), entityManager);
+ this._bombs.add(b);
+ entityManager.getBombManager().addBomb(b);
+ Sound.play("BOM_SET");
}
- @Override
- public void move(double xa, double ya) {
- // TODO: sử dụng canMove() để kiểm tra xem có thể di chuyển tới điểm đã tính toán hay không và thực hiện thay đổi tọa độ _x, _y
- // TODO: nhớ cập nhật giá trị _direction sau khi di chuyển
- if(xa > 0) _direction = 1;
- if(xa < 0) _direction = 3;
- if(ya > 0) _direction = 2;
- if(ya < 0) _direction = 0;
-
- if(canMove(0, ya)) { //separate the moves for the player can slide when is colliding
- _y += ya;
- }
-
- if(canMove(xa, 0)) {
- _x += xa;
- }
+ private void clearExpiredBombs() {
+ _bombs = _bombs.stream()
+ .filter(bomb -> !bomb.isRemoved())
+ .collect(Collectors.toList());
}
@Override
public boolean collide(Entity e) {
- // TODO: xử lý va chạm với Flame
- // TODO: xử lý va chạm với Enemy
- if(e instanceof Flame){
- this.kill();
+ if (!super.collide(e))
return false;
- }
- if(e instanceof Enemy){
- this.kill();
- return true;
- }
- if( e instanceof LayeredEntity) return(e.collide(this));
return true;
}
- //sprite
- private void chooseSprite() {
- switch (_direction) {
+ // sprite
+ // protected
+ protected void chooseSprite() {
+ switch (getDirection()) {
case 0:
_sprite = Sprite.player_up;
- if (_moving) {
+ if (isMoving()) {
_sprite = Sprite.movingSprite(Sprite.player_up_1, Sprite.player_up_2, _animate, 20);
}
break;
case 1:
_sprite = Sprite.player_right;
- if (_moving) {
+ if (isMoving()) {
_sprite = Sprite.movingSprite(Sprite.player_right_1, Sprite.player_right_2, _animate, 20);
}
break;
case 2:
_sprite = Sprite.player_down;
- if (_moving) {
+ if (isMoving()) {
_sprite = Sprite.movingSprite(Sprite.player_down_1, Sprite.player_down_2, _animate, 20);
}
break;
case 3:
_sprite = Sprite.player_left;
- if (_moving) {
+ if (isMoving()) {
_sprite = Sprite.movingSprite(Sprite.player_left_1, Sprite.player_left_2, _animate, 20);
}
break;
default:
_sprite = Sprite.player_right;
- if (_moving) {
+ if (isMoving()) {
_sprite = Sprite.movingSprite(Sprite.player_right_1, Sprite.player_right_2, _animate, 20);
}
break;
}
}
+
+ @Override
+ public int getPoints() {
+ return 0;
+ }
+
+ private static final List extends Action> VALID_ACTIONS = new ArrayList() {
+ {
+ addAll(ActionConstants.LIST_ACTION_MOVE);
+ add(ActionConstants.PLACE_BOMB);
+ }
+ };
+
+ @Override
+ protected List extends Action> getValidActions() {
+ return VALID_ACTIONS;
+ }
+
+ @Override
+ protected void performAction(Action action, boolean isDryRun)
+ throws InvalidActionException, CannotPerformActionException {
+ super.performAction(action, isDryRun);
+ if (action instanceof ActionPlaceBomb) {
+ if (getBombRemainingQuota() < 0)
+ throw new BombQuotaReachedException();
+ if (bombCooldown > 0)
+ throw new ActionOnCooldownException();
+ if (!isDryRun)
+ placeBomb();
+ }
+ }
+
+ @Override
+ public Stream
- getActiveItems() {
+ return activeItems.stream().filter(Item::isActive);
+ }
+
+ @Override
+ public void addActiveItem(Item item) {
+ this.activeItems.add(item);
+ }
+
+ @Override
+ protected double getSpeedMultiplier() {
+ double speedMultiplier = 1;
+ for (Item item : activeItems) {
+ if (!item.isActive())
+ continue;
+ if (item instanceof SpeedItem) {
+ speedMultiplier += SpeedItem.SPEED_MULTIPLIER;
+ }
+ }
+ return speedMultiplier;
+ }
+
}
diff --git a/src/uet/oop/bomberman/entities/character/Bomber2.java b/src/uet/oop/bomberman/entities/character/Bomber2.java
new file mode 100644
index 0000000..aca61f1
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/Bomber2.java
@@ -0,0 +1,60 @@
+package uet.oop.bomberman.entities.character;
+
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.entities.Entity;
+import uet.oop.bomberman.graphics.Screen;
+import uet.oop.bomberman.graphics.Sprite;
+
+public class Bomber2 extends Bomber {
+
+ public Bomber2(int x, int y, double baseSpeed, int baseBombLimit, int baseBombRadius,
+ IEntityManager entityManager) {
+ super(x, y, baseSpeed, baseBombLimit, baseBombRadius, entityManager);
+ }
+
+ @Override
+ public void render(Screen screen) {
+ if (isAlive())
+ chooseSprite();
+ else
+ _sprite = Sprite.player_dead1;
+
+ screen.renderEntity((int) _x, (int) _y - _sprite.SIZE, this);
+ }
+
+ @Override
+ protected void chooseSprite() {
+ switch (getDirection()) {
+ case 0:
+ _sprite = Sprite.player2_up;
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.player2_up_1, Sprite.player2_up_2, _animate, 20);
+ }
+ break;
+ case 1:
+ _sprite = Sprite.player2_right;
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.player2_right_1, Sprite.player2_right_2, _animate, 20);
+ }
+ break;
+ case 2:
+ _sprite = Sprite.player2_down;
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.player2_down_1, Sprite.player2_down_2, _animate, 20);
+ }
+ break;
+ case 3:
+ _sprite = Sprite.player2_left;
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.player2_left_1, Sprite.player2_left_2, _animate, 20);
+ }
+ break;
+ default:
+ _sprite = Sprite.player2_right;
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.player2_right_1, Sprite.player2_right_2, _animate, 20);
+ }
+ break;
+ }
+ }
+}
diff --git a/src/uet/oop/bomberman/entities/character/CanUseItem.java b/src/uet/oop/bomberman/entities/character/CanUseItem.java
new file mode 100644
index 0000000..0d1103a
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/CanUseItem.java
@@ -0,0 +1,12 @@
+package uet.oop.bomberman.entities.character;
+
+import java.util.stream.Stream;
+
+import uet.oop.bomberman.entities.tile.item.Item;
+
+public interface CanUseItem {
+
+ public Stream
- getActiveItems();
+ public void addActiveItem(Item item);
+
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java
index 52842a9..c3ba74d 100644
--- a/src/uet/oop/bomberman/entities/character/Character.java
+++ b/src/uet/oop/bomberman/entities/character/Character.java
@@ -1,64 +1,297 @@
package uet.oop.bomberman.entities.character;
-import uet.oop.bomberman.Board;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.stream.Collectors;
+
import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.entities.AnimatedEntitiy;
+import uet.oop.bomberman.entities.Entity;
+import uet.oop.bomberman.entities.LayeredEntity;
+import uet.oop.bomberman.entities.bomb.Flame;
+import uet.oop.bomberman.entities.character.action.Action;
+import uet.oop.bomberman.entities.character.action.ActionConstants;
+import uet.oop.bomberman.entities.character.action.ActionMove;
+import uet.oop.bomberman.entities.character.exceptions.ActionOnCooldownException;
+import uet.oop.bomberman.entities.character.exceptions.CannotPerformActionException;
+import uet.oop.bomberman.entities.character.exceptions.CharacterActionException;
+import uet.oop.bomberman.entities.character.exceptions.InvalidActionException;
import uet.oop.bomberman.graphics.Screen;
+import uet.oop.bomberman.level.Coordinates;
/**
* Bao gồm Bomber và Enemy
*/
public abstract class Character extends AnimatedEntitiy {
-
- protected Board _board;
- protected int _direction = -1;
- protected boolean _alive = true;
- protected boolean _moving = false;
- public int _timeAfter = 40;
-
- public Character(int x, int y, Board board) {
+
+ protected IEntityManager entityManager;
+
+ private int direction = -1;
+ private boolean alive = true;
+ private int timerDeathAnimation = 40;
+
+ private final double baseSpeed;
+ private Queue waypoints = new LinkedList<>();
+
+ public Character(int x, int y, double baseSpeed, IEntityManager entityManager) {
_x = x;
_y = y;
- _board = board;
+ this.entityManager = entityManager;
+ this.baseSpeed = baseSpeed;
}
-
+
@Override
- public abstract void update();
-
+ public final void update() {
+ if (!alive) {
+ if (timerDeathAnimation > 0) {
+ timerDeathAnimation -= 1;
+ } else {
+ handleAfterDeath();
+ }
+ return;
+ }
+ updateMove();
+ handleUpdate();
+ };
+
+ protected abstract void handleUpdate();
+
@Override
public abstract void render(Screen screen);
+ private static final List extends Action> VALID_ACTIONS = new ArrayList() {
+ {
+ addAll(ActionConstants.LIST_ACTION_MOVE);
+ add(ActionConstants.DO_NOTHING);
+ }
+ };
+
+ protected List extends Action> getValidActions() {
+ return VALID_ACTIONS;
+ }
+
+ public boolean isValidAction(Action action) {
+ return getValidActions().contains(action);
+ }
+
+ public final void performAction(Action action) throws InvalidActionException, CannotPerformActionException {
+ performAction(action, false);
+ }
+
+ protected void performAction(Action action, boolean isDryRun)
+ throws InvalidActionException, CannotPerformActionException {
+ if (!isValidAction(action))
+ throw new InvalidActionException();
+ if (action instanceof ActionMove) {
+ ActionMove actionMove = (ActionMove) action;
+ double dx = actionMove.getDx() * Game.TILES_SIZE;
+ double dy = actionMove.getDy() * Game.TILES_SIZE;
+ if (isMoving())
+ throw new ActionOnCooldownException();
+ if (!isDryRun)
+ move(dx, dy);
+ }
+ };
+
+ public final boolean canPerformAction(Action action) {
+ try {
+ performAction(action, true);
+ return true;
+ } catch (CharacterActionException ex) {
+ return false;
+ }
+ };
+
+ public List extends Action> getPerformableActions() {
+ return getValidActions().stream()
+ .filter(this::canPerformAction)
+ .collect(Collectors.toList());
+ }
+
/**
- * Tính toán hướng đi
+ * Check if can be moved with vector (xa, ya).
+ *
+ * @param xa
+ * @param ya
*/
- protected abstract void calculateMove();
-
- protected abstract void move(double xa, double ya);
+ public void move(double xa, double ya) {
+ double moveDurationBase = Game.TICKS_PER_SECOND / getSpeed();
+ Waypoint waypointX = new Waypoint(
+ xa,
+ 0,
+ moveDurationBase);
+ Waypoint waypointY = new Waypoint(
+ 0,
+ ya,
+ moveDurationBase);
+ if (xa != 0 && ya != 0 && canMove(xa, ya) && canMove(xa, 0)) {
+ waypoints.add(waypointX);
+ waypoints.add(waypointY);
+ } else if (xa != 0 && ya != 0 && canMove(xa, ya) && canMove(0, ya)) {
+ waypoints.add(waypointY);
+ waypoints.add(waypointX);
+ } else if (xa != 0 && canMove(xa, 0)) {
+ waypoints.add(waypointX);
+ } else if (ya != 0 && canMove(0, ya)) {
+ waypoints.add(waypointY);
+ } else {
+ System.out.println(String.format(
+ "Cannot move character %s to (%s, %s)",
+ getClass().getSimpleName(), xa, ya));
+ }
+ }
+
+ private void updateMove() {
+ if (waypoints.isEmpty())
+ return;
+ Waypoint waypoint = waypoints.peek();
+ if (!waypoint.started) {
+ waypoint.started = true;
+ waypoint.moveDestX = _x + waypoint.moveX;
+ waypoint.moveDestY = _y + waypoint.moveY;
+ }
+
+ waypoint.moveDuration -= 1;
+ if (waypoint.moveDuration > 0) {
+ _x += waypoint.moveDx;
+ _y += waypoint.moveDy;
+ } else {
+ // Correct rounding errors by force teleporting to destination
+ _x = waypoint.moveDestX;
+ _y = waypoint.moveDestY;
+ // Remove waypoint
+ waypoints.poll();
+ }
+
+ // Adjust direction
+ if (waypoint.moveDx > 0)
+ direction = 1;
+ if (waypoint.moveDx < 0)
+ direction = 3;
+ if (waypoint.moveDy > 0)
+ direction = 2;
+ if (waypoint.moveDy < 0)
+ direction = 0;
+
+ Entity collidingEntity = entityManager.getEntityAtExcluding(
+ Coordinates.pixelToTile(getCenterX()),
+ Coordinates.pixelToTile(getCenterY()),
+ this);
+ if (collidingEntity != null) {
+ this.collide(collidingEntity);
+ collidingEntity.collide(this);
+ }
+ }
/**
* Được gọi khi đối tượng bị tiêu diệt
*/
- public abstract void kill();
+ public final void handleOnDeath() {
+ if (!alive)
+ return;
+ alive = false;
+ // TODO: determine killer
+ entityManager.getCharacterManager().handleOnDeath(this, null);
+ }
/**
* Xử lý hiệu ứng bị tiêu diệt
*/
- protected abstract void afterKill();
+ private void handleAfterDeath() {
+ entityManager.getCharacterManager().handleAfterDeath(this);
+ remove();
+ }
/**
* Kiểm tra xem đối tượng có di chuyển tới vị trí đã tính toán hay không
+ *
* @param x
* @param y
* @return
*/
- protected abstract boolean canMove(double x, double y);
+ public boolean canMove(double dx, double dy) {
+ double x = getCenterX() + dx;
+ double y = getCenterY() + dy;
+ Entity a = entityManager.getEntityAtExcluding(
+ Coordinates.pixelToTile(x),
+ Coordinates.pixelToTile(y),
+ this);
+ if (a == null)
+ return true;
+ return a.canBePassedThroughBy(this);
+ }
protected double getXMessage() {
return (_x * Game.SCALE) + (_sprite.SIZE / 2 * Game.SCALE);
}
-
+
protected double getYMessage() {
- return (_y* Game.SCALE) - (_sprite.SIZE / 2 * Game.SCALE);
+ return (_y * Game.SCALE) - (_sprite.SIZE / 2 * Game.SCALE);
+ }
+
+ public boolean isPlayer() {
+ return entityManager.getPlayers().contains(this);
+ }
+
+ public boolean isAlive() {
+ return alive;
+ }
+
+ public boolean isMoving() {
+ return waypoints.size() > 0;
+ }
+
+ public final double getSpeed() {
+ double speedMultiplier = getSpeedMultiplier();
+ return speedMultiplier * this.baseSpeed;
+ }
+
+ protected double getSpeedMultiplier() {
+ return 1;
+ }
+
+ public abstract int getPoints();
+
+ public int getDirection() {
+ return direction;
+ }
+
+ public int getTimerDeathAnimation() {
+ return timerDeathAnimation;
}
-
+
+ public void setTimerDeathAnimation(int timerDeathAnimation) {
+ this.timerDeathAnimation = timerDeathAnimation;
+ }
+
+ @Override
+ public boolean collide(Entity e) {
+ if (e instanceof Flame) {
+ this.handleOnDeath();
+ return false;
+ }
+ if (e instanceof Character) {
+ Character other = (Character) e;
+ if (this.isPlayer() && !other.isPlayer()) {
+ this.handleOnDeath();
+ return false;
+ }
+ if (other.isPlayer() && !this.isPlayer()) {
+ other.handleOnDeath();
+ return false;
+ }
+ }
+ if (e instanceof LayeredEntity)
+ return (e.collide(this));
+ return true;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return true;
+ }
+
}
diff --git a/src/uet/oop/bomberman/entities/character/Waypoint.java b/src/uet/oop/bomberman/entities/character/Waypoint.java
new file mode 100644
index 0000000..417df96
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/Waypoint.java
@@ -0,0 +1,21 @@
+package uet.oop.bomberman.entities.character;
+
+class Waypoint {
+ double moveX;
+ double moveY;
+ double moveDuration;
+ double moveDx;
+ double moveDy;
+
+ public boolean started = false;
+ public double moveDestX;
+ public double moveDestY;
+
+ public Waypoint(double moveX, double moveY, double moveDuration) {
+ this.moveX = moveX;
+ this.moveY = moveY;
+ this.moveDuration = moveDuration;
+ this.moveDx = moveX / moveDuration;
+ this.moveDy = moveY / moveDuration;
+ }
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/entities/character/action/Action.java b/src/uet/oop/bomberman/entities/character/action/Action.java
new file mode 100644
index 0000000..13b7f5a
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/action/Action.java
@@ -0,0 +1,4 @@
+package uet.oop.bomberman.entities.character.action;
+
+public abstract class Action {
+}
diff --git a/src/uet/oop/bomberman/entities/character/action/ActionConstants.java b/src/uet/oop/bomberman/entities/character/action/ActionConstants.java
new file mode 100644
index 0000000..332f398
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/action/ActionConstants.java
@@ -0,0 +1,32 @@
+package uet.oop.bomberman.entities.character.action;
+
+import java.util.Arrays;
+import java.util.List;
+
+public interface ActionConstants {
+
+ public static final ActionMove MOVE_UP = new ActionMove(0, -1);
+ public static final ActionMove MOVE_DOWN = new ActionMove(0, +1);
+ public static final ActionMove MOVE_LEFT = new ActionMove(-1, 0);
+ public static final ActionMove MOVE_RIGHT = new ActionMove(+1, 0);
+
+ public static final ActionMove MOVE_UP_LEFT = new ActionMove(-1, -1);
+ public static final ActionMove MOVE_UP_RIGHT = new ActionMove(+1, -1);
+ public static final ActionMove MOVE_DOWN_LEFT = new ActionMove(-1, +1);
+ public static final ActionMove MOVE_DOWN_RIGHT = new ActionMove(+1, +1);
+
+ public static final List LIST_ACTION_MOVE = Arrays.asList(new ActionMove[] {
+ MOVE_UP,
+ MOVE_DOWN,
+ MOVE_LEFT,
+ MOVE_RIGHT,
+ MOVE_UP_LEFT,
+ MOVE_UP_RIGHT,
+ MOVE_DOWN_LEFT,
+ MOVE_DOWN_RIGHT,
+ });
+
+ public static final ActionPlaceBomb PLACE_BOMB = new ActionPlaceBomb();
+ public static final Action DO_NOTHING = new ActionNoop();
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/action/ActionMove.java b/src/uet/oop/bomberman/entities/character/action/ActionMove.java
new file mode 100644
index 0000000..38ed878
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/action/ActionMove.java
@@ -0,0 +1,45 @@
+package uet.oop.bomberman.entities.character.action;
+
+import java.util.Objects;
+
+public class ActionMove extends Action {
+
+ private final double dx;
+ private final double dy;
+
+ public ActionMove(double dx, double dy) {
+ this.dx = dx;
+ this.dy = dy;
+ }
+
+ public double getDx() {
+ return dx;
+ }
+
+ public double getDy() {
+ return dy;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(dx, dy);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ActionMove other = (ActionMove) obj;
+ if (Double.doubleToLongBits(dx) != Double.doubleToLongBits(other.dx))
+ return false;
+ if (Double.doubleToLongBits(dy) != Double.doubleToLongBits(other.dy))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/action/ActionNoop.java b/src/uet/oop/bomberman/entities/character/action/ActionNoop.java
new file mode 100644
index 0000000..df0795b
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/action/ActionNoop.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.action;
+
+public class ActionNoop extends Action {
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/action/ActionPlaceBomb.java b/src/uet/oop/bomberman/entities/character/action/ActionPlaceBomb.java
new file mode 100644
index 0000000..93b6556
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/action/ActionPlaceBomb.java
@@ -0,0 +1,21 @@
+package uet.oop.bomberman.entities.character.action;
+
+public class ActionPlaceBomb extends Action {
+
+ protected ActionPlaceBomb() {}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Balloon.java b/src/uet/oop/bomberman/entities/character/enemy/Balloon.java
index e0d43dc..2cee00e 100644
--- a/src/uet/oop/bomberman/entities/character/enemy/Balloon.java
+++ b/src/uet/oop/bomberman/entities/character/enemy/Balloon.java
@@ -1,35 +1,29 @@
package uet.oop.bomberman.entities.character.enemy;
-import static java.lang.Math.random;
-import java.util.Random;
-import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
-import uet.oop.bomberman.entities.character.enemy.ai.AILow;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.graphics.Sprite;
public class Balloon extends Enemy {
- public Balloon(int x, int y, Board board) {
- super(x, y, board, Sprite.balloom_dead, 0.5, 100);
+ public Balloon(int x, int y, IEntityManager entityManager) {
+ super(x, y, entityManager, Sprite.balloom_dead, Game.BOMBERSPEED / 2, 100);
_sprite = Sprite.balloom_left1;
- _ai = new AILow();
- _direction = _ai.calculateDirection();
-
}
@Override
protected void chooseSprite() {
- switch(_direction) {
+ switch(getDirection()) {
case 0:
case 1:
- _sprite = Sprite.movingSprite(Sprite.balloom_right1, Sprite.balloom_right2, Sprite.balloom_right3, _animate, 60);
+ _sprite = Sprite.movingSprite(Sprite.balloom_right1, Sprite.balloom_right2, Sprite.balloom_right3, _animate, Game.TICKS_PER_SECOND);
break;
case 2:
case 3:
- _sprite = Sprite.movingSprite(Sprite.balloom_left1, Sprite.balloom_left2, Sprite.balloom_left3, _animate, 60);
+ _sprite = Sprite.movingSprite(Sprite.balloom_left1, Sprite.balloom_left2, Sprite.balloom_left3, _animate, Game.TICKS_PER_SECOND);
break;
}
}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Doll.java b/src/uet/oop/bomberman/entities/character/enemy/Doll.java
index dc85fce..b4e2b0e 100644
--- a/src/uet/oop/bomberman/entities/character/enemy/Doll.java
+++ b/src/uet/oop/bomberman/entities/character/enemy/Doll.java
@@ -5,42 +5,36 @@
*/
package uet.oop.bomberman.entities.character.enemy;
-import uet.oop.bomberman.Board;
-import uet.oop.bomberman.entities.character.enemy.ai.AILow;
-import uet.oop.bomberman.entities.character.enemy.ai.AIMedium;
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.graphics.Sprite;
-/**
- *
- * @author TUNG318
- */
-public class Doll extends Enemy{
-
- public Doll(int x, int y, Board board) {
- super(x, y, board, Sprite.balloom_dead, 0.8, 100);
+public class Doll extends Enemy {
- _sprite = Sprite.balloom_left1;
+ public Doll(int x, int y, IEntityManager entityManager) {
+ super(x, y, entityManager, Sprite.balloom_dead, Game.BOMBERSPEED, 100);
- _ai = new AIMedium(_board.getBomber(), this);
- _direction = _ai.calculateDirection();
+ _sprite = Sprite.doll_left1;
}
@Override
protected void chooseSprite() {
- switch (_direction) {
+ switch (getDirection()) {
case 0:
case 1:
- if (_moving) {
- _sprite = Sprite.movingSprite(Sprite.doll_right1, Sprite.doll_right2, Sprite.doll_right3, _animate, 60);
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.doll_right1, Sprite.doll_right2, Sprite.doll_right3, _animate,
+ Game.TICKS_PER_SECOND);
} else {
_sprite = Sprite.doll_left1;
}
break;
case 2:
case 3:
- if (_moving) {
- _sprite = Sprite.movingSprite(Sprite.doll_left1, Sprite.doll_left2, Sprite.doll_left3, _animate, 60);
+ if (isMoving()) {
+ _sprite = Sprite.movingSprite(Sprite.doll_left1, Sprite.doll_left2, Sprite.doll_left3, _animate,
+ Game.TICKS_PER_SECOND);
} else {
_sprite = Sprite.doll_left1;
}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java
index 61a7b99..3839cb9 100644
--- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java
+++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java
@@ -1,26 +1,17 @@
package uet.oop.bomberman.entities.character.enemy;
-import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.Message;
-import uet.oop.bomberman.entities.bomb.Flame;
-import uet.oop.bomberman.entities.character.Bomber;
import uet.oop.bomberman.entities.character.Character;
-import uet.oop.bomberman.entities.character.enemy.ai.AI;
import uet.oop.bomberman.graphics.Screen;
import uet.oop.bomberman.graphics.Sprite;
-import uet.oop.bomberman.level.Coordinates;
-
-import java.awt.*;
-import uet.oop.bomberman.sound.Sound;
public abstract class Enemy extends Character {
protected int _points;
protected double _speed;
- protected AI _ai;
protected final double MAX_STEPS;
protected final double rest;
@@ -28,10 +19,10 @@ public abstract class Enemy extends Character {
protected int _finalAnimation = 30;
protected Sprite _deadSprite;
-
- public Enemy(int x, int y, Board board, Sprite dead, double speed, int points) {
- super(x, y, board);
-
+
+ public Enemy(int x, int y, IEntityManager entityManager, Sprite dead, double speed, int points) {
+ super(x, y, speed, entityManager);
+
_points = points;
_speed = speed;
@@ -39,34 +30,25 @@ public Enemy(int x, int y, Board board, Sprite dead, double speed, int points) {
rest = (MAX_STEPS - (int) MAX_STEPS) / MAX_STEPS;
_steps = MAX_STEPS;
- _timeAfter = 20;
+ setTimerDeathAnimation(20);
_deadSprite = dead;
}
@Override
- public void update() {
+ public void handleUpdate() {
animate();
-
- if(!_alive) {
- afterKill();
- return;
- }
-
- if(_alive)
- calculateMove();
}
@Override
public void render(Screen screen) {
-
- if(_alive)
+ if(isAlive())
chooseSprite();
else {
- if(_timeAfter > 0) {
+ if(getTimerDeathAnimation() > 0) {
_sprite = _deadSprite;
_animate = 0;
} else {
- _sprite = Sprite.movingSprite(Sprite.mob_dead1, Sprite.mob_dead2, Sprite.mob_dead3, _animate, 60);
+ _sprite = Sprite.movingSprite(Sprite.mob_dead1, Sprite.mob_dead2, Sprite.mob_dead3, _animate, Game.TICKS_PER_SECOND);
}
}
@@ -74,94 +56,16 @@ public void render(Screen screen) {
screen.renderEntity((int)_x, (int)_y - _sprite.SIZE, this);
}
- @Override
- public void calculateMove() {
- // TODO: Tính toán hướng đi và di chuyển Enemy theo _ai và cập nhật giá trị cho _direction
- // TODO: sử dụng canMove() để kiểm tra xem có thể di chuyển tới điểm đã tính toán hay không
- // TODO: sử dụng move() để di chuyển
- // TODO: nhớ cập nhật lại giá trị cờ _moving khi thay đổi trạng thái di chuyển
- int xa = 0, ya = 0;
- if(_steps <= 0){
- _direction = _ai.calculateDirection();
- _steps = MAX_STEPS;
- }
-
- if(_direction == 0) ya--;
- if(_direction == 2) ya++;
- if(_direction == 3) xa--;
- if(_direction == 1) xa++;
-
- if(canMove(xa, ya)) {
- _steps -= 1 + rest;
- move(xa * _speed, ya * _speed);
- _moving = true;
- } else {
- _steps = 0;
- _moving = false;
- }
- }
-
- @Override
- public void move(double xa, double ya) {
- if(!_alive) return;
- _y += ya;
- _x += xa;
- }
-
- @Override
- public boolean canMove(double x, double y) {
- double xr = _x, yr = _y - 16; //subtract y to get more accurate results
-
- //the thing is, subract 15 to 16 (sprite size), so if we add 1 tile we get the next pixel tile with this
- //we avoid the shaking inside tiles with the help of steps
- if(_direction == 0) { yr += _sprite.getSize() -1 ; xr += _sprite.getSize()/2; }
- if(_direction == 1) {yr += _sprite.getSize()/2; xr += 1;}
- if(_direction == 2) { xr += _sprite.getSize()/2; yr += 1;}
- if(_direction == 3) { xr += _sprite.getSize() -1; yr += _sprite.getSize()/2;}
-
- int xx = Coordinates.pixelToTile(xr) +(int)x;
- int yy = Coordinates.pixelToTile(yr) +(int)y;
-
- Entity a = _board.getEntity(xx, yy, this); //entity of the position we want to go
-
- return a.collide(this);
- }
-
@Override
public boolean collide(Entity e) {
- if(e instanceof Flame){
- this.kill();
- return false;
- }
- if(e instanceof Bomber){
- ((Bomber) e).kill();
- return false;
- }
+ if (!super.collide(e)) return false;
return true;
}
- @Override
- public void kill() {
- if(!_alive) return;
- _alive = false;
-
- _board.addPoints(_points);
+ protected abstract void chooseSprite();
- Message msg = new Message("+" + _points, getXMessage(), getYMessage(), 2, Color.white, 14);
- _board.addMessage(msg);
- Sound.play("AA126_11");
- }
-
-
@Override
- protected void afterKill() {
- if(_timeAfter > 0) --_timeAfter;
- else {
- if(_finalAnimation > 0) --_finalAnimation;
- else
- remove();
- }
+ public int getPoints() {
+ return _points;
}
-
- protected abstract void chooseSprite();
}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java
new file mode 100644
index 0000000..0f7db66
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java
@@ -0,0 +1,36 @@
+package uet.oop.bomberman.entities.character.enemy;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.graphics.Sprite;
+
+public class Kondoria extends Enemy {
+ public Kondoria(int x, int y, IEntityManager entityManager) {
+ super(x, y, entityManager, Sprite.balloom_dead, Game.BOMBERSPEED / 4, 1000);
+
+ _sprite = Sprite.kondoria_right1;
+
+ }
+
+ @Override
+ protected void chooseSprite() {
+ switch (getDirection()) {
+ case 0:
+ case 1:
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.kondoria_right1, Sprite.kondoria_right2,
+ Sprite.kondoria_right3, _animate, Game.TICKS_PER_SECOND);
+ else
+ _sprite = Sprite.kondoria_left1;
+ break;
+ case 2:
+ case 3:
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.kondoria_left1, Sprite.kondoria_left2, Sprite.kondoria_left3,
+ _animate, Game.TICKS_PER_SECOND);
+ else
+ _sprite = Sprite.kondoria_left1;
+ break;
+ }
+ }
+}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java
new file mode 100644
index 0000000..43cf3c4
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java
@@ -0,0 +1,34 @@
+package uet.oop.bomberman.entities.character.enemy;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.graphics.Sprite;
+
+public class Minvo extends Enemy {
+ public Minvo(int x, int y, IEntityManager entityManager) {
+ super(x, y, entityManager, Sprite.minvo_dead, Game.BOMBERSPEED * 1.5, 800);
+ _sprite = Sprite.minvo_right1;
+ }
+
+ @Override
+ protected void chooseSprite() {
+ switch (getDirection()) {
+ case 0:
+ case 1:
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.minvo_right1, Sprite.minvo_right2, Sprite.minvo_right3,
+ _animate, Game.TICKS_PER_SECOND);
+ else
+ _sprite = Sprite.minvo_left1;
+ break;
+ case 2:
+ case 3:
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.minvo_left1, Sprite.minvo_left2, Sprite.minvo_left3, _animate,
+ Game.TICKS_PER_SECOND);
+ else
+ _sprite = Sprite.minvo_left1;
+ break;
+ }
+ }
+}
diff --git a/src/uet/oop/bomberman/entities/character/enemy/Oneal.java b/src/uet/oop/bomberman/entities/character/enemy/Oneal.java
index 3ad4b23..e353833 100644
--- a/src/uet/oop/bomberman/entities/character/enemy/Oneal.java
+++ b/src/uet/oop/bomberman/entities/character/enemy/Oneal.java
@@ -1,40 +1,33 @@
package uet.oop.bomberman.entities.character.enemy;
-
-import java.util.Random;
-import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
-import uet.oop.bomberman.entities.character.enemy.ai.AILow;
-import uet.oop.bomberman.entities.character.enemy.ai.AIMedium;
+import uet.oop.bomberman.base.IEntityManager;
import uet.oop.bomberman.graphics.Sprite;
public class Oneal extends Enemy {
- //private Random random = new Random();
- public Oneal(int x, int y, Board board) {
- super(x, y, board, Sprite.balloom_dead, 0.8 , 100);
-
- _sprite = Sprite.balloom_left1;
-
- _ai = new AILow();
- _direction = _ai.calculateDirection();
- //this._speed += random.nextDouble()/2;
-
+ // private Random random = new Random();
+ public Oneal(int x, int y, IEntityManager entityManager) {
+ super(x, y, entityManager, Sprite.balloom_dead, Game.BOMBERSPEED, 100);
+
+ _sprite = Sprite.oneal_left1;
}
-
+
@Override
protected void chooseSprite() {
- switch(_direction) {
+ switch (getDirection()) {
case 0:
case 1:
- if(_moving)
- _sprite = Sprite.movingSprite(Sprite.oneal_right1, Sprite.oneal_right2, Sprite.oneal_right3, _animate, 60);
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.oneal_right1, Sprite.oneal_right2, Sprite.oneal_right3,
+ _animate, Game.TICKS_PER_SECOND);
else
_sprite = Sprite.oneal_left1;
break;
case 2:
case 3:
- if(_moving)
- _sprite = Sprite.movingSprite(Sprite.oneal_left1, Sprite.oneal_left2, Sprite.oneal_left3, _animate, 60);
+ if (isMoving())
+ _sprite = Sprite.movingSprite(Sprite.oneal_left1, Sprite.oneal_left2, Sprite.oneal_left3, _animate,
+ Game.TICKS_PER_SECOND);
else
_sprite = Sprite.oneal_left1;
break;
diff --git a/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java b/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java
index 1fa7960..9ad759f 100644
--- a/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java
+++ b/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java
@@ -1,23 +1,21 @@
package uet.oop.bomberman.entities.character.enemy.ai;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.character.enemy.Enemy;
+import uet.oop.bomberman.base.ICharacterManager;
+import uet.oop.bomberman.entities.character.Character;
public class AIMedium extends AI {
- Bomber _bomber;
- Enemy _e;
+
+ private final Character character;
+ private final ICharacterManager characterManager;
- public AIMedium(Bomber bomber, Enemy e) {
- _bomber = bomber;
- _e = e;
+ public AIMedium(Character character, ICharacterManager entityManager) {
+ this.character = character;
+ this.characterManager = entityManager;
}
@Override
public int calculateDirection() {
- // TODO: cài đặt thuật toán tìm đường đi
- if(_bomber == null)
- return random.nextInt(4);
-
+
int vertical = random.nextInt(2);
if(vertical == 1) {
@@ -36,19 +34,24 @@ public int calculateDirection() {
return calculateRowDirection();
}
}
- protected int calculateColDirection() {
- if(_bomber.getXTile() < _e.getXTile())
+
+ protected int calculateColDirection() {
+ Character player = characterManager.getPlayer();
+
+ if(player.getXTile() < character.getXTile())
return 3;
- else if(_bomber.getXTile() > _e.getXTile())
+ else if(player.getXTile() > character.getXTile())
return 1;
return -1;
}
protected int calculateRowDirection() {
- if(_bomber.getYTile() < _e.getYTile())
+ Character player = characterManager.getPlayer();
+
+ if(player.getYTile() < character.getYTile())
return 0;
- else if(_bomber.getYTile() > _e.getYTile())
+ else if(player.getYTile() > character.getYTile())
return 2;
return -1;
}
diff --git a/src/uet/oop/bomberman/entities/character/exceptions/ActionOnCooldownException.java b/src/uet/oop/bomberman/entities/character/exceptions/ActionOnCooldownException.java
new file mode 100644
index 0000000..665dc0c
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/exceptions/ActionOnCooldownException.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.exceptions;
+
+public class ActionOnCooldownException extends CannotPerformActionException {
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/exceptions/BombQuotaReachedException.java b/src/uet/oop/bomberman/entities/character/exceptions/BombQuotaReachedException.java
new file mode 100644
index 0000000..6d263d8
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/exceptions/BombQuotaReachedException.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.exceptions;
+
+public class BombQuotaReachedException extends CannotPerformActionException {
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/exceptions/CannotPerformActionException.java b/src/uet/oop/bomberman/entities/character/exceptions/CannotPerformActionException.java
new file mode 100644
index 0000000..eea7279
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/exceptions/CannotPerformActionException.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.exceptions;
+
+public class CannotPerformActionException extends CharacterActionException {
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/exceptions/CharacterActionException.java b/src/uet/oop/bomberman/entities/character/exceptions/CharacterActionException.java
new file mode 100644
index 0000000..7ce9a17
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/exceptions/CharacterActionException.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.exceptions;
+
+public class CharacterActionException extends Exception {
+
+}
diff --git a/src/uet/oop/bomberman/entities/character/exceptions/InvalidActionException.java b/src/uet/oop/bomberman/entities/character/exceptions/InvalidActionException.java
new file mode 100644
index 0000000..43dc374
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/character/exceptions/InvalidActionException.java
@@ -0,0 +1,5 @@
+package uet.oop.bomberman.entities.character.exceptions;
+
+public class InvalidActionException extends CharacterActionException {
+
+}
diff --git a/src/uet/oop/bomberman/entities/tile/Grass.java b/src/uet/oop/bomberman/entities/tile/Grass.java
index 6046143..acd57c0 100644
--- a/src/uet/oop/bomberman/entities/tile/Grass.java
+++ b/src/uet/oop/bomberman/entities/tile/Grass.java
@@ -4,7 +4,7 @@
import uet.oop.bomberman.entities.Entity;
import uet.oop.bomberman.graphics.Sprite;
-public class Grass extends Tile {
+public class Grass extends NonDestroyableTile {
public Grass(int x, int y, Sprite sprite) {
super(x, y, sprite);
@@ -19,4 +19,9 @@ public Grass(int x, int y, Sprite sprite) {
public boolean collide(Entity e) {
return true;
}
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return true;
+ }
}
diff --git a/src/uet/oop/bomberman/entities/tile/NonDestroyableTile.java b/src/uet/oop/bomberman/entities/tile/NonDestroyableTile.java
new file mode 100644
index 0000000..53b7101
--- /dev/null
+++ b/src/uet/oop/bomberman/entities/tile/NonDestroyableTile.java
@@ -0,0 +1,16 @@
+package uet.oop.bomberman.entities.tile;
+
+import uet.oop.bomberman.graphics.Sprite;
+
+public abstract class NonDestroyableTile extends Tile {
+
+ public NonDestroyableTile(int x, int y, Sprite sprite) {
+ super(x, y, sprite);
+ }
+
+ @Override
+ public boolean isDestroyable() {
+ return false;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/entities/tile/Portal.java b/src/uet/oop/bomberman/entities/tile/Portal.java
index 9b077d7..a9cf4ec 100644
--- a/src/uet/oop/bomberman/entities/tile/Portal.java
+++ b/src/uet/oop/bomberman/entities/tile/Portal.java
@@ -1,40 +1,45 @@
package uet.oop.bomberman.entities.tile;
import uet.oop.bomberman.Board;
-import uet.oop.bomberman.Game;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.tile.item.Item;
+import uet.oop.bomberman.entities.character.Character;
import uet.oop.bomberman.graphics.Sprite;
import uet.oop.bomberman.sound.Sound;
-public class Portal extends Tile {
- protected Board _board;
- public Portal(int x, int y,Board board, Sprite sprite) {
+public class Portal extends NonDestroyableTile {
+ protected Board _board;
+
+ public Portal(int x, int y, Board board, Sprite sprite) {
super(x, y, sprite);
- _board = board;
+ _board = board;
}
-
+
@Override
- public boolean collide(Entity e) {//xu li khi 2 entity va cham
- //true cho di qua
- //false khong cho di qua
+ public boolean collide(Entity e) {// xu li khi 2 entity va cham
+ // true cho di qua
+ // false khong cho di qua
// TODO: xử lý khi Bomber đi vào
- if(e instanceof Bomber ) {
-
- if(_board.detectNoEnemies() == false)
- return false;
-
- if(e.getXTile() == getX() && e.getYTile() == getY()) {
- if(_board.detectNoEnemies()){
- _board.nextLevel();
- Sound.play("CRYST_UP");
- }
+ if (e instanceof Character && ((Character) e).isPlayer()) {
+
+ if (canBePassedThroughBy(e)) {
+ _board.nextLevel();
+ Sound.play("CRYST_UP");
}
-
+
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ if (other instanceof Character && ((Character) other).isPlayer()) {
+
+ if (!_board.getEntityManager().isEnemyCleared())
+ return false;
+
return true;
}
-
return true;
}
diff --git a/src/uet/oop/bomberman/entities/tile/Tile.java b/src/uet/oop/bomberman/entities/tile/Tile.java
index 33f9272..f2036c9 100644
--- a/src/uet/oop/bomberman/entities/tile/Tile.java
+++ b/src/uet/oop/bomberman/entities/tile/Tile.java
@@ -26,6 +26,12 @@ public boolean collide(Entity e) {
return false;//khong cho di qua
}
+
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return false;
+ }
+
@Override
public void render(Screen screen) {
screen.renderEntity( Coordinates.tileToPixel(_x), Coordinates.tileToPixel(_y), this);
@@ -33,4 +39,6 @@ public void render(Screen screen) {
@Override
public void update() {}
+
+ public abstract boolean isDestroyable();
}
diff --git a/src/uet/oop/bomberman/entities/tile/Wall.java b/src/uet/oop/bomberman/entities/tile/Wall.java
index 3af3dad..4404dc1 100644
--- a/src/uet/oop/bomberman/entities/tile/Wall.java
+++ b/src/uet/oop/bomberman/entities/tile/Wall.java
@@ -3,7 +3,7 @@
import uet.oop.bomberman.graphics.Sprite;
-public class Wall extends Tile {
+public class Wall extends NonDestroyableTile {
public Wall(int x, int y, Sprite sprite) {
super(x, y, sprite);
diff --git a/src/uet/oop/bomberman/entities/tile/destroyable/DestroyableTile.java b/src/uet/oop/bomberman/entities/tile/destroyable/DestroyableTile.java
index 5148855..6c2683f 100644
--- a/src/uet/oop/bomberman/entities/tile/destroyable/DestroyableTile.java
+++ b/src/uet/oop/bomberman/entities/tile/destroyable/DestroyableTile.java
@@ -42,6 +42,11 @@ public boolean collide(Entity e) {
return false;
}
+ @Override
+ public boolean canBePassedThroughBy(Entity other) {
+ return false;
+ }
+
public void addBelowSprite(Sprite sprite) {
_belowSprite = sprite;
}
@@ -59,5 +64,10 @@ protected Sprite movingSprite(Sprite normal, Sprite x1, Sprite x2) {
return x2;
}
+
+ @Override
+ public boolean isDestroyable() {
+ return true;
+ }
}
diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java
index cfdceba..a288df4 100644
--- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java
+++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java
@@ -1,27 +1,25 @@
package uet.oop.bomberman.entities.tile.item;
-import uet.oop.bomberman.Game;
-import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
import uet.oop.bomberman.graphics.Sprite;
-import uet.oop.bomberman.sound.Sound;
public class BombItem extends Item {
+ public static final int BOMB_LIMIT_BONUS = 1;
+
public BombItem(int x, int y, Sprite sprite) {
super(x, y, sprite);
}
@Override
- public boolean collide(Entity e) {
- // TODO: xử lý Bomber ăn Item
- if (e instanceof Bomber) {
-
- Sound.play("Item");
- Game.addBombRate(1);
- remove();
- }
- return false;
+ protected void handleItemActive() {
+ }
+
+ @Override
+ protected void handleItemInactive() {
}
+ @Override
+ public String getDisplayActiveItem() {
+ return "Bomb:";
+ }
}
diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java
index e251754..cf3c0d1 100644
--- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java
+++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java
@@ -1,26 +1,25 @@
package uet.oop.bomberman.entities.tile.item;
-import uet.oop.bomberman.Game;
-import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
import uet.oop.bomberman.graphics.Sprite;
-import uet.oop.bomberman.sound.Sound;
public class FlameItem extends Item {
+ public static final int BOMB_RADIUS_BONUS = 1;
+
public FlameItem(int x, int y, Sprite sprite) {
super(x, y, sprite);
}
@Override
- public boolean collide(Entity e) {
- // TODO: xử lý Bomber ăn
- if (e instanceof Bomber) {
-
- Sound.play("Item");
- Game.addBombRadius(1);
- remove();
- }
- return false;
+ protected void handleItemActive() {
+ }
+
+ @Override
+ protected void handleItemInactive() {
+ }
+
+ @Override
+ public String getDisplayActiveItem() {
+ return "Flame:";
}
}
diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java
index b3a1b8f..f48d13c 100644
--- a/src/uet/oop/bomberman/entities/tile/item/Item.java
+++ b/src/uet/oop/bomberman/entities/tile/item/Item.java
@@ -1,17 +1,66 @@
package uet.oop.bomberman.entities.tile.item;
+import uet.oop.bomberman.Game;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
-import uet.oop.bomberman.entities.tile.Tile;
+import uet.oop.bomberman.entities.character.CanUseItem;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.tile.NonDestroyableTile;
import uet.oop.bomberman.graphics.Sprite;
import uet.oop.bomberman.sound.Sound;
-public abstract class Item extends Tile {
- protected int _duration = -1; //thoi gian cua item ,-1 la vo han
+public abstract class Item extends NonDestroyableTile {
+ protected int _duration = 30 * Game.TICKS_PER_SECOND; // 30s
protected boolean _active = false;
+
protected int _level;
+
public Item(int x, int y, Sprite sprite) {
super(x, y, sprite);
}
-
+
+ protected abstract void handleItemActive();
+
+ protected abstract void handleItemInactive();
+
+ @Override
+ public boolean collide(Entity e) {
+ if (isRemoved())
+ return false;
+ if (e instanceof CanUseItem) {
+ CanUseItem player = (CanUseItem) e;
+ Sound.play("Item");
+ handleItemActive();
+ _active = true;
+ player.addActiveItem(this);
+ remove();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canBePassedThroughBy(Entity e) {
+ return (e instanceof CanUseItem);
+ }
+
+ @Override
+ public void update() {
+ if (!_active)
+ return;
+ if (_duration > 0) {
+ _duration--;
+ } else {
+ handleItemInactive();
+ _active = false;
+ }
+ }
+
+ public int getDuration() {
+ return _duration;
+ }
+
+ public abstract String getDisplayActiveItem();
+
+ public boolean isActive() {
+ return _active;
+ }
}
diff --git a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java
index 7bc50b7..bcdeb48 100644
--- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java
+++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java
@@ -1,26 +1,25 @@
package uet.oop.bomberman.entities.tile.item;
-import uet.oop.bomberman.Game;
-import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
import uet.oop.bomberman.graphics.Sprite;
-import uet.oop.bomberman.sound.Sound;
public class SpeedItem extends Item {
+ public static final double SPEED_MULTIPLIER = 0.5;
+
public SpeedItem(int x, int y, Sprite sprite) {
super(x, y, sprite);
}
@Override
- public boolean collide(Entity e) {
- // TODO: xử lý Bomber ăn Item
- if (e instanceof Bomber) {
-
- Sound.play("Item");
- Game.addBomberSpeed(0.5);
- remove();
- }
- return false;
+ protected void handleItemActive() {
+ }
+
+ @Override
+ protected void handleItemInactive() {
+ }
+
+ @Override
+ public String getDisplayActiveItem() {
+ return "Speed:";
}
}
diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java
index 2494ea2..7b6e207 100644
--- a/src/uet/oop/bomberman/graphics/Screen.java
+++ b/src/uet/oop/bomberman/graphics/Screen.java
@@ -3,7 +3,7 @@
import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
import uet.oop.bomberman.entities.Entity;
-import uet.oop.bomberman.entities.character.Bomber;
+import uet.oop.bomberman.utils.Global;
import java.awt.*;
@@ -14,7 +14,7 @@ public class Screen {
protected int _width, _height;
public int[] _pixels;
private int _transparentColor = 0xffff00ff;
-
+
public static int xOffset = 0, yOffset = 0;
public Screen(int width, int height) {
@@ -22,15 +22,10 @@ public Screen(int width, int height) {
_height = height;
_pixels = new int[width * height];
-
- }
-
- public void clear() {
- for (int i = 0; i < _pixels.length; i++) {
- _pixels[i] = 0;
- }
+
+ Global.screenWidth = this.getRealWidth();
+ Global.screenHeight = this.getRealHeight();
}
-
public void renderEntity(int xp, int yp, Entity entity) { //save entity pixels
xp -= xOffset;
yp -= yOffset;
@@ -63,23 +58,27 @@ public void renderEntityWithBelowSprite(int xp, int yp, Entity entity, Sprite be
}
}
}
-
+ public void clear() {
+ for (int i = 0; i < _pixels.length; i++) {
+ _pixels[i] = 0;
+ }
+ }
public static void setOffset(int xO, int yO) {
xOffset = xO;
yOffset = yO;
}
- public static int calculateXOffset(Board board, Bomber bomber) {
- if(bomber == null) return 0;
+ public static int calculateXOffset(Board board, Entity entity) {
+ if(entity == null) return 0;
int temp = xOffset;
- double BomberX = bomber.getX() / 16;
+ double x = entity.getX() / 16;
double complement = 0.5;
int firstBreakpoint = board.getWidth() / 4;
int lastBreakpoint = board.getWidth() - firstBreakpoint;
- if( BomberX > firstBreakpoint + complement && BomberX < lastBreakpoint - complement) {
- temp = (int)bomber.getX() - (Game.WIDTH / 2);
+ if( x > firstBreakpoint + complement && x < lastBreakpoint - complement) {
+ temp = (int)entity.getX() - (Game.WIDTH / 2);
}
return temp;
@@ -92,13 +91,18 @@ public void drawEndGame(Graphics g, int points) {
Font font = new Font("Arial", Font.PLAIN, 20 * Game.SCALE);
g.setFont(font);
g.setColor(Color.white);
- drawCenteredString("GAME OVER", getRealWidth(), getRealHeight(), g);
+ drawCenteredString("GAME OVER", getRealWidth(), getRealHeight()/4, g);
font = new Font("Arial", Font.PLAIN, 10 * Game.SCALE);
g.setFont(font);
g.setColor(Color.yellow);
- drawCenteredString("POINTS: " + points, getRealWidth(), getRealHeight() + (Game.TILES_SIZE * 2) * Game.SCALE, g);
- }
+ drawCenteredString("POINTS: " + points, getRealWidth(), getRealHeight()/3 + (Game.TILES_SIZE * 2) * Game.SCALE, g);
+ font = new Font("Arial", Font.PLAIN, 8 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.white);
+ drawCenteredString("Press R to retry", getRealWidth(), getRealHeight()/2 + (Game.TILES_SIZE * 4) * Game.SCALE, g);
+ drawCenteredString("Press B to Back Home", getRealWidth(), getRealHeight()/2 + (Game.TILES_SIZE * 5) * Game.SCALE, g);
+ }
public void drawChangeLevel(Graphics g, int level) {
g.setColor(Color.black);
diff --git a/src/uet/oop/bomberman/graphics/Sprite.java b/src/uet/oop/bomberman/graphics/Sprite.java
index fb1d38c..8cfdc69 100644
--- a/src/uet/oop/bomberman/graphics/Sprite.java
+++ b/src/uet/oop/bomberman/graphics/Sprite.java
@@ -4,170 +4,192 @@
* Lưu trữ thông tin các pixel của 1 sprite (hình ảnh game)
*/
public class Sprite {
-
+
public final int SIZE;
private int _x, _y;
public int[] _pixels;
protected int _realWidth;
protected int _realHeight;
private SpriteSheet _sheet;
- private SpriteSheet1 _sheet1;
+ private SpriteSheet1 _sheet1;
/*
- |--------------------------------------------------------------------------
- | Board sprites
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Board sprites
+ * |--------------------------------------------------------------------------
*/
public static Sprite grass = new Sprite(16, 8, 4, SpriteSheet1.tiles, 16, 16);
public static Sprite brick = new Sprite(16, 7, 0, SpriteSheet.tiles, 16, 16);
public static Sprite wall = new Sprite(16, 3, 13, SpriteSheet1.tiles, 16, 16);
public static Sprite portal = new Sprite(16, 8, 7, SpriteSheet1.tiles, 14, 14);
-
+
/*
- |--------------------------------------------------------------------------
- | Bomber Sprites
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Bomber Sprites
+ * |--------------------------------------------------------------------------
*/
public static Sprite player_up = new Sprite(16, 0, 0, SpriteSheet.tiles, 15, 16);
public static Sprite player_down = new Sprite(16, 2, 0, SpriteSheet.tiles, 12, 15);
public static Sprite player_left = new Sprite(16, 3, 0, SpriteSheet.tiles, 10, 15);
public static Sprite player_right = new Sprite(16, 1, 0, SpriteSheet.tiles, 10, 16);
-
+
public static Sprite player_up_1 = new Sprite(16, 0, 1, SpriteSheet.tiles, 12, 16);
public static Sprite player_up_2 = new Sprite(16, 0, 2, SpriteSheet.tiles, 12, 15);
-
+
public static Sprite player_down_1 = new Sprite(16, 2, 1, SpriteSheet.tiles, 12, 15);
public static Sprite player_down_2 = new Sprite(16, 2, 2, SpriteSheet.tiles, 12, 16);
-
+
public static Sprite player_left_1 = new Sprite(16, 3, 1, SpriteSheet.tiles, 11, 16);
- public static Sprite player_left_2 = new Sprite(16, 3, 2, SpriteSheet.tiles, 12 ,16);
-
+ public static Sprite player_left_2 = new Sprite(16, 3, 2, SpriteSheet.tiles, 12, 16);
+
public static Sprite player_right_1 = new Sprite(16, 1, 1, SpriteSheet.tiles, 11, 16);
public static Sprite player_right_2 = new Sprite(16, 1, 2, SpriteSheet.tiles, 12, 16);
-
+
public static Sprite player_dead1 = new Sprite(16, 4, 2, SpriteSheet.tiles, 14, 16);
public static Sprite player_dead2 = new Sprite(16, 5, 2, SpriteSheet.tiles, 13, 15);
public static Sprite player_dead3 = new Sprite(16, 6, 2, SpriteSheet.tiles, 16, 16);
-
+
+ // Render player 2
+ public static Sprite player2_up = new Sprite(16, 8, 9, SpriteSheet.tiles, 15, 16);
+ public static Sprite player2_down = new Sprite(16, 10, 9, SpriteSheet.tiles, 12, 15);
+ public static Sprite player2_left = new Sprite(16, 11, 9, SpriteSheet.tiles, 10, 15);
+ public static Sprite player2_right = new Sprite(16, 9, 9, SpriteSheet.tiles, 10, 16);
+
+ public static Sprite player2_up_1 = new Sprite(16, 8, 10, SpriteSheet.tiles, 12, 16);
+ public static Sprite player2_up_2 = new Sprite(16, 8, 11, SpriteSheet.tiles, 12, 15);
+
+ public static Sprite player2_down_1 = new Sprite(16, 10, 10, SpriteSheet.tiles, 12, 15);
+ public static Sprite player2_down_2 = new Sprite(16, 10, 11, SpriteSheet.tiles, 12, 16);
+
+ public static Sprite player2_left_1 = new Sprite(16, 11, 10, SpriteSheet.tiles, 11, 16);
+ public static Sprite player2_left_2 = new Sprite(16, 11, 11, SpriteSheet.tiles, 12, 16);
+
+ public static Sprite player2_right_1 = new Sprite(16, 9, 10, SpriteSheet.tiles, 11, 16);
+ public static Sprite player2_right_2 = new Sprite(16, 9, 11, SpriteSheet.tiles, 12, 16);
+
+ public static Sprite player2_dead1 = new Sprite(16, 12, 11, SpriteSheet.tiles, 14, 16);
+ public static Sprite player2_dead2 = new Sprite(16, 13, 11, SpriteSheet.tiles, 13, 15);
+ public static Sprite player2_dead3 = new Sprite(16, 14, 11, SpriteSheet.tiles, 16, 16);
+
/*
- |--------------------------------------------------------------------------
- | Character
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Character
+ * |--------------------------------------------------------------------------
*/
- //BALLOM
+ // BALLOM
public static Sprite balloom_left1 = new Sprite(16, 9, 0, SpriteSheet.tiles, 16, 16);
public static Sprite balloom_left2 = new Sprite(16, 9, 1, SpriteSheet.tiles, 16, 16);
public static Sprite balloom_left3 = new Sprite(16, 9, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite balloom_right1 = new Sprite(16, 10, 0, SpriteSheet.tiles, 16, 16);
public static Sprite balloom_right2 = new Sprite(16, 10, 1, SpriteSheet.tiles, 16, 16);
public static Sprite balloom_right3 = new Sprite(16, 10, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite balloom_dead = new Sprite(16, 9, 3, SpriteSheet.tiles, 16, 16);
-
- //ONEAL
+
+ // ONEAL
public static Sprite oneal_left1 = new Sprite(16, 11, 0, SpriteSheet.tiles, 16, 16);
public static Sprite oneal_left2 = new Sprite(16, 11, 1, SpriteSheet.tiles, 16, 16);
public static Sprite oneal_left3 = new Sprite(16, 11, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite oneal_right1 = new Sprite(16, 12, 0, SpriteSheet.tiles, 16, 16);
public static Sprite oneal_right2 = new Sprite(16, 12, 1, SpriteSheet.tiles, 16, 16);
public static Sprite oneal_right3 = new Sprite(16, 12, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite oneal_dead = new Sprite(16, 11, 3, SpriteSheet.tiles, 16, 16);
-
- //Doll
+
+ // Doll
public static Sprite doll_left1 = new Sprite(16, 13, 0, SpriteSheet.tiles, 16, 16);
public static Sprite doll_left2 = new Sprite(16, 13, 1, SpriteSheet.tiles, 16, 16);
public static Sprite doll_left3 = new Sprite(16, 13, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite doll_right1 = new Sprite(16, 14, 0, SpriteSheet.tiles, 16, 16);
public static Sprite doll_right2 = new Sprite(16, 14, 1, SpriteSheet.tiles, 16, 16);
public static Sprite doll_right3 = new Sprite(16, 14, 2, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite doll_dead = new Sprite(16, 13, 3, SpriteSheet.tiles, 16, 16);
-
- //Minvo
+
+ // Minvo
public static Sprite minvo_left1 = new Sprite(16, 8, 5, SpriteSheet.tiles, 16, 16);
public static Sprite minvo_left2 = new Sprite(16, 8, 6, SpriteSheet.tiles, 16, 16);
public static Sprite minvo_left3 = new Sprite(16, 8, 7, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite minvo_right1 = new Sprite(16, 9, 5, SpriteSheet.tiles, 16, 16);
public static Sprite minvo_right2 = new Sprite(16, 9, 6, SpriteSheet.tiles, 16, 16);
public static Sprite minvo_right3 = new Sprite(16, 9, 7, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite minvo_dead = new Sprite(16, 8, 8, SpriteSheet.tiles, 16, 16);
-
- //Kondoria
+
+ // Kondoria
public static Sprite kondoria_left1 = new Sprite(16, 10, 5, SpriteSheet.tiles, 16, 16);
public static Sprite kondoria_left2 = new Sprite(16, 10, 6, SpriteSheet.tiles, 16, 16);
public static Sprite kondoria_left3 = new Sprite(16, 10, 7, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite kondoria_right1 = new Sprite(16, 11, 5, SpriteSheet.tiles, 16, 16);
public static Sprite kondoria_right2 = new Sprite(16, 11, 6, SpriteSheet.tiles, 16, 16);
public static Sprite kondoria_right3 = new Sprite(16, 11, 7, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite kondoria_dead = new Sprite(16, 10, 8, SpriteSheet.tiles, 16, 16);
-
- //ALL
+
+ // ALL
public static Sprite mob_dead1 = new Sprite(16, 15, 0, SpriteSheet.tiles, 16, 16);
public static Sprite mob_dead2 = new Sprite(16, 15, 1, SpriteSheet.tiles, 16, 16);
public static Sprite mob_dead3 = new Sprite(16, 15, 2, SpriteSheet.tiles, 16, 16);
-
+
/*
- |--------------------------------------------------------------------------
- | Bomb Sprites
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Bomb Sprites
+ * |--------------------------------------------------------------------------
*/
public static Sprite bomb = new Sprite(16, 0, 3, SpriteSheet.tiles, 15, 15);
public static Sprite bomb_1 = new Sprite(16, 1, 3, SpriteSheet.tiles, 13, 15);
public static Sprite bomb_2 = new Sprite(16, 2, 3, SpriteSheet.tiles, 12, 14);
-
+
/*
- |--------------------------------------------------------------------------
- | FlameSegment Sprites
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | FlameSegment Sprites
+ * |--------------------------------------------------------------------------
*/
public static Sprite bomb_exploded = new Sprite(16, 0, 4, SpriteSheet.tiles, 16, 16);
public static Sprite bomb_exploded1 = new Sprite(16, 0, 5, SpriteSheet.tiles, 16, 16);
public static Sprite bomb_exploded2 = new Sprite(16, 0, 6, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_vertical = new Sprite(16, 1, 5, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical1 = new Sprite(16, 2, 5, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical2 = new Sprite(16, 3, 5, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_horizontal = new Sprite(16, 1, 7, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal1 = new Sprite(16, 1, 8, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal2 = new Sprite(16, 1, 9, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_horizontal_left_last = new Sprite(16, 0, 7, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal_left_last1 = new Sprite(16, 0, 8, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal_left_last2 = new Sprite(16, 0, 9, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_horizontal_right_last = new Sprite(16, 2, 7, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal_right_last1 = new Sprite(16, 2, 8, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_horizontal_right_last2 = new Sprite(16, 2, 9, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_vertical_top_last = new Sprite(16, 1, 4, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical_top_last1 = new Sprite(16, 2, 4, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical_top_last2 = new Sprite(16, 3, 4, SpriteSheet.tiles, 16, 16);
-
+
public static Sprite explosion_vertical_down_last = new Sprite(16, 1, 6, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical_down_last1 = new Sprite(16, 2, 6, SpriteSheet.tiles, 16, 16);
public static Sprite explosion_vertical_down_last2 = new Sprite(16, 3, 6, SpriteSheet.tiles, 16, 16);
-
+
/*
- |--------------------------------------------------------------------------
- | Brick FlameSegment
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Brick FlameSegment
+ * |--------------------------------------------------------------------------
*/
public static Sprite brick_exploded = new Sprite(16, 7, 1, SpriteSheet.tiles, 16, 16);
public static Sprite brick_exploded1 = new Sprite(16, 7, 2, SpriteSheet.tiles, 16, 16);
public static Sprite brick_exploded2 = new Sprite(16, 7, 3, SpriteSheet.tiles, 16, 16);
-
+
/*
- |--------------------------------------------------------------------------
- | Powerups
- |--------------------------------------------------------------------------
+ * |--------------------------------------------------------------------------
+ * | Powerups
+ * |--------------------------------------------------------------------------
*/
public static Sprite powerup_bombs = new Sprite(16, 0, 10, SpriteSheet.tiles, 16, 16);
public static Sprite powerup_flames = new Sprite(16, 1, 10, SpriteSheet.tiles, 16, 16);
@@ -176,7 +198,7 @@ public class Sprite {
public static Sprite powerup_detonator = new Sprite(16, 4, 10, SpriteSheet.tiles, 16, 16);
public static Sprite powerup_bombpass = new Sprite(16, 5, 10, SpriteSheet.tiles, 16, 16);
public static Sprite powerup_flamepass = new Sprite(16, 6, 10, SpriteSheet.tiles, 16, 16);
-
+
public Sprite(int size, int x, int y, SpriteSheet sheet, int rw, int rh) {
SIZE = size;
_pixels = new int[SIZE * SIZE];
@@ -187,6 +209,7 @@ public Sprite(int size, int x, int y, SpriteSheet sheet, int rw, int rh) {
_realHeight = rh;
load();
}
+
public Sprite(int size, int x, int y, SpriteSheet1 sheet1, int rw, int rh) {
SIZE = size;
_pixels = new int[SIZE * SIZE];
@@ -197,12 +220,13 @@ public Sprite(int size, int x, int y, SpriteSheet1 sheet1, int rw, int rh) {
_realHeight = rh;
load1();
}
+
public Sprite(int size, int color) {
SIZE = size;
_pixels = new int[SIZE * SIZE];
setColor(color);
}
-
+
private void setColor(int color) {
for (int i = 0; i < _pixels.length; i++) {
_pixels[i] = color;
@@ -216,6 +240,7 @@ private void load() {
}
}
}
+
private void load1() {
for (int y = 0; y < SIZE; y++) {
for (int x = 0; x < SIZE; x++) {
@@ -223,26 +248,27 @@ private void load1() {
}
}
}
+
public static Sprite movingSprite(Sprite normal, Sprite x1, Sprite x2, int animate, int time) {
int calc = animate % time;
int diff = time / 3;
-
- if(calc < diff) {
+
+ if (calc < diff) {
return normal;
}
-
- if(calc < diff * 2) {
+
+ if (calc < diff * 2) {
return x1;
}
-
+
return x2;
}
-
+
public static Sprite movingSprite(Sprite x1, Sprite x2, int animate, int time) {
int diff = time / 2;
- return (animate % time > diff) ? x1 : x2;
+ return (animate % time > diff) ? x1 : x2;
}
-
+
public int getSize() {
return SIZE;
}
diff --git a/src/uet/oop/bomberman/gui/Frame.java b/src/uet/oop/bomberman/gui/Frame.java
index 1a331e4..92d9c6a 100644
--- a/src/uet/oop/bomberman/gui/Frame.java
+++ b/src/uet/oop/bomberman/gui/Frame.java
@@ -45,5 +45,9 @@ public void setTime(int time) {
public void setPoints(int points) {
_infopanel.setPoints(points);
}
+
+ public void renderItemTime() {
+ _infopanel.renderItemTime();
+ }
}
diff --git a/src/uet/oop/bomberman/gui/GameScreen.java b/src/uet/oop/bomberman/gui/GameScreen.java
new file mode 100644
index 0000000..a473496
--- /dev/null
+++ b/src/uet/oop/bomberman/gui/GameScreen.java
@@ -0,0 +1,9 @@
+package uet.oop.bomberman.gui;
+
+import java.awt.*;
+
+public abstract class GameScreen {
+ public abstract void drawScreen(Graphics g);
+ public abstract void update();
+ public abstract void onDestroy();
+}
diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java
index de01310..543f6bd 100644
--- a/src/uet/oop/bomberman/gui/InfoPanel.java
+++ b/src/uet/oop/bomberman/gui/InfoPanel.java
@@ -1,36 +1,46 @@
package uet.oop.bomberman.gui;
import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IGameInfoManager;
+import uet.oop.bomberman.entities.tile.item.Item;
import javax.swing.*;
import java.awt.*;
+import java.util.List;
/**
* Swing Panel hiển thị thông tin thời gian, điểm mà người chơi đạt được
*/
public class InfoPanel extends JPanel {
-
private JLabel timeLabel;
private JLabel pointsLabel;
+ private JLabel itemTimeLabel;
+
+ private final Game game;
public InfoPanel(Game game) {
+ this.game = game;
setLayout(new GridLayout());
-
- timeLabel = new JLabel("Time: " + game.getBoard().getTime());
+ timeLabel = new JLabel("Time: " + game.getBoard().getGameInfoManager().getTime());
timeLabel.setForeground(Color.white);
timeLabel.setHorizontalAlignment(JLabel.CENTER);
-
- pointsLabel = new JLabel("Points: " + game.getBoard().getPoints());
+
+ pointsLabel = new JLabel("Points: " + game.getBoard().getGameInfoManager().getPoints());
pointsLabel.setForeground(Color.white);
pointsLabel.setHorizontalAlignment(JLabel.CENTER);
-
+
+ itemTimeLabel = new JLabel("");
+ itemTimeLabel.setForeground(Color.white);
+ itemTimeLabel.setHorizontalAlignment(JLabel.LEFT);
+ itemTimeLabel.setBorder(BorderFactory.createEmptyBorder(0, 40, 0, 0));
+
+ add(itemTimeLabel);
add(timeLabel);
add(pointsLabel);
-
setBackground(Color.black);
setPreferredSize(new Dimension(0, 40));
}
-
+
public void setTime(int t) {
timeLabel.setText("Time: " + t);
}
@@ -38,5 +48,18 @@ public void setTime(int t) {
public void setPoints(int t) {
pointsLabel.setText("Score: " + t);
}
-
+
+ public void renderItemTime() {
+ String label = "";
+ List
- items = game.getBoard().getGameInfoManager().getPlayerActiveItems();
+ for (int i = 0; i < items.size(); i++) {
+ Item item = items.get(i);
+ if ((item.getDuration()) == 0) {
+ continue;
+ }
+ label += item.getDisplayActiveItem() + item.getDuration() / Game.TICKS_PER_SECOND + " ";
+ }
+ itemTimeLabel.setText(label);
+ }
+
}
diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java
index bb8daad..09d8878 100644
--- a/src/uet/oop/bomberman/input/Keyboard.java
+++ b/src/uet/oop/bomberman/input/Keyboard.java
@@ -1,37 +1,113 @@
package uet.oop.bomberman.input;
+import uet.oop.bomberman.utils.EGameControl;
+
+import java.awt.RenderingHints.Key;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
+import java.util.Optional;
/**
* Tiếp nhận và xử lý các sự kiện nhập từ bàn phím
*/
public class Keyboard implements KeyListener {
-
- private boolean[] keys = new boolean[120]; //120 is enough to this game
- public boolean up, down, left, right, space;
-
+
+ private static Keyboard INST = null;
+
+ public static Keyboard i() {
+ if (INST == null) {
+ INST = new Keyboard();
+ }
+ return INST;
+ }
+
+ private Keyboard() {
+ }
+
+ public interface KeyboardInputCallback {
+ void onKeyPressed(EGameControl gameControl);
+ }
+
+ private boolean[] keys = new boolean[65536]; // 120 is enough to this game
+ public boolean up, down, left, right, space, x, pause, resume;
+ public Optional keyboardInputCallback;
+
+ public boolean player1_up, player1_down, player1_left, player1_right, player1_bomb;
+ public boolean player2_up, player2_down, player2_left, player2_right, player2_bomb;
+
public void update() {
up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W];
down = keys[KeyEvent.VK_DOWN] || keys[KeyEvent.VK_S];
left = keys[KeyEvent.VK_LEFT] || keys[KeyEvent.VK_A];
right = keys[KeyEvent.VK_RIGHT] || keys[KeyEvent.VK_D];
- space = keys[KeyEvent.VK_SPACE] || keys[KeyEvent.VK_X];
+
+ space = keys[KeyEvent.VK_SPACE];
+ x = keys[KeyEvent.VK_X];
+
+ // Player 1
+ player1_up = keys[KeyEvent.VK_W];
+ player1_down = keys[KeyEvent.VK_S];
+ player1_left = keys[KeyEvent.VK_A];
+ player1_right = keys[KeyEvent.VK_D];
+ player1_bomb = keys[KeyEvent.VK_X];
+
+ // Player 2
+ player2_up = keys[KeyEvent.VK_UP];
+ player2_down = keys[KeyEvent.VK_DOWN];
+ player2_left = keys[KeyEvent.VK_LEFT];
+ player2_right = keys[KeyEvent.VK_RIGHT];
+ player2_bomb = keys[KeyEvent.VK_SPACE];
+
+ }
+
+ private EGameControl keyToGameControl(int keyCode) {
+ if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
+ return EGameControl.UP;
+ }
+
+ if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
+ return EGameControl.DOWN;
+ }
+
+ if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
+ return EGameControl.LEFT;
+ }
+
+ if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
+ return EGameControl.RIGHT;
+ }
+
+ if (keyCode == KeyEvent.VK_SPACE) {
+ return EGameControl.SPACE;
+ }
+
+ if (keyCode == KeyEvent.VK_ENTER) {
+ return EGameControl.ENTER;
+ }
+ if (keyCode == KeyEvent.VK_X) {
+ return EGameControl.X;
+ }
+
+ return EGameControl.NONE;
}
@Override
- public void keyTyped(KeyEvent e) {}
+ public void keyTyped(KeyEvent e) {
+ }
@Override
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
-
+ if (keyboardInputCallback.isPresent()) {
+ KeyboardInputCallback callback = keyboardInputCallback.get();
+ callback.onKeyPressed(keyToGameControl(e.getKeyCode()));
+ }
}
@Override
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
-
+
}
-}
+}
\ No newline at end of file
diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java
index 3432f1e..ef21d9c 100644
--- a/src/uet/oop/bomberman/level/FileLevelLoader.java
+++ b/src/uet/oop/bomberman/level/FileLevelLoader.java
@@ -6,11 +6,22 @@
import java.util.List;
import uet.oop.bomberman.Board;
import uet.oop.bomberman.Game;
+import uet.oop.bomberman.agent.Agent;
+import uet.oop.bomberman.agent.KeyboardAgent;
+import uet.oop.bomberman.agent.KeyboardAgentPlayer1;
+import uet.oop.bomberman.agent.KeyboardAgentPlayer2;
+import uet.oop.bomberman.agent.MovingAgent;
import uet.oop.bomberman.entities.LayeredEntity;
import uet.oop.bomberman.entities.character.Bomber;
+import uet.oop.bomberman.entities.character.Bomber2;
import uet.oop.bomberman.entities.character.enemy.Balloon;
import uet.oop.bomberman.entities.character.enemy.Doll;
+import uet.oop.bomberman.entities.character.enemy.Enemy;
+import uet.oop.bomberman.entities.character.enemy.Kondoria;
+import uet.oop.bomberman.entities.character.enemy.Minvo;
import uet.oop.bomberman.entities.character.enemy.Oneal;
+import uet.oop.bomberman.entities.character.enemy.ai.AILow;
+import uet.oop.bomberman.entities.character.enemy.ai.AIMedium;
import uet.oop.bomberman.entities.tile.Grass;
import uet.oop.bomberman.entities.tile.Portal;
import uet.oop.bomberman.entities.tile.Wall;
@@ -21,6 +32,8 @@
import uet.oop.bomberman.exceptions.LoadLevelException;
import uet.oop.bomberman.graphics.Screen;
import uet.oop.bomberman.graphics.Sprite;
+import uet.oop.bomberman.utils.EGameMode;
+import uet.oop.bomberman.utils.Global;
public class FileLevelLoader extends LevelLoader {
@@ -36,41 +49,45 @@ public FileLevelLoader(Board board, int level) throws LoadLevelException {
@Override
public void loadLevel(int level) {
- // TODO: đọc dữ liệu từ tệp cấu hình /levels/Level{level}.txt
- // TODO: cập nhật các giá trị đọc được vào _width, _height, _level, _map
List list = new ArrayList<>();
try {
- FileReader fr = new FileReader("res\\levels\\Level" + level + ".txt");//doc tep luu map
+ String filePath;
+ if (Global.gameMode == EGameMode.ONE_PLAYER) {
+ filePath = "res/levels/Level1P_" + level + ".txt";
+ } else {
+ filePath = "res/levels/Level2P_" + level + ".txt";
+ }
+
+ FileReader fr = new FileReader(filePath); // Đọc tệp lưu map
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
- while (!line.equals("")) {
+ while (line != null && !line.isEmpty()) {
list.add(line);
line = br.readLine();
- //doc file txt luu vao list
}
} catch (Exception e) {
e.printStackTrace();
}
- String[] arrays = list.get(0).trim().split(" ");
- _level = Integer.parseInt(arrays[0]);
- _height = Integer.parseInt(arrays[1]);
- _width = Integer.parseInt(arrays[2]);
- _map = new char[_height][_width];
- for (int i = 0; i < _height; i++) {
- for (int j = 0; j < _width; j++) {
- _map[i][j] = list.get(i + 1).charAt(j);
+
+ if (!list.isEmpty()) {
+ String[] arrays = list.get(0).trim().split(" ");
+ _level = Integer.parseInt(arrays[0]);
+ _height = Integer.parseInt(arrays[1]);
+ _width = Integer.parseInt(arrays[2]);
+ _map = new char[_height][_width];
+ for (int i = 0; i < _height; i++) {
+ for (int j = 0; j < _width; j++) {
+ _map[i][j] = list.get(i + 1).charAt(j);
+ }
}
}
- //gan cac phan tu cho mang
}
@Override
public void createEntities() {
- // TODO: tạo các Entity của màn chơi
- // TODO: sau khi tạo xong, gọi _board.addEntity() để thêm Entity vào game
-
- // TODO: phần code mẫu ở dưới để hướng dẫn cách thêm các loại Entity vào game
- // TODO: hãy xóa nó khi hoàn thành chức năng load màn chơi từ tệp cấu hình
+ Enemy enemy;
+ Agent agent;
+ LayeredEntity layeredEntity;
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
int pos = x + y * getWidth();
@@ -78,78 +95,162 @@ public void createEntities() {
switch (c) {
// Thêm grass
case ' ':
- _board.addEntity(pos, new Grass(x, y, Sprite.grass));
+ _board.getEntityManager().getTileManager().addTile(pos, new Grass(x, y, Sprite.grass));
break;
// Thêm Wall
case '#':
- _board.addEntity(pos, new Wall(x, y, Sprite.wall));
+ _board.getEntityManager().getTileManager().addTile(pos, new Wall(x, y, Sprite.wall));
break;
// Thêm Portal
case 'x':
- _board.addEntity(pos, new LayeredEntity(x, y,
+ layeredEntity = new LayeredEntity(
+ x, y,
new Grass(x, y, Sprite.grass),
new Portal(x, y, _board, Sprite.portal),
- new Brick(x, y, Sprite.brick)));
+ new Brick(x, y, Sprite.brick));
+ _board.getEntityManager().getTileManager().addTile(pos, layeredEntity);
break;
// Thêm brick
case '*':
- _board.addEntity(x + y * _width,
- new LayeredEntity(x, y,
- new Grass(x, y, Sprite.grass),
- new Brick(x, y, Sprite.brick)
- )
- );
+ layeredEntity = new LayeredEntity(
+ x, y,
+ new Grass(x, y, Sprite.grass),
+ new Brick(x, y, Sprite.brick));
+ _board.getEntityManager().getTileManager().addTile(x + y * _width, layeredEntity);
break;
- // Thêm Bomber
+ // Thêm Bomber player
case 'p':
- _board.addCharacter(new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board));
+ Bomber bomber = new Bomber(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ Game.BOMBERSPEED,
+ Game.BOMBRATE,
+ Game.BOMBRADIUS,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(bomber);
+ _board.getEntityManager().getCharacterManager().setPlayer(bomber);
+ _board.getEntityManager().getCharacterManager().addPlayer(bomber);
Screen.setOffset(0, 0);
- _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass));
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ // if
+ if (Global.gameMode == EGameMode.TWO_PLAYER) {
+ agent = new KeyboardAgentPlayer1(bomber);
+ } else {
+ agent = new KeyboardAgent(bomber);
+ }
+ _board.addAgent(agent);
+ break;
+ // Thêm player 2:
+ case 'a':
+ Bomber bomber2 = new Bomber2(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ Game.BOMBERSPEED,
+ Game.BOMBRATE,
+ Game.BOMBRADIUS,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(bomber2);
+ _board.getEntityManager().getCharacterManager().setPlayer(bomber2);
+ _board.getEntityManager().getCharacterManager().addPlayer(bomber2);
+ Screen.setOffset(0, 0);
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ agent = new KeyboardAgentPlayer2(bomber2);
+ _board.addAgent(agent);
break;
-
// Thêm balloon
case '1':
- _board.addCharacter(new Balloon(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board));
- _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass));
+ enemy = new Balloon(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(enemy);
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ agent = new MovingAgent(enemy, new AILow());
+ _board.addAgent(agent);
break;
// Thêm oneal
case '2':
- _board.addCharacter(new Oneal(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board));
- _board.addEntity(pos, new Grass(x, y, Sprite.grass));
+ enemy = new Oneal(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(enemy);
+ _board.getEntityManager().getTileManager().addTile(pos, new Grass(x, y, Sprite.grass));
+ agent = new MovingAgent(enemy, new AILow());
+ _board.addAgent(agent);
break;
// Thêm doll
case '3':
- _board.addCharacter(new Doll(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board));
- _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass));
+ enemy = new Doll(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(enemy);
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ agent = new MovingAgent(enemy,
+ new AIMedium(enemy, _board.getEntityManager().getCharacterManager()));
+ _board.addAgent(agent);
break;
- // Thêm oneal
- // Thêm BomItem
+ // Thêm minvo
+ case '4':
+ enemy = new Minvo(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(enemy);
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ agent = new MovingAgent(enemy,
+ new AIMedium(enemy, _board.getEntityManager().getCharacterManager()));
+ _board.addAgent(agent);
+ break;
+ // Thêm kondoria
+ case '5':
+ enemy = new Kondoria(
+ Coordinates.tileToPixel(x),
+ Coordinates.tileToPixel(y) + Game.TILES_SIZE,
+ _board.getEntityManager());
+ _board.getEntityManager().getCharacterManager().addCharacter(enemy);
+ _board.getEntityManager().getTileManager().addTile(x + y * _width,
+ new Grass(x, y, Sprite.grass));
+ agent = new MovingAgent(enemy,
+ new AIMedium(enemy, _board.getEntityManager().getCharacterManager()));
+ _board.addAgent(agent);
+ break;
+ // Thêm BomItem
case 'b':
- LayeredEntity layer = new LayeredEntity(x, y,
+ layeredEntity = new LayeredEntity(
+ x, y,
new Grass(x, y, Sprite.grass),
new BombItem(x, y, Sprite.powerup_bombs),
new Brick(x, y, Sprite.brick));
- _board.addEntity(pos, layer);
+ _board.getEntityManager().getTileManager().addTile(pos, layeredEntity);
break;
// Thêm SpeedItem
case 's':
- layer = new LayeredEntity(x, y,
+ layeredEntity = new LayeredEntity(
+ x, y,
new Grass(x, y, Sprite.grass),
new SpeedItem(x, y, Sprite.powerup_speed),
new Brick(x, y, Sprite.brick));
- _board.addEntity(pos, layer);
+ _board.getEntityManager().getTileManager().addTile(pos, layeredEntity);
break;
// Thêm FlameItem
case 'f':
- layer = new LayeredEntity(x, y,
+ layeredEntity = new LayeredEntity(
+ x, y,
new Grass(x, y, Sprite.grass),
new FlameItem(x, y, Sprite.powerup_flames),
new Brick(x, y, Sprite.brick));
- _board.addEntity(pos, layer);
+ _board.getEntityManager().getTileManager().addTile(pos, layeredEntity);
break;
default:
- _board.addEntity(pos, new Grass(x, y, Sprite.grass));
+ _board.getEntityManager().getTileManager().addTile(pos, new Grass(x, y, Sprite.grass));
break;
}
diff --git a/src/uet/oop/bomberman/manager/BombManager.java b/src/uet/oop/bomberman/manager/BombManager.java
new file mode 100644
index 0000000..096b63e
--- /dev/null
+++ b/src/uet/oop/bomberman/manager/BombManager.java
@@ -0,0 +1,72 @@
+package uet.oop.bomberman.manager;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import uet.oop.bomberman.base.IBombManager;
+import uet.oop.bomberman.entities.bomb.Bomb;
+import uet.oop.bomberman.entities.bomb.FlameSegment;
+import uet.oop.bomberman.graphics.Screen;
+
+public class BombManager implements IBombManager {
+
+ private List bombs = new ArrayList<>();
+
+ public BombManager() {
+ }
+
+ @Override
+ public void addBomb(Bomb e) {
+ bombs.add(e);
+ }
+
+ @Override
+ public List getBombs() {
+ return bombs;
+ }
+
+ @Override
+ public Bomb getBombAt(double x, double y) {
+ Iterator bs = bombs.iterator();
+ Bomb b;
+ while (bs.hasNext()) {
+ b = bs.next();
+ if (b.getX() == (int) x && b.getY() == (int) y)
+ return b;
+ }
+
+ return null;
+ }
+
+ @Override
+ public FlameSegment getFlameSegmentAt(int x, int y) {
+ Iterator bs = bombs.iterator();
+ Bomb b;
+ while (bs.hasNext()) {
+ b = bs.next();
+
+ FlameSegment e = b.flameAt(x, y);
+ if (e != null) {
+ return e;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void update() {
+ bombs.forEach(Bomb::update);
+ bombs = bombs.stream()
+ .filter(bomb -> !bomb.isRemoved())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void render(Screen screen) {
+ bombs.forEach(bomb -> bomb.render(screen));
+ }
+
+}
diff --git a/src/uet/oop/bomberman/manager/CharacterManager.java b/src/uet/oop/bomberman/manager/CharacterManager.java
new file mode 100644
index 0000000..2da14b9
--- /dev/null
+++ b/src/uet/oop/bomberman/manager/CharacterManager.java
@@ -0,0 +1,125 @@
+package uet.oop.bomberman.manager;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.ICharacterManager;
+import uet.oop.bomberman.base.IGameInfoManager;
+import uet.oop.bomberman.entities.Message;
+import uet.oop.bomberman.entities.character.CanUseItem;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.tile.item.Item;
+import uet.oop.bomberman.graphics.Screen;
+import uet.oop.bomberman.sound.Sound;
+
+public class CharacterManager implements ICharacterManager {
+
+ private List characters = new ArrayList<>();
+ // list
+ private Character player;
+ private List players = new ArrayList<>();
+
+ private final IGameInfoManager gameInfoManager;
+
+ public CharacterManager(IGameInfoManager gameInfoManager) {
+ this.gameInfoManager = gameInfoManager;
+ }
+
+ @Override
+ public Character getCharacterAtExcluding(int x, int y, Character a) {
+ Iterator itr = characters.iterator();
+
+ Character cur;
+ while (itr.hasNext()) {
+ cur = itr.next();
+ if (cur == a) {
+ continue;
+ }
+
+ if (cur.getXTile() == x && cur.getYTile() == y) {
+ return cur;
+ }
+
+ }
+
+ return null;
+ }
+
+ @Override
+ public void addCharacter(Character e) {
+ characters.add(e);
+ }
+
+ @Override
+ public void setPlayer(Character character) {
+ this.player = character;
+ }
+
+ @Override
+ public Character getPlayer() {
+ return this.player;
+ }
+
+ @Override
+ public void addPlayer(Character e) {
+ players.add(e);
+ }
+
+ @Override
+ public List getPlayers() {
+ return players;
+ }
+
+ @Override
+ public void handleOnDeath(Character character, Character killer) {
+ if (character.isPlayer()) {
+ // TODO: handle player death
+ Sound.play("endgame3");
+ } else {
+ // TODO: document how to calculate message coord
+ double messageX = (character.getX() * Game.SCALE) + (character.getSprite().SIZE / 2 * Game.SCALE);
+ double messageY = (character.getY() * Game.SCALE) - (character.getSprite().SIZE / 2 * Game.SCALE);
+ int points = character.getPoints();
+ gameInfoManager.addPoints(points);
+ Message msg = new Message("+" + points, messageX, messageY, 2, Color.white, 14);
+ gameInfoManager.addMessage(msg);
+ Sound.play("AA126_11");
+ }
+ }
+
+ @Override
+ public void handleAfterDeath(Character character) {
+ if (character.isPlayer()) {
+ gameInfoManager.endGame();
+ }
+ }
+
+ @Override
+ public void update() {
+ for (Character character : characters) {
+ character.update();
+ if (character instanceof CanUseItem) {
+ CanUseItem characterCanUseItem = ((CanUseItem) character);
+ characterCanUseItem.getActiveItems().forEach(Item::update);
+ }
+ }
+ characters = characters.stream()
+ .filter(character -> !character.isRemoved())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void render(Screen screen) {
+ characters.forEach(character -> character.render(screen));
+ }
+
+ @Override
+ public List getCharacters() {
+ return characters;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/manager/EntityManager.java b/src/uet/oop/bomberman/manager/EntityManager.java
new file mode 100644
index 0000000..6809482
--- /dev/null
+++ b/src/uet/oop/bomberman/manager/EntityManager.java
@@ -0,0 +1,117 @@
+package uet.oop.bomberman.manager;
+
+import java.util.List;
+
+import uet.oop.bomberman.base.IBombManager;
+import uet.oop.bomberman.base.ICharacterManager;
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.base.IGameInfoManager;
+import uet.oop.bomberman.base.ITileManager;
+import uet.oop.bomberman.entities.Entity;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.character.enemy.Enemy;
+import uet.oop.bomberman.graphics.Screen;
+import uet.oop.bomberman.level.LevelLoader;
+
+public class EntityManager implements IEntityManager {
+
+ private ITileManager tileManager;
+ private ICharacterManager characterManager;
+ private IBombManager bombManager;
+
+ private LevelLoader levelLoader;
+
+ public EntityManager(LevelLoader levelLoader, IGameInfoManager gameInfoManager) {
+ this.levelLoader = levelLoader;
+ this.tileManager = new TileManager(levelLoader.getWidth(), levelLoader.getHeight());
+ this.characterManager = new CharacterManager(gameInfoManager);
+ this.bombManager = new BombManager();
+ }
+
+ @Override
+ public Entity getEntityAtExcluding(double x, double y, Character m) {
+
+ Entity res = null;
+
+ if (x < 0)
+ return null;
+ if (y < 0)
+ return null;
+ if (x >= levelLoader.getWidth())
+ return null;
+ if (y >= levelLoader.getHeight())
+ return null;
+
+ res = bombManager.getFlameSegmentAt((int) x, (int) y);
+ if (res != null)
+ return res;
+
+ res = bombManager.getBombAt(x, y);
+ if (res != null)
+ return res;
+
+ res = characterManager.getCharacterAtExcluding((int) x, (int) y, m);
+ if (res != null)
+ return res;
+
+ res = tileManager.getTileAt((int) x, (int) y);
+
+ return res;
+ }
+
+ @Override
+ public boolean isEnemyCleared() {
+ // viết lại thành dòng for: kiểm tra trong list character xem có ai nằm trong
+ // list players hay không
+ // Nếu có thì chưa clear -> false
+ // Nếu không còn thì clear -> true
+ // return !characterManager.getCharacters().stream()
+ // .anyMatch(character -> characterManager.getPlayers().contains(character));
+ for (Character character : characterManager.getCharacters()) {
+ if (!characterManager.getPlayers().contains(character)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void update() {
+ tileManager.update();
+ characterManager.update();
+ bombManager.update();
+ }
+
+ @Override
+ public void render(Screen screen) {
+ tileManager.render(screen);
+ characterManager.render(screen);
+ bombManager.render(screen);
+ }
+
+ @Override
+ public Character getPlayer() {
+ return characterManager.getPlayer();
+ }
+
+ @Override
+ public List getPlayers() {
+ return characterManager.getPlayers();
+ }
+
+ @Override
+ public ITileManager getTileManager() {
+ return tileManager;
+ }
+
+ @Override
+ public ICharacterManager getCharacterManager() {
+ return characterManager;
+ }
+
+ @Override
+ public IBombManager getBombManager() {
+ return bombManager;
+ }
+
+}
diff --git a/src/uet/oop/bomberman/manager/GameInfoManager.java b/src/uet/oop/bomberman/manager/GameInfoManager.java
new file mode 100644
index 0000000..e635f0a
--- /dev/null
+++ b/src/uet/oop/bomberman/manager/GameInfoManager.java
@@ -0,0 +1,136 @@
+package uet.oop.bomberman.manager;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.IEntityManager;
+import uet.oop.bomberman.base.IGameInfoManager;
+import uet.oop.bomberman.entities.Message;
+import uet.oop.bomberman.entities.character.CanUseItem;
+import uet.oop.bomberman.entities.character.Character;
+import uet.oop.bomberman.entities.tile.item.Item;
+import uet.oop.bomberman.graphics.Screen;
+import uet.oop.bomberman.utils.EScreenName;
+import uet.oop.bomberman.utils.Global;
+
+public class GameInfoManager implements IGameInfoManager {
+
+ private int time;
+ private int points;
+ private boolean paused;
+ private List messages = new ArrayList<>();
+
+ private Game game;
+ private IEntityManager entityManager;
+
+ public GameInfoManager(Game game) {
+ this.game = game;
+ this.time = Game.TIME;
+ this.points = Game.POINTS;
+ }
+
+ public void setEntityManager(IEntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ @Override
+ public List
- getPlayerActiveItems() {
+ Character player = entityManager.getPlayer();
+ if (!(player instanceof CanUseItem)) return new ArrayList<>();
+ return ((CanUseItem)player).getActiveItems().collect(Collectors.toList());
+ }
+
+ @Override
+ public void addMessage(Message e) {
+ messages.add(e);
+ }
+
+ @Override
+ public int subtractTime() {
+ if (!isPaused() && time > 0)
+ return --time;
+ else
+ return time;
+ }
+
+ @Override
+ public int getTime() {
+ return time;
+ }
+
+ @Override
+ public int getPoints() {
+ return points;
+ }
+
+ @Override
+ public void addPoints(int points) {
+ this.points += points;
+ }
+
+ @Override
+ public void update() {
+ updateMessages();
+ if (getTime() <= 0) endGame();
+ }
+
+ @Override
+ public void render(Screen screen) {}
+
+ private void updateMessages() {
+ Message m;
+ int left;
+ for (int i = 0; i < messages.size(); i++) {
+ m = messages.get(i);
+ left = m.getDuration();
+
+ if (left > 0)
+ m.setDuration(--left);
+ else
+ messages.remove(i);
+ }
+ }
+
+ public void render(Screen screen, Graphics g) {
+ renderMessages(g);
+ }
+
+ public void renderMessages(Graphics g) {
+ Message m;
+ for (int i = 0; i < messages.size(); i++) {
+ m = messages.get(i);
+
+ g.setFont(new Font("Arial", Font.PLAIN, m.getSize()));
+ g.setColor(m.getColor());
+ g.drawString(m.getMessage(), (int) m.getX() - Screen.xOffset * Game.SCALE, (int) m.getY());
+ }
+ }
+
+ @Override
+ public boolean isPaused() {
+ return paused;
+ }
+
+ @Override
+ public void pause() {
+ paused = true;
+ }
+
+ @Override
+ public void unpause() {
+ paused = false;
+ }
+
+ @Override
+ public void endGame() {
+ Global.currentScreen = EScreenName.END_GAME_SCREEN;
+ game.setScreenToShow(1);
+ game.resetScreenDelay();
+ pause();
+ }
+
+}
diff --git a/src/uet/oop/bomberman/manager/TileManager.java b/src/uet/oop/bomberman/manager/TileManager.java
new file mode 100644
index 0000000..5867774
--- /dev/null
+++ b/src/uet/oop/bomberman/manager/TileManager.java
@@ -0,0 +1,52 @@
+package uet.oop.bomberman.manager;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.base.ITileManager;
+import uet.oop.bomberman.entities.tile.Tile;
+import uet.oop.bomberman.graphics.Screen;
+
+public class TileManager implements ITileManager {
+
+ private int width;
+ @SuppressWarnings("unused") private int height;
+ private final Tile[] tiles;
+
+ public TileManager(int width, int height) {
+ this.width = width;
+ this.height = height;
+ tiles = new Tile[width * height];
+ }
+
+ @Override
+ public Tile getTileAt(double x, double y) {
+ return tiles[(int) x + (int) y * width];
+ }
+
+ @Override
+ public void addTile(int pos, Tile e) {
+ tiles[pos] = e;
+ }
+
+ @Override
+ public void update() {
+ for (Tile tile: tiles) {
+ tile.update();
+ }
+ }
+
+ @Override
+ public void render(Screen screen) {
+ // only render the visible part of screen
+ int x0 = Screen.xOffset / Game.TILES_SIZE; // tile precision, -> left X
+ int x1 = (Screen.xOffset + screen.getWidth() + Game.TILES_SIZE) / Game.TILES_SIZE; // -> right X
+ int y0 = Screen.yOffset / Game.TILES_SIZE;
+ int y1 = (Screen.yOffset + screen.getHeight()) / Game.TILES_SIZE; // render one tile plus to fix black margins
+
+ for (int y = y0; y < y1; y++) {
+ for (int x = x0; x < x1; x++) {
+ tiles[x + y * width].render(screen);
+ }
+ }
+ }
+
+}
diff --git a/src/uet/oop/bomberman/screen/DeadScreen.java b/src/uet/oop/bomberman/screen/DeadScreen.java
new file mode 100644
index 0000000..04e28cf
--- /dev/null
+++ b/src/uet/oop/bomberman/screen/DeadScreen.java
@@ -0,0 +1,194 @@
+package uet.oop.bomberman.screen;
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.gui.GameScreen;
+import uet.oop.bomberman.input.Keyboard;
+import uet.oop.bomberman.utils.EGameControl;
+import uet.oop.bomberman.utils.Global;
+import java.awt.*;
+import java.util.ArrayList;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+public class DeadScreen extends GameScreen {
+ ArrayList options = new ArrayList<>();
+ int selectorIndex = 0;
+ private Game game;
+ private BufferedImage restartIcon;
+ private BufferedImage homeIcon;
+ private BufferedImage backgroundImage;
+ private BufferedImage gameover;
+ public DeadScreen(Game game) {
+ this.game = game;
+ options.add("Restart");
+ options.add("Back Home");
+ try {
+ gameover = ImageIO.read(getClass().getResource("/menu/gameover.png"));
+ restartIcon = ImageIO.read(getClass().getResource("/menu/restart.png"));
+ homeIcon = ImageIO.read(getClass().getResource("/menu/9165683_home_house_icon.png"));
+ backgroundImage = ImageIO.read(getClass().getResource("/menu/forest_by_forheksed_d9q4k94-fullview 1.png"));
+ homeIcon = resizeImage(homeIcon, 11 * Game.SCALE, 11 * Game.SCALE);
+ restartIcon = resizeImage(restartIcon, 11 * Game.SCALE, 11 * Game.SCALE);
+ restartIcon = colorizeIcon(restartIcon, Color.black);
+ homeIcon = colorizeIcon(homeIcon, Color.black);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public void setInput() {
+ Keyboard.i().keyboardInputCallback = java.util.Optional.of(new Keyboard.KeyboardInputCallback() {
+ @Override
+ public void onKeyPressed(EGameControl gameControl) {
+ switch (gameControl) {
+ case LEFT:
+ selectorIndex--;
+ break;
+ case RIGHT:
+ selectorIndex++;
+ break;
+ case ENTER:
+ if (selectorIndex == 0) {
+ game.restartGame();
+ } else if (selectorIndex == 1) {
+ game.startNewGame();
+ }
+ break;
+ }
+
+ if (selectorIndex < 0) {
+ selectorIndex = options.size() - 1;
+ } else if (selectorIndex > options.size() - 1) {
+ selectorIndex = 0;
+ }
+ }
+ });
+ }
+ private BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
+ BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2d = resizedImage.createGraphics();
+ g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
+ g2d.dispose();
+ return resizedImage;
+ }
+ // Rest of the class remains unchanged
+ private BufferedImage colorizeIcon(BufferedImage icon, Color color) {
+ BufferedImage newIcon = new BufferedImage(icon.getWidth(), icon.getHeight(), BufferedImage.TYPE_INT_ARGB);
+ for (int x = 0; x < icon.getWidth(); x++) {
+ for (int y = 0; y < icon.getHeight(); y++) {
+ int argb = icon.getRGB(x, y);
+ if ((argb >> 24) != 0x00) { // Check if pixel is not transparent
+ newIcon.setRGB(x, y, color.getRGB());
+ } else {
+ newIcon.setRGB(x, y, argb);
+ }
+ }
+ }
+ return newIcon;
+ }
+
+ @Override
+ public void drawScreen(Graphics g) {
+
+ if (backgroundImage != null) {
+ g.drawImage(backgroundImage, 0, 0, Global.screenWidth, Global.screenHeight, null);
+ } else {
+ g.setColor(Color.BLACK);
+ g.fillRect(0, 0, Global.screenWidth, Global.screenHeight);
+ }
+ drawTitle(g);
+ drawPOINTS(g, game.getBoard().getGameInfoManager().getPoints());
+ drawTIMES(g, game.getBoard().getGameInfoManager().getTime());
+ drawOptions(g);
+ drawSelector(g);
+ g.drawImage(gameover, Global.screenWidth/3 + 40, Global.screenHeight/2 + 80, 50*Game.SCALE, 50*Game.SCALE, null);
+ }
+
+ private void drawTitle(Graphics g) {
+ String title = "GAME OVER";
+ Font font = new Font("Arial", Font.BOLD, 22 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.BLACK);
+
+ FontMetrics fm = g.getFontMetrics();
+ int x = (Global.screenWidth - fm.stringWidth(title)) / 2;
+ int marginTop = 180;
+ int y = marginTop + fm.getAscent();
+
+ g.drawString(title, x, y);
+ }
+ private void drawPOINTS(Graphics g,int points)
+ {
+ String Point = "POINTS: " + points;
+ Font font = new Font("Arial", Font.BOLD, 6 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.BLACK);
+
+ FontMetrics fm = g.getFontMetrics();
+ int textWidth = fm.stringWidth(Point);
+ int x = (Global.screenWidth - textWidth) / 2; // Vị trí x để chuỗi ở giữa màn hình
+ int marginTop = 255;
+ int y = marginTop + fm.getAscent();
+
+ g.drawString(Point, x, y);
+
+ }
+ private void drawTIMES(Graphics g,int times)
+ {
+ String Point = "TIME : " + times;
+ Font font = new Font("Arial", Font.BOLD, 6 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.BLACK);
+
+ FontMetrics fm = g.getFontMetrics();
+ int textWidth = fm.stringWidth(Point);
+ int x = (Global.screenWidth - textWidth) / 2; // Vị trí x để chuỗi ở giữa màn hình
+ int marginTop = 280;
+ int y = marginTop + fm.getAscent();
+
+ g.drawString(Point, x, y);
+
+ }
+ private void drawOptions(Graphics g) {
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ int iconHeight = restartIcon.getHeight();
+ int marginTop = (h - iconHeight + 50) / (2);
+
+ int spacing = 70;
+ int totalOptionsWidth = restartIcon.getWidth() + spacing + homeIcon.getWidth();
+
+ int startX = (w - totalOptionsWidth) / 2;
+
+ g.drawImage(restartIcon, startX, marginTop, null);
+
+ int homeIconX = startX + restartIcon.getWidth() + spacing;
+ g.drawImage(homeIcon, homeIconX, marginTop, null);
+ }
+
+ private void drawSelector(Graphics g) {
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ int iconHeight = restartIcon.getHeight();
+ int marginTop = (h - iconHeight) / 2;
+
+ int spacing = 80;
+ int totalOptionsWidth = restartIcon.getWidth() + spacing + homeIcon.getWidth();
+
+ int startX = (w - totalOptionsWidth) / 2;
+
+ int selectorX = selectorIndex == 0 ? startX - 20 : startX + restartIcon.getWidth() + spacing - 30;
+ int y = marginTop + (iconHeight / 2) + 35;
+
+ g.drawString(">", selectorX, y);
+ }
+
+
+ @Override
+ public void update() {
+ }
+ @Override
+ public void onDestroy() {
+ }
+}
diff --git a/src/uet/oop/bomberman/screen/SelectGameModeScreen.java b/src/uet/oop/bomberman/screen/SelectGameModeScreen.java
new file mode 100644
index 0000000..951dc64
--- /dev/null
+++ b/src/uet/oop/bomberman/screen/SelectGameModeScreen.java
@@ -0,0 +1,124 @@
+package uet.oop.bomberman.screen;
+
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.gui.GameScreen;
+import uet.oop.bomberman.input.Keyboard;
+import uet.oop.bomberman.utils.*;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Optional;
+
+public class SelectGameModeScreen extends GameScreen {
+ ArrayList gameModes = new ArrayList();
+ int selectorIndex = 0;
+ private Optional _input;
+
+ public SelectGameModeScreen() {
+ gameModes.add(EGameMode.ONE_PLAYER.getStringLevel());
+ gameModes.add(EGameMode.TWO_PLAYER.getStringLevel());
+ }
+
+ public void setInput(Keyboard input) {
+ _input = Optional.ofNullable(input);
+
+ _input.get().keyboardInputCallback = Optional.of(new Keyboard.KeyboardInputCallback() {
+ @Override
+ public void onKeyPressed(EGameControl gameControl) {
+ switch (gameControl) {
+ case UP:
+ selectorIndex--;
+ break;
+ case DOWN:
+ selectorIndex++;
+ break;
+ case ENTER:
+ Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN;
+ if (selectorIndex == 1) {
+ Global.gameMode = EGameMode.TWO_PLAYER;
+ } else {
+ Global.gameMode = EGameMode.ONE_PLAYER;
+ }
+ break;
+ }
+
+ if (selectorIndex < 0) {
+ selectorIndex = gameModes.size() - 1;
+ } else if (selectorIndex > gameModes.size() - 1) {
+ selectorIndex = 0;
+ }
+ }
+ });
+ }
+
+ @Override
+ public void drawScreen(Graphics g) {
+ // set background
+ g.setColor(Color.black);
+ g.fillRect(0, 0, Global.screenWidth, Global.screenHeight);
+
+ drawTitle(g);
+ drawOptions(g);
+ drawSelector(g);
+ }
+
+ private void drawTitle(Graphics g) {
+ String title = "SELECT GAME MODE";
+ Font font = new Font("Arial", Font.BOLD, 20 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.white);
+
+ FontMetrics fm = g.getFontMetrics();
+ int x = (Global.screenWidth - fm.stringWidth(title)) / 2;
+ int marginTop = 20;
+ int y = marginTop + fm.getAscent();
+
+ g.drawString(title, x, y);
+ }
+
+ private void drawOptions(Graphics g) {
+ Font font = new Font("Arial", Font.PLAIN, 10 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.white);
+
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ FontMetrics fm = g.getFontMetrics();
+ int textHeight = fm.getAscent() + fm.getDescent();
+ int boxHeight = textHeight * this.gameModes.size();
+ int marginTop = (h - boxHeight) / 2;
+
+ for (int i = 0; i < this.gameModes.size(); i++) {
+ String level = this.gameModes.get(i);
+ int x = (w - fm.stringWidth(level)) / 2;
+ int y = marginTop + fm.getAscent() + textHeight * i;
+
+ g.drawString(level, x, y);
+ }
+ }
+
+ private void drawSelector(Graphics g) {
+ String level = this.gameModes.get(selectorIndex);
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ FontMetrics fm = g.getFontMetrics();
+ int textHeight = fm.getAscent() + fm.getDescent();
+ int boxHeight = textHeight * this.gameModes.size();
+ int marginTop = (h - boxHeight) / 2;
+
+ int x = (w - fm.stringWidth(level)) / 2 - 30;
+ int y = marginTop + fm.getAscent() + textHeight * selectorIndex;
+
+ g.drawString(">", x, y);
+ }
+
+ @Override
+ public void update() {
+
+ }
+
+ @Override
+ public void onDestroy() {
+ this._input.get().keyboardInputCallback = Optional.ofNullable(null);
+ }
+}
diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java
new file mode 100644
index 0000000..84bd521
--- /dev/null
+++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java
@@ -0,0 +1,134 @@
+package uet.oop.bomberman.screen;
+
+import uet.oop.bomberman.Board;
+import uet.oop.bomberman.Game;
+import uet.oop.bomberman.gui.GameScreen;
+import uet.oop.bomberman.input.Keyboard;
+
+import uet.oop.bomberman.utils.EGameControl;
+import uet.oop.bomberman.utils.EGameLevel;
+import uet.oop.bomberman.utils.EGameMode;
+import uet.oop.bomberman.utils.EScreenName;
+import uet.oop.bomberman.utils.Global;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Optional;
+
+public class SelectLevelScreen extends GameScreen {
+ ArrayList levels = new ArrayList();
+ int selectorIndex = 0;
+ private Optional _input;
+ private Board _board;
+
+ public SelectLevelScreen(Board board) {
+ _board = board;
+
+ levels.add(EGameLevel.EASY.getStringLevel());
+ levels.add(EGameLevel.MEDIUM.getStringLevel());
+ levels.add(EGameLevel.HARD.getStringLevel());
+ }
+
+ public void setInput(Keyboard input) {
+ _input = Optional.ofNullable(input);
+
+ _input.get().keyboardInputCallback = java.util.Optional.of(new Keyboard.KeyboardInputCallback() {
+ @Override
+ public void onKeyPressed(EGameControl gameControl) {
+ switch (gameControl) {
+ case UP:
+ selectorIndex--;
+ break;
+ case DOWN:
+ selectorIndex++;
+ break;
+ case ENTER:
+ Global.gameLevel = selectorIndex + 1;
+ synchronized (_board) {
+ _board.loadLevel(Global.gameLevel);
+ }
+ Global.currentScreen = EScreenName.GAME_PLAY_SCREEN;
+ onDestroy();
+ break;
+ }
+
+ if (selectorIndex < 0) {
+ selectorIndex = levels.size() - 1;
+ } else if (selectorIndex > levels.size() - 1) {
+ selectorIndex = 0;
+ }
+ }
+ });
+ }
+
+ @Override
+ public void drawScreen(Graphics g) {
+ // set background
+ g.setColor(Color.black);
+ g.fillRect(0, 0, Global.screenWidth, Global.screenHeight);
+
+ drawTitle(g);
+ drawOptions(g);
+ drawSelector(g);
+ }
+
+ private void drawTitle(Graphics g) {
+ String title = "SELECT LEVEL";
+ Font font = new Font("Arial", Font.BOLD, 20 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.white);
+
+ FontMetrics fm = g.getFontMetrics();
+ int x = (Global.screenWidth - fm.stringWidth(title)) / 2;
+ int marginTop = 20;
+ int y = marginTop + fm.getAscent();
+
+ g.drawString(title, x, y);
+ }
+
+ private void drawOptions(Graphics g) {
+ Font font = new Font("Arial", Font.PLAIN, 10 * Game.SCALE);
+ g.setFont(font);
+ g.setColor(Color.white);
+
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ FontMetrics fm = g.getFontMetrics();
+ int textHeight = fm.getAscent() + fm.getDescent();
+ int boxHeight = textHeight * this.levels.size();
+ int marginTop = (h - boxHeight) / 2;
+
+ for (int i = 0; i < this.levels.size(); i++) {
+ String level = this.levels.get(i);
+ int x = (w - fm.stringWidth(level)) / 2;
+ int y = marginTop + fm.getAscent() + textHeight * i;
+
+ g.drawString(level, x, y);
+ }
+ }
+
+ private void drawSelector(Graphics g) {
+ String level = this.levels.get(selectorIndex);
+ int w = Global.screenWidth;
+ int h = Global.screenHeight;
+ FontMetrics fm = g.getFontMetrics();
+ int textHeight = fm.getAscent() + fm.getDescent();
+ int boxHeight = textHeight * this.levels.size();
+ int marginTop = (h - boxHeight) / 2;
+
+ int x = (w - fm.stringWidth(level)) / 2 - 30;
+ int y = marginTop + fm.getAscent() + textHeight * selectorIndex;
+
+ g.drawString(">", x, y);
+ }
+
+ @Override
+ public void update() {
+ }
+
+ @Override
+ public void onDestroy() {
+ this._input.get().keyboardInputCallback = Optional.ofNullable(null);
+ ;
+ }
+}
diff --git a/src/uet/oop/bomberman/sound/Sound.java b/src/uet/oop/bomberman/sound/Sound.java
index efafdc1..b231175 100644
--- a/src/uet/oop/bomberman/sound/Sound.java
+++ b/src/uet/oop/bomberman/sound/Sound.java
@@ -18,13 +18,14 @@ public void run() {
clip.open(inputStream);
clip.start();
} catch (Exception e) {
- System.err.println(e.getMessage());
+ System.err.println("Failed playing sound '" + sound + "': " + e.getMessage());
}
}
}).start();
-
+
}
- public static void stop(String sound){
+
+ public static void stop(String sound) {
new Thread(new Runnable() {
public void run() {
try {
@@ -34,7 +35,7 @@ public void run() {
clip.open(inputStream);
clip.stop();
} catch (Exception e) {
- System.err.println(e.getMessage());
+ System.err.println("Failed stopping sound '" + sound + "': " + e.getMessage());
}
}
}).start();
diff --git a/src/uet/oop/bomberman/utils/EGameControl.java b/src/uet/oop/bomberman/utils/EGameControl.java
new file mode 100644
index 0000000..4d1e3f8
--- /dev/null
+++ b/src/uet/oop/bomberman/utils/EGameControl.java
@@ -0,0 +1,12 @@
+package uet.oop.bomberman.utils;
+
+public enum EGameControl {
+ NONE,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+ ENTER,
+ SPACE,
+ X,
+}
diff --git a/src/uet/oop/bomberman/utils/EGameLevel.java b/src/uet/oop/bomberman/utils/EGameLevel.java
new file mode 100644
index 0000000..7644772
--- /dev/null
+++ b/src/uet/oop/bomberman/utils/EGameLevel.java
@@ -0,0 +1,17 @@
+package uet.oop.bomberman.utils;
+
+public enum EGameLevel {
+ EASY("Easy"),
+ MEDIUM("Medium"),
+ HARD("Hard");
+
+ private final String level;
+
+ EGameLevel(String level) {
+ this.level = level;
+ }
+
+ public String getStringLevel() {
+ return this.level;
+ }
+}
diff --git a/src/uet/oop/bomberman/utils/EGameMode.java b/src/uet/oop/bomberman/utils/EGameMode.java
new file mode 100644
index 0000000..d45b474
--- /dev/null
+++ b/src/uet/oop/bomberman/utils/EGameMode.java
@@ -0,0 +1,16 @@
+package uet.oop.bomberman.utils;
+
+public enum EGameMode {
+ ONE_PLAYER("1 Player"),
+ TWO_PLAYER("2 Player");
+
+ private final String mode;
+
+ EGameMode(String level) {
+ this.mode = level;
+ }
+
+ public String getStringLevel() {
+ return this.mode;
+ }
+}
diff --git a/src/uet/oop/bomberman/utils/EScreenName.java b/src/uet/oop/bomberman/utils/EScreenName.java
new file mode 100644
index 0000000..9410891
--- /dev/null
+++ b/src/uet/oop/bomberman/utils/EScreenName.java
@@ -0,0 +1,8 @@
+package uet.oop.bomberman.utils;
+
+public enum EScreenName {
+ SELECT_GAME_MODE,
+ SELECT_LEVEL_SCREEN,
+ GAME_PLAY_SCREEN,
+ END_GAME_SCREEN,
+}
diff --git a/src/uet/oop/bomberman/utils/Global.java b/src/uet/oop/bomberman/utils/Global.java
new file mode 100644
index 0000000..ff4616e
--- /dev/null
+++ b/src/uet/oop/bomberman/utils/Global.java
@@ -0,0 +1,13 @@
+package uet.oop.bomberman.utils;
+
+public class Global {
+ public static int screenWidth;
+ public static int screenHeight;
+
+ public static EScreenName currentScreen = EScreenName.SELECT_GAME_MODE;
+ public static EScreenName previousScreen = EScreenName.GAME_PLAY_SCREEN;
+
+ // GAME PLAY
+ public static int gameLevel = 1;
+ public static EGameMode gameMode;
+}