From 1d1f733279acc750eca0f4e610d392103f3291af Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Wed, 1 May 2024 07:52:23 +0000 Subject: [PATCH 01/28] add dockerfile --- Dockerfile | 10 ++++++++++ src/uet/oop/bomberman/level/FileLevelLoader.java | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Dockerfile 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/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index 3432f1e..d7ca60a 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -1,6 +1,7 @@ package uet.oop.bomberman.level; import java.io.BufferedReader; +import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.List; @@ -40,7 +41,7 @@ public void loadLevel(int level) { // 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 + FileReader fr = new FileReader("res/levels/Level" + level + ".txt");//doc tep luu map BufferedReader br = new BufferedReader(fr); String line = br.readLine(); while (!line.equals("")) { From b9fc04656619398cede73310185bfc700811dbba Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Fri, 3 May 2024 12:39:28 +0000 Subject: [PATCH 02/28] add item duration --- src/uet/oop/bomberman/Board.java | 15 ++++++++++ src/uet/oop/bomberman/Game.java | 7 +++-- .../entities/tile/item/BombItem.java | 16 +++++----- .../entities/tile/item/FlameItem.java | 16 +++++----- .../bomberman/entities/tile/item/Item.java | 30 ++++++++++++++++++- .../entities/tile/item/SpeedItem.java | 16 +++++----- 6 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 4130228..9c503b4 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -6,6 +6,7 @@ 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.entities.tile.item.Item; import uet.oop.bomberman.exceptions.LoadLevelException; import uet.oop.bomberman.graphics.IRender; import uet.oop.bomberman.graphics.Screen; @@ -31,6 +32,7 @@ public class Board implements IRender { public List _characters = new ArrayList<>(); protected List _bombs = new ArrayList<>(); private List _messages = new ArrayList<>(); + private List _activeItems = new ArrayList<>(); private int _screenToShow = -1; //1:endgame, 2:changelevel, 3:paused @@ -53,6 +55,7 @@ public void update() { updateCharacters(); updateBombs(); updateMessages(); + updateActiveItems(); detectEndGame(); for (int i = 0; i < _characters.size(); i++) { @@ -228,6 +231,10 @@ public FlameSegment getFlameSegmentAt(int x, int y) { public Entity getEntityAt(double x, double y) { return _entities[(int)x + (int)y * _levelLoader.getWidth()]; } + + public void addActiveItem(Item item) { + _activeItems.add(item); + } public void addEntity(int pos, Entity e) { _entities[pos] = e; @@ -293,6 +300,14 @@ protected void updateBombs() { itr.next().update(); } + protected void updateActiveItems() { + if( _game.isPaused() ) return; + Iterator itr = _activeItems.iterator(); + + while(itr.hasNext()) + itr.next().update(); + } + protected void updateMessages() { if( _game.isPaused() ) return; Message m; diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 53e5c53..340459b 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -30,6 +30,7 @@ public class Game extends Canvas { private static final double BOMBERSPEED = 1.0;//toc do bomber public static final int TIME = 200; + public static final int ITEM_TIME = 20; public static final int POINTS = 0; protected static int SCREENDELAY = 3; @@ -45,7 +46,7 @@ public class Game extends Canvas { private boolean _running = false; private boolean _paused = true; - private Board _board; + private static Board _board; private Screen screen; private Frame _frame; @@ -156,7 +157,7 @@ public void start() { } } } - + public static double getBomberSpeed() { return bomberSpeed; } @@ -185,7 +186,7 @@ public void resetScreenDelay() { _screenDelay = SCREENDELAY; } - public Board getBoard() { + public static Board getBoard() { return _board; } diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java index cfdceba..c0d0ff0 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -13,15 +13,13 @@ public BombItem(int x, int y, Sprite 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() { + Game.addBombRate(1); + } + + @Override + protected void handleItemInactive() { + Game.addBombRate(-1); } } diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java index e251754..78bbe57 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -13,14 +13,12 @@ public FlameItem(int x, int y, Sprite 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() { + Game.addBombRadius(1); + } + + @Override + protected void handleItemInactive() { + Game.addBombRadius(-1); } } diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index b3a1b8f..33ac804 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -1,5 +1,6 @@ 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; @@ -7,11 +8,38 @@ import uet.oop.bomberman.sound.Sound; public abstract class Item extends Tile { - protected int _duration = -1; //thoi gian cua item ,-1 la vo han + protected int _duration = 300; //5s 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) { + // TODO: xử lý Bomber ăn Item + if (e instanceof Bomber) { + Sound.play("Item"); + handleItemActive(); + _active = true; + Game.getBoard().addActiveItem(this); + remove(); + } + return false; + } + + @Override + public void update() { + if (!_active) return; + if (_duration > 0) { + _duration--; + } else { + handleItemInactive(); + _active = false; + } + } } diff --git a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java index 7bc50b7..b752c14 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -13,14 +13,12 @@ public SpeedItem(int x, int y, Sprite 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() { + Game.addBomberSpeed(0.5); + } + + @Override + protected void handleItemInactive() { + Game.addBomberSpeed(-0.5); } } From 8c9d30ed685b47edd64d772771017250c85cea8e Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Mon, 6 May 2024 13:12:43 +0700 Subject: [PATCH 03/28] select level --- src/uet/oop/bomberman/Game.java | 129 +++++++++++------- src/uet/oop/bomberman/graphics/Screen.java | 5 +- src/uet/oop/bomberman/gui/GameScreen.java | 8 ++ src/uet/oop/bomberman/input/Keyboard.java | 6 + .../bomberman/screen/SelectLevelScreen.java | 102 ++++++++++++++ src/uet/oop/bomberman/utils/EGameLevel.java | 17 +++ src/uet/oop/bomberman/utils/EScreenName.java | 6 + src/uet/oop/bomberman/utils/Global.java | 8 ++ 8 files changed, 231 insertions(+), 50 deletions(-) create mode 100644 src/uet/oop/bomberman/gui/GameScreen.java create mode 100644 src/uet/oop/bomberman/screen/SelectLevelScreen.java create mode 100644 src/uet/oop/bomberman/utils/EGameLevel.java create mode 100644 src/uet/oop/bomberman/utils/EScreenName.java create mode 100644 src/uet/oop/bomberman/utils/Global.java diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 340459b..ef78f05 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,6 +3,9 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; +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; @@ -52,6 +55,14 @@ public class Game extends Canvas { private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); private int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData(); + + // game variable + private int frames; + private int updates; + private long timer; + + // game screens + private SelectLevelScreen selectLevelScreen; public Game(Frame frame) { _frame = frame; @@ -62,16 +73,12 @@ public Game(Frame frame) { _board = new Board(this, _input, screen); addKeyListener(_input); + + initScreen(); } - private void renderGame() { - BufferStrategy bs = getBufferStrategy(); - if(bs == null) { - createBufferStrategy(3); - return; - } - + private void renderGame(Graphics g) { screen.clear(); _board.render(screen); @@ -80,46 +87,93 @@ private void renderGame() { pixels[i] = screen._pixels[i]; } - Graphics g = bs.getDrawGraphics(); - g.drawImage(image, 0, 0, getWidth(), getHeight(), null); _board.renderMessages(g); - - g.dispose(); - bs.show(); } - private void renderScreen() { + private void renderScreen(Graphics g) { + screen.clear(); + _board.drawScreen(g); + } + + private void initScreen() { + Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN; + + this.selectLevelScreen = new SelectLevelScreen(_input); + } + + private void update() { + _input.update(); + switch (Global.currentScreen) { + case GAME_PLAY_SCREEN: + _board.update(); + break; + case SELECT_LEVEL_SCREEN: + // TODO: call select level screen update + selectLevelScreen.update(); + break; + } + } + + private void showScreen() { BufferStrategy bs = getBufferStrategy(); if(bs == null) { createBufferStrategy(3); return; } - - screen.clear(); - Graphics g = bs.getDrawGraphics(); - - _board.drawScreen(g); + + switch (Global.currentScreen) { + case GAME_PLAY_SCREEN: + if(_paused) { + if(_screenDelay <= 0) { + _board.setShow(-1); + _paused = false; + } + + renderScreen(g); + } else { + renderGame(g); + } + + + 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; + } + break; + case SELECT_LEVEL_SCREEN: + // TODO: render select level screen + selectLevelScreen.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; + + initGame(); long lastTime = System.nanoTime(); - long timer = System.currentTimeMillis(); final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second double delta = 0; - int frames = 0; - int updates = 0; requestFocus(); while(_running) { long now = System.nanoTime(); @@ -130,31 +184,8 @@ public void start() { 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; - } + + showScreen(); } } diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 2494ea2..8cbc134 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -4,6 +4,7 @@ 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.*; @@ -22,7 +23,9 @@ public Screen(int width, int height) { _height = height; _pixels = new int[width * height]; - + + Global.screenWidth = this.getRealWidth(); + Global.screenHeight = this.getRealHeight(); } public void clear() { diff --git a/src/uet/oop/bomberman/gui/GameScreen.java b/src/uet/oop/bomberman/gui/GameScreen.java new file mode 100644 index 0000000..93a79c1 --- /dev/null +++ b/src/uet/oop/bomberman/gui/GameScreen.java @@ -0,0 +1,8 @@ +package uet.oop.bomberman.gui; + +import java.awt.*; + +public abstract class GameScreen { + public abstract void drawScreen(Graphics g); + public abstract void update(); +} diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index bb8daad..bdae548 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -7,9 +7,15 @@ * Tiếp nhận và xử lý các sự kiện nhập từ bàn phím */ public class Keyboard implements KeyListener { + + public interface KeyboardInputCallback { + void keyInputDelay(); + } private boolean[] keys = new boolean[120]; //120 is enough to this game public boolean up, down, left, right, space; + private boolean delayUp, delayDown; + public KeyboardInputCallback keyboardInputCallback; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java new file mode 100644 index 0000000..60ef5b7 --- /dev/null +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -0,0 +1,102 @@ +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.EGameLevel; +import uet.oop.bomberman.utils.Global; + +import java.awt.*; +import java.util.ArrayList; + +public class SelectLevelScreen extends GameScreen { + ArrayList levels = new ArrayList(); + int selectorIndex = 0; + private Keyboard _input; + + public SelectLevelScreen(Keyboard input) { + _input = input; + + levels.add(EGameLevel.EASY.getStringLevel()); + levels.add(EGameLevel.MEDIUM.getStringLevel()); + levels.add(EGameLevel.HARD.getStringLevel()); + } + + @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() { + if (_input.getSingleUp()) { + System.out.print("vao day up"); + selectorIndex++; + } else if (_input.getSingleDown()) { + selectorIndex--; + System.out.print("vao day down"); + } + + if (selectorIndex < 0) { + selectorIndex = levels.size() - 1; + } else if (selectorIndex > levels.size() - 1) { + selectorIndex = 0; + } + } +} 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/EScreenName.java b/src/uet/oop/bomberman/utils/EScreenName.java new file mode 100644 index 0000000..515a6e8 --- /dev/null +++ b/src/uet/oop/bomberman/utils/EScreenName.java @@ -0,0 +1,6 @@ +package uet.oop.bomberman.utils; + +public enum EScreenName { + SELECT_LEVEL_SCREEN, + GAME_PLAY_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..623e0a6 --- /dev/null +++ b/src/uet/oop/bomberman/utils/Global.java @@ -0,0 +1,8 @@ +package uet.oop.bomberman.utils; + +public class Global { + public static int screenWidth; + public static int screenHeight; + + public static EScreenName currentScreen; +} From 471cbc535f68b015463c384fe8c40137816362b5 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Mon, 6 May 2024 23:19:41 +0700 Subject: [PATCH 04/28] select level keyboard input --- src/uet/oop/bomberman/input/Keyboard.java | 42 +++++++++++++++++-- .../bomberman/screen/SelectLevelScreen.java | 39 ++++++++++------- src/uet/oop/bomberman/utils/EGameControl.java | 11 +++++ 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 src/uet/oop/bomberman/utils/EGameControl.java diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index bdae548..7026dc9 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -1,7 +1,10 @@ package uet.oop.bomberman.input; +import uet.oop.bomberman.utils.EGameControl; + 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 @@ -9,13 +12,12 @@ public class Keyboard implements KeyListener { public interface KeyboardInputCallback { - void keyInputDelay(); + void onKeyPressed(EGameControl gameControl); } private boolean[] keys = new boolean[120]; //120 is enough to this game public boolean up, down, left, right, space; - private boolean delayUp, delayDown; - public KeyboardInputCallback keyboardInputCallback; + public Optional keyboardInputCallback; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -25,13 +27,45 @@ public void update() { space = keys[KeyEvent.VK_SPACE] || keys[KeyEvent.VK_X]; } + 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 || keyCode == KeyEvent.VK_X) { + return EGameControl.SPACE; + } + + if (keyCode == KeyEvent.VK_ENTER) { + return EGameControl.ENTER; + } + + return EGameControl.NONE; + } + @Override 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 diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java index 60ef5b7..34d51bc 100644 --- a/src/uet/oop/bomberman/screen/SelectLevelScreen.java +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -3,10 +3,13 @@ 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.EScreenName; import uet.oop.bomberman.utils.Global; import java.awt.*; +import java.awt.event.KeyEvent; import java.util.ArrayList; public class SelectLevelScreen extends GameScreen { @@ -20,6 +23,26 @@ public SelectLevelScreen(Keyboard input) { levels.add(EGameLevel.EASY.getStringLevel()); levels.add(EGameLevel.MEDIUM.getStringLevel()); levels.add(EGameLevel.HARD.getStringLevel()); + + _input.keyboardInputCallback = java.util.Optional.of(new Keyboard.KeyboardInputCallback() { + @Override + public void onKeyPressed(EGameControl gameControl) { + switch (gameControl) { + case UP: + selectorIndex--; + case DOWN: + selectorIndex++; + case ENTER: + Global.currentScreen = EScreenName.GAME_PLAY_SCREEN; + } + + if (selectorIndex < 0) { + selectorIndex = levels.size() - 1; + } else if (selectorIndex > levels.size() - 1) { + selectorIndex = 0; + } + } + }); } @Override @@ -84,19 +107,5 @@ private void drawSelector(Graphics g) { } @Override - public void update() { - if (_input.getSingleUp()) { - System.out.print("vao day up"); - selectorIndex++; - } else if (_input.getSingleDown()) { - selectorIndex--; - System.out.print("vao day down"); - } - - if (selectorIndex < 0) { - selectorIndex = levels.size() - 1; - } else if (selectorIndex > levels.size() - 1) { - selectorIndex = 0; - } - } + public void update() {} } diff --git a/src/uet/oop/bomberman/utils/EGameControl.java b/src/uet/oop/bomberman/utils/EGameControl.java new file mode 100644 index 0000000..fa8cea4 --- /dev/null +++ b/src/uet/oop/bomberman/utils/EGameControl.java @@ -0,0 +1,11 @@ +package uet.oop.bomberman.utils; + +public enum EGameControl { + NONE, + UP, + DOWN, + LEFT, + RIGHT, + ENTER, + SPACE, +} From 42623970ee4a500b1c9dd7bddf861f09513ae468 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Tue, 7 May 2024 17:50:37 +0700 Subject: [PATCH 05/28] update keyboard input --- src/uet/oop/bomberman/screen/SelectLevelScreen.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java index 34d51bc..33fb2a1 100644 --- a/src/uet/oop/bomberman/screen/SelectLevelScreen.java +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -30,10 +30,13 @@ public void onKeyPressed(EGameControl gameControl) { switch (gameControl) { case UP: selectorIndex--; + break; case DOWN: selectorIndex++; + break; case ENTER: Global.currentScreen = EScreenName.GAME_PLAY_SCREEN; + break; } if (selectorIndex < 0) { From 8ad3da91f7db85eedb4dbf18d54c8561e5b0f6f8 Mon Sep 17 00:00:00 2001 From: 21522098_HuyHoang <21522098@gm.uit.edu.vn> Date: Fri, 10 May 2024 10:47:02 +0700 Subject: [PATCH 06/28] Pause_game w P,and Button on Screen --- src/uet/oop/bomberman/Game.java | 28 ++++++++++++------- src/uet/oop/bomberman/graphics/Screen.java | 7 ----- src/uet/oop/bomberman/gui/InfoPanel.java | 31 +++++++++++++++++++--- src/uet/oop/bomberman/input/Keyboard.java | 3 ++- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 53e5c53..74bc69f 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -108,11 +108,16 @@ private void renderScreen() { private void update() { _input.update(); _board.update(); + if (_input.pause) { // Kiểm tra nếu phím "p" được nhấn + _board.setShow(3); // Hiển thị màn hình tạm dừng + _paused = true; // Đặt trạng thái game là tạm dừng + return; + } } public void start() { _running = true; - + _paused = false; long lastTime = System.nanoTime(); long timer = System.currentTimeMillis(); final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second @@ -129,17 +134,20 @@ public void start() { updates++; delta--; } - - if(_paused) { - if(_screenDelay <= 0) { - _board.setShow(-1); - _paused = false; - } - - renderScreen(); + if (_input.pause) { + _paused = !_paused; + if (_paused) { + _board.setShow(3); } else { - renderGame(); + _board.setShow(-1); } + } + + if(_paused) { + renderScreen(); + } else { + renderGame(); + } frames++; diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 2494ea2..fa3b2e9 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -24,13 +24,6 @@ public Screen(int width, int height) { _pixels = new int[width * height]; } - - public void clear() { - for (int i = 0; i < _pixels.length; i++) { - _pixels[i] = 0; - } - } - public void renderEntity(int xp, int yp, Entity entity) { //save entity pixels xp -= xOffset; yp -= yOffset; diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index de01310..4ef0cfd 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -1,8 +1,13 @@ package uet.oop.bomberman.gui; - +import java.awt.event.ActionListener; +import uet.oop.bomberman.Board; import uet.oop.bomberman.Game; import javax.swing.*; + + +import javafx.event.ActionEvent; + import java.awt.*; /** @@ -10,11 +15,13 @@ */ public class InfoPanel extends JPanel { + private static Board _board; + private boolean gamePaused = false; private JLabel timeLabel; private JLabel pointsLabel; - + private JButton pauseButton; public InfoPanel(Game game) { - setLayout(new GridLayout()); + setLayout(new GridLayout(1, 3)); timeLabel = new JLabel("Time: " + game.getBoard().getTime()); timeLabel.setForeground(Color.white); @@ -24,9 +31,25 @@ public InfoPanel(Game game) { pointsLabel.setForeground(Color.white); pointsLabel.setHorizontalAlignment(JLabel.CENTER); + pauseButton = new JButton("Pause"); + pauseButton.setForeground(Color.white); + pauseButton.setHorizontalAlignment(JButton.CENTER); + pauseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // Nếu trò chơi đang tạm dừng, tiếp tục trò chơi và thay đổi trạng thái + if (gamePaused) { + _board.setShow(3); // Tiếp tục trò chơi + gamePaused = false; // Thay đổi trạng thái + } else { // Nếu trò chơi đang chạy, tạm dừng trò chơi và thay đổi trạng thái + _board.setShow(-1); // Tạm dừng trò chơi + gamePaused = true; // Thay đổi trạng thái + } + } + }); add(timeLabel); add(pointsLabel); - + add(pauseButton); setBackground(Color.black); setPreferredSize(new Dimension(0, 40)); } diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index bb8daad..44fdf07 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -9,7 +9,7 @@ public class Keyboard implements KeyListener { private boolean[] keys = new boolean[120]; //120 is enough to this game - public boolean up, down, left, right, space; + public boolean up, down, left, right, space,pause; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -17,6 +17,7 @@ public void update() { 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]; + pause = keys[KeyEvent.VK_P]; } @Override From e4d259dd414b42284eec518d36b1b1793a1c4777 Mon Sep 17 00:00:00 2001 From: 21522098 <21522098@gm.uit.edu.vn> Date: Sat, 11 May 2024 13:25:09 +0700 Subject: [PATCH 07/28] Pause-game --- src/uet/oop/bomberman/graphics/Screen.java | 6 +++++- src/uet/oop/bomberman/gui/InfoPanel.java | 15 +-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index fa3b2e9..9aa0058 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -56,7 +56,11 @@ 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; diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index 4ef0cfd..366a835 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -6,7 +6,7 @@ import javax.swing.*; -import javafx.event.ActionEvent; +import javafx.event.*; import java.awt.*; @@ -34,19 +34,6 @@ public InfoPanel(Game game) { pauseButton = new JButton("Pause"); pauseButton.setForeground(Color.white); pauseButton.setHorizontalAlignment(JButton.CENTER); - pauseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // Nếu trò chơi đang tạm dừng, tiếp tục trò chơi và thay đổi trạng thái - if (gamePaused) { - _board.setShow(3); // Tiếp tục trò chơi - gamePaused = false; // Thay đổi trạng thái - } else { // Nếu trò chơi đang chạy, tạm dừng trò chơi và thay đổi trạng thái - _board.setShow(-1); // Tạm dừng trò chơi - gamePaused = true; // Thay đổi trạng thái - } - } - }); add(timeLabel); add(pointsLabel); add(pauseButton); From 091ad4e7b62f56ead21855d3406f55bd2404152b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=C6=B0=C6=A1ng=20Minh?= <113281373+phuonnngminh@users.noreply.github.com> Date: Sat, 11 May 2024 13:56:34 +0700 Subject: [PATCH 08/28] display item time --- src/uet/oop/bomberman/Board.java | 237 ++++++++++-------- src/uet/oop/bomberman/Game.java | 125 ++++----- .../entities/tile/item/BombItem.java | 5 + .../entities/tile/item/FlameItem.java | 5 + .../bomberman/entities/tile/item/Item.java | 30 ++- .../entities/tile/item/SpeedItem.java | 5 + src/uet/oop/bomberman/gui/Frame.java | 4 + src/uet/oop/bomberman/gui/InfoPanel.java | 38 ++- 8 files changed, 263 insertions(+), 186 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 9c503b4..0bf31f2 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -27,71 +27,78 @@ public class Board implements IRender { 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 List _activeItems = new ArrayList<>(); - - private int _screenToShow = -1; //1:endgame, 2:changelevel, 3:paused - + + public List getActiveItems() { + return _activeItems; + } + + 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) { _game = game; _input = input; _screen = screen; - - loadLevel(1); //start in level 1 + + loadLevel(1); // start in level 1 } - + @Override public void update() { - if( _game.isPaused() ) return; - + if (_game.isPaused()) + return; + updateEntities(); updateCharacters(); updateBombs(); updateMessages(); updateActiveItems(); detectEndGame(); - + for (int i = 0; i < _characters.size(); i++) { Character a = _characters.get(i); - if(a.isRemoved()) _characters.remove(i); + if (a.isRemoved()) + _characters.remove(i); } } @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 + 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 - + 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); - + } - + public void nextLevel() { - Game.setBombRadius(1); - Game.setBombRate(1); - Game.setBomberSpeed(1.0); + Game.setBombRadius(1); + Game.setBombRate(1); + Game.setBomberSpeed(1.0); loadLevel(_levelLoader.getLevel() + 1); } - + public void loadLevel(int level) { _time = Game.TIME; _screenToShow = 2; @@ -100,38 +107,38 @@ public void loadLevel(int level) { _characters.clear(); _bombs.clear(); _messages.clear(); - + try { _levelLoader = new FileLevelLoader(this, level); _entities = new Entity[_levelLoader.getHeight() * _levelLoader.getWidth()]; - + _levelLoader.createEntities(); } catch (LoadLevelException e) { endGame(); } } - + protected void detectEndGame() { - if(_time <= 0) + 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) + if (_characters.get(i) instanceof Bomber == false) ++total; } - + return total == 0; } - + public void drawScreen(Graphics g) { switch (_screenToShow) { case 1: @@ -145,178 +152,186 @@ public void drawScreen(Graphics 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 = 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); - + 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()) { + while (bs.hasNext()) { b = bs.next(); - if(b.getX() == (int)x && b.getY() == (int)y) + 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()) { + while (itr.hasNext()) { cur = itr.next(); - - if(cur instanceof Bomber) + + 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()) { + while (itr.hasNext()) { cur = itr.next(); - if(cur == a) { + if (cur == a) { continue; } - - if(cur.getXTile() == x && cur.getYTile() == y) { + + 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()) { + while (bs.hasNext()) { b = bs.next(); - + FlameSegment e = b.flameAt(x, y); - if(e != null) { + if (e != null) { return e; } } - + return null; } - + public Entity getEntityAt(double x, double y) { - return _entities[(int)x + (int)y * _levelLoader.getWidth()]; + return _entities[(int) x + (int) y * _levelLoader.getWidth()]; } public void addActiveItem(Item item) { _activeItems.add(item); } - + 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()) + + while (itr.hasNext()) itr.next().render(screen); } - + protected void renderBombs(Screen screen) { Iterator itr = _bombs.iterator(); - - while(itr.hasNext()) + + 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()); + g.drawString(m.getMessage(), (int) m.getX() - Screen.xOffset * Game.SCALE, (int) m.getY()); } } - + protected void updateEntities() { - if( _game.isPaused() ) return; + if (_game.isPaused()) + return; for (int i = 0; i < _entities.length; i++) { _entities[i].update(); } } - + protected void updateCharacters() { - if( _game.isPaused() ) return; + if (_game.isPaused()) + return; Iterator itr = _characters.iterator(); - - while(itr.hasNext() && !_game.isPaused()) + + while (itr.hasNext() && !_game.isPaused()) itr.next().update(); } - + protected void updateBombs() { - if( _game.isPaused() ) return; + if (_game.isPaused()) + return; Iterator itr = _bombs.iterator(); - - while(itr.hasNext()) + + while (itr.hasNext()) itr.next().update(); } - + protected void updateActiveItems() { - if( _game.isPaused() ) return; + if (_game.isPaused()) + return; Iterator itr = _activeItems.iterator(); - - while(itr.hasNext()) + + while (itr.hasNext()) itr.next().update(); } - + protected void updateMessages() { - if( _game.isPaused() ) return; + 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) + + if (left > 0) m.setDuration(--left); else _messages.remove(i); @@ -324,10 +339,18 @@ protected void updateMessages() { } public int subtractTime() { - if(_game.isPaused()) - return this._time; + if (!_game.isPaused() && _time > 0) + return --_time; else - return this._time--; + return _time; + } + + public int getItemTime() { + int totalTime = 0; + for (int i = 0; i < _activeItems.size(); i++) { + totalTime += _activeItems.get(i).getDuration() / 60; + } + return totalTime; } public Keyboard getInput() { @@ -361,7 +384,7 @@ public int getPoints() { public void addPoints(int points) { this._points += points; } - + public int getWidth() { return _levelLoader.getWidth(); } @@ -369,5 +392,5 @@ public int getWidth() { public int getHeight() { return _levelLoader.getHeight(); } - + } diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 340459b..f043707 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -15,91 +15,88 @@ */ 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 - + private static final double BOMBERSPEED = 1.0;// toc do bomber + private static int itemTime; + public static final int TIME = 200; public static final int ITEM_TIME = 20; 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 static 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(); + 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); } - - + private void renderGame() { BufferStrategy bs = getBufferStrategy(); - if(bs == null) { + if (bs == null) { createBufferStrategy(3); return; } - + 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(); } - + private void renderScreen() { BufferStrategy bs = getBufferStrategy(); - if(bs == null) { + if (bs == null) { createBufferStrategy(3); return; } - + screen.clear(); - + Graphics g = bs.getDrawGraphics(); - + _board.drawScreen(g); g.dispose(); @@ -110,74 +107,78 @@ private void update() { _input.update(); _board.update(); } - + public void start() { _running = true; - - long lastTime = System.nanoTime(); + + long lastTime = System.nanoTime(); long timer = System.currentTimeMillis(); - final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second + 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) { + while (delta >= 1) { update(); updates++; delta--; } - - if(_paused) { - if(_screenDelay <= 0) { + + if (_paused) { + if (_screenDelay <= 0) { _board.setShow(-1); _paused = false; } - + renderScreen(); } else { renderGame(); } - - + frames++; - if(System.currentTimeMillis() - timer > 1000) { + if (System.currentTimeMillis() - timer > 1000) { _frame.setTime(_board.subtractTime()); _frame.setPoints(_board.getPoints()); + _frame.setItemTime(_board.getItemTime()); timer += 1000; _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps"); updates = 0; frames = 0; - - if(_board.getShow() == 2) + + if (_board.getShow() == 2) --_screenDelay; } } } + public static int getItemTime() { + return itemTime; + } + 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; } @@ -193,19 +194,21 @@ public static Board getBoard() { public boolean isPaused() { return _paused; } - + public void pause() { _paused = true; } + public static void setBombRate(int bombRate) { - Game.bombRate = bombRate; - } + Game.bombRate = bombRate; + } - public static void setBombRadius(int bombRadius) { - Game.bombRadius = bombRadius; - } + public static void setBombRadius(int bombRadius) { + Game.bombRadius = bombRadius; + } + + public static void setBomberSpeed(double bomberSpeed) { + Game.bomberSpeed = bomberSpeed; + } - public static void setBomberSpeed(double bomberSpeed) { - Game.bomberSpeed = bomberSpeed; - } } diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java index c0d0ff0..cf9b5fc 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -22,4 +22,9 @@ protected void handleItemInactive() { Game.addBombRate(-1); } + @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 78bbe57..6507dcf 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -21,4 +21,9 @@ protected void handleItemActive() { protected void handleItemInactive() { Game.addBombRadius(-1); } + + @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 33ac804..b67655a 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -8,32 +8,35 @@ import uet.oop.bomberman.sound.Sound; public abstract class Item extends Tile { - protected int _duration = 300; //5s + protected int _duration = 300; // 5s 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) { // TODO: xử lý Bomber ăn Item - if (e instanceof Bomber) { - Sound.play("Item"); - handleItemActive(); - _active = true; - Game.getBoard().addActiveItem(this); - remove(); - } - return false; + if (e instanceof Bomber) { + Sound.play("Item"); + handleItemActive(); + _active = true; + Game.getBoard().addActiveItem(this); + remove(); + } + return false; } @Override public void update() { - if (!_active) return; + if (!_active) + return; if (_duration > 0) { _duration--; } else { @@ -41,5 +44,10 @@ public void update() { _active = false; } } - + + public int getDuration() { + return _duration; + } + + public abstract String getDisplayActiveItem(); } diff --git a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java index b752c14..e8ebfd8 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -21,4 +21,9 @@ protected void handleItemActive() { protected void handleItemInactive() { Game.addBomberSpeed(-0.5); } + + @Override + public String getDisplayActiveItem() { + return "Speed:"; + } } diff --git a/src/uet/oop/bomberman/gui/Frame.java b/src/uet/oop/bomberman/gui/Frame.java index 1a331e4..0ccb41c 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 setItemTime(int itemTime) { + _infopanel.setItemTime(itemTime); + } } diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index de01310..166630b 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -1,36 +1,47 @@ package uet.oop.bomberman.gui; import uet.oop.bomberman.Game; +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 final Game game; private JLabel timeLabel; private JLabel pointsLabel; + private JLabel itemTimeLabel; public InfoPanel(Game game) { + this.game = game; setLayout(new GridLayout()); - + timeLabel = new JLabel("Time: " + game.getBoard().getTime()); timeLabel.setForeground(Color.white); timeLabel.setHorizontalAlignment(JLabel.CENTER); - + pointsLabel = new JLabel("Points: " + game.getBoard().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 +49,18 @@ public void setTime(int t) { public void setPoints(int t) { pointsLabel.setText("Score: " + t); } - + + public void setItemTime(int t) { + String label = ""; + List items = game.getBoard().getActiveItems(); + for (int i = 0; i < items.size(); i++) { + Item item = items.get(i); + if ((item.getDuration()) == 0) { + continue; + } + label += item.getDisplayActiveItem() + item.getDuration() / 60 + " "; + } + itemTimeLabel.setText(label); + } + } From fb64fc0efc767a1a00c55d44d412996acfff8e44 Mon Sep 17 00:00:00 2001 From: 21522098_HuyHoang <21522098@gm.uit.edu.vn> Date: Sun, 12 May 2024 07:55:17 +0700 Subject: [PATCH 09/28] Pause_Button_Fixed --- src/uet/oop/bomberman/Game.java | 32 ++++++++++++++++-------- src/uet/oop/bomberman/gui/InfoPanel.java | 22 ++++++++++------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 74bc69f..c44c977 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,12 +3,14 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; - +import uet.oop.bomberman.gui.InfoPanel; import java.awt.*; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; +import javafx.event.ActionEvent; + /** * 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, * Gọi phương thức render(), update() cho tất cả các entity @@ -44,6 +46,7 @@ public class Game extends Canvas { private Keyboard _input; private boolean _running = false; private boolean _paused = true; + private boolean _paused1 = true; private Board _board; private Screen screen; @@ -114,10 +117,8 @@ private void update() { return; } } - public void start() { _running = true; - _paused = false; long lastTime = System.nanoTime(); long timer = System.currentTimeMillis(); final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second @@ -134,19 +135,27 @@ public void start() { updates++; delta--; } - if (_input.pause) { - _paused = !_paused; if (_paused) { + if (_screenDelay <= 0) { + _board.setShow(-1); + _paused = false; + } + renderScreen(); + } else { + renderGame(); + } + if (_paused1) { _board.setShow(3); } else { _board.setShow(-1); } - } - if(_paused) { - renderScreen(); - } else { - renderGame(); + if (_input.pause) { + _paused1 = !_paused1; + if (_paused) { + _board.setShow(3); + } else { + } } @@ -202,7 +211,7 @@ public boolean isPaused() { } public void pause() { - _paused = true; + _paused = !_paused; } public static void setBombRate(int bombRate) { Game.bombRate = bombRate; @@ -215,4 +224,5 @@ public static void setBombRadius(int bombRadius) { public static void setBomberSpeed(double bomberSpeed) { Game.bomberSpeed = bomberSpeed; } + } diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index 366a835..2341c67 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -1,28 +1,24 @@ package uet.oop.bomberman.gui; -import java.awt.event.ActionListener; import uet.oop.bomberman.Board; import uet.oop.bomberman.Game; import javax.swing.*; - - -import javafx.event.*; - import java.awt.*; +import java.awt.event.*; /** * 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 static Board _board; private boolean gamePaused = false; private JLabel timeLabel; private JLabel pointsLabel; private JButton pauseButton; + private Game game; public InfoPanel(Game game) { setLayout(new GridLayout(1, 3)); - + this.game = game; timeLabel = new JLabel("Time: " + game.getBoard().getTime()); timeLabel.setForeground(Color.white); timeLabel.setHorizontalAlignment(JLabel.CENTER); @@ -32,8 +28,18 @@ public InfoPanel(Game game) { pointsLabel.setHorizontalAlignment(JLabel.CENTER); pauseButton = new JButton("Pause"); - pauseButton.setForeground(Color.white); + pauseButton.setForeground(Color.WHITE); pauseButton.setHorizontalAlignment(JButton.CENTER); + pauseButton.setBackground(Color.BLACK); + pauseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + game.pause(); + gamePaused = !gamePaused; + pauseButton.setText(gamePaused? "Resume" : "Pause"); + } + }); + add(timeLabel); add(pointsLabel); add(pauseButton); From 5ca0502702a40977878eb888f4d7db9d7d9f7ebc Mon Sep 17 00:00:00 2001 From: Huy010302 <111289985+Huy010302@users.noreply.github.com> Date: Sun, 12 May 2024 13:32:40 +0700 Subject: [PATCH 10/28] add level, create enemy --- res/levels/Level3.txt | 14 ++ .../entities/character/enemy/Kondoria.java | 40 +++++ .../entities/character/enemy/Minvo.java | 138 ++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 res/levels/Level3.txt create mode 100644 src/uet/oop/bomberman/entities/character/enemy/Kondoria.java create mode 100644 src/uet/oop/bomberman/entities/character/enemy/Minvo.java diff --git a/res/levels/Level3.txt b/res/levels/Level3.txt new file mode 100644 index 0000000..40a9bf4 --- /dev/null +++ b/res/levels/Level3.txt @@ -0,0 +1,14 @@ +3 13 31 +############################### +#p * *3 * ** * * *# +# # # # #*# # #*# # # # # #*# # +# * * *** ** # * ** # +# #*# # # # #4# #b#1# # # # #*# +# * ** * **# +# # #*# # # # # #*#*#*#*# # # # +# * * * *x* * 4 # +# # # # #*# # # # # # #*# #*# # +# **** *2 # +# # # # # # # # # #*# # # # #*# +# ** ** * 5 # +############################### \ No newline at end of file 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..95fe5d4 --- /dev/null +++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java @@ -0,0 +1,40 @@ +package uet.oop.bomberman.entities.character.enemy; + +import uet.oop.bomberman.Game; +import uet.oop.bomberman.Board; +import uet.oop.bomberman.entities.character.enemy.ai.AIMedium; +import uet.oop.bomberman.graphics.Sprite; + +public class Kondoria extends Enemy { + public Kondoria(int x, int y, Board board) { + super(x, y, board, Sprite.balloom_dead, Game.getBomberSpeed() / 4, 1000); + + _sprite = Sprite.kondoria_right1; + + _ai = new AIMedium(_board.getBomber(), this); + _direction = _ai.calculateDirection(); + // this._speed += random.nextDouble()/2; + } + + @Override + protected void chooseSprite() { + switch (_direction) { + case 0: + case 1: + if (_moving) + _sprite = Sprite.movingSprite(Sprite.kondoria_right1, Sprite.kondoria_right2, + Sprite.kondoria_right3, _animate, 60); + else + _sprite = Sprite.kondoria_left1; + break; + case 2: + case 3: + if (_moving) + _sprite = Sprite.movingSprite(Sprite.kondoria_left1, Sprite.kondoria_left2, Sprite.kondoria_left3, + _animate, 60); + 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..e4ad4d7 --- /dev/null +++ b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java @@ -0,0 +1,138 @@ +package uet.oop.bomberman.entities.character.enemy; + +import uet.oop.bomberman.Board; +import uet.oop.bomberman.Game; +import uet.oop.bomberman.entities.character.enemy.ai.AIMedium; +import uet.oop.bomberman.graphics.Sprite; + +public class Minvo extends Enemy { + private Board _board; + + public Minvo(int x, int y, Board board) { + super(x, y, board, Sprite.minvo_dead, Game.getBomberSpeed() * 1.5, 800); + _board = board; + _sprite = Sprite.minvo_right1; + + _ai = new AIMedium(_board.getBomber(), this); + _direction = _ai.calculateDirection(); + } + + @Override + protected void chooseSprite() { + switch (_direction) { + case 0: + case 1: + if (_moving) + _sprite = Sprite.movingSprite(Sprite.minvo_right1, Sprite.minvo_right2, Sprite.minvo_right3, + _animate, 60); + else + _sprite = Sprite.minvo_left1; + break; + case 2: + case 3: + if (_moving) + _sprite = Sprite.movingSprite(Sprite.minvo_left1, Sprite.minvo_left2, Sprite.minvo_left3, _animate, + 60); + else + _sprite = Sprite.minvo_left1; + break; + } + } + + // // Thêm hành vi cho Minvo + + // @Override + // public void update() { + // super.update(); + // Bomber bomber = _board.getBomber(); + // if (bomber != null) { + // int bomberX = bomber.getXTile(); + // int bomberY = bomber.getYTile(); + // int minvoX = this.getXTile(); + // int minvoY = this.getYTile(); + + // double distance = Math.sqrt(Math.pow(bomberX - minvoX, 2) + Math.pow(bomberY + // - minvoY, 2)); + + // // Kiểm tra xem khoảng cách giữa Minvo và Bomber có dưới một ngưỡng nhất định + // // hay không + // if (distance <= 3) { + // moveTowardBomber(); + // placeBomb(); + // } else { + // _direction = _ai.calculateDirection(); + // // move(); + // } + // } + // } + + // private void moveTowardBomber() { + // Bomber bomber = _board.getBomber(); + // if (bomber != null) { + // int bomberX = bomber.getXTile(); + // int bomberY = bomber.getYTile(); + // int minvoX = this.getXTile(); + // int minvoY = this.getYTile(); + + // // hướng vector từ minvo đến bomber + // int dx = bomberX - minvoX; + // int dy = bomberY - minvoY; + + // // Chọn hướng đi gần nhất + // if (Math.abs(dx) > Math.abs(dy)) { + // if (dx > 0) { + // _direction = 1; // Di chuyển sang phải + // } else { + // _direction = 3; // Di chuyển sang trái + // } + // } else { + // if (dy > 0) { + // _direction = 2; // Di chuyển xuống dưới + // } else { + // _direction = 0; // Di chuyển lên trên + // } + + // } + // } + // // // di chuyển mivo + // // move(); + + // } + + // private void placeBomb() { + // if (_board.detectNoEnemies()) { + // return; + // } + // int bombRate = _board.getBombRate(); + // if (Math.random() < bombRate) { // Kiểm tra xác suất đặt bom + // int xt = Coordinates.pixelToTile(_x + Game.TILES_SIZE / 2); + // int yt = Coordinates.pixelToTile((_y + Game.TILES_SIZE / 2)); + // _board.addBomb(new Bomb(xt, yt, _board)); + // } + // } + + // private void move() { + // double xa = _x, ya = _y; + + // switch (_direction) { + // case 0: + // ya -= _speed; + // break; + // case 1: + // xa += _speed; + // break; + // case 2: + // ya += _speed; + // break; + // case 3: + // xa -= _speed; + // break; + // } + + // // Kiểm tra va chạm với tường và cập nhật tọa độ đích đến nếu cần + // if (!_board.detectWallCollision(xa, ya, _collisionRadius)) { + // _x = xa; + // _y = ya; + // } + // } +} From e6441d4f5bd241cabfdb99140bb9aae842edccf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=C6=B0=C6=A1ng=20Minh?= <113281373+phuonnngminh@users.noreply.github.com> Date: Sun, 12 May 2024 22:09:48 +0700 Subject: [PATCH 11/28] Revert "Select level" --- src/uet/oop/bomberman/Game.java | 132 +++++++----------- src/uet/oop/bomberman/graphics/Screen.java | 5 +- src/uet/oop/bomberman/gui/GameScreen.java | 8 -- src/uet/oop/bomberman/input/Keyboard.java | 42 +----- .../bomberman/screen/SelectLevelScreen.java | 114 --------------- src/uet/oop/bomberman/utils/EGameControl.java | 11 -- src/uet/oop/bomberman/utils/EGameLevel.java | 17 --- src/uet/oop/bomberman/utils/EScreenName.java | 6 - src/uet/oop/bomberman/utils/Global.java | 8 -- 9 files changed, 52 insertions(+), 291 deletions(-) delete mode 100644 src/uet/oop/bomberman/gui/GameScreen.java delete mode 100644 src/uet/oop/bomberman/screen/SelectLevelScreen.java delete mode 100644 src/uet/oop/bomberman/utils/EGameControl.java delete mode 100644 src/uet/oop/bomberman/utils/EGameLevel.java delete mode 100644 src/uet/oop/bomberman/utils/EScreenName.java delete mode 100644 src/uet/oop/bomberman/utils/Global.java diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 6af2a57..f043707 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,9 +3,6 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; -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; @@ -52,16 +49,8 @@ public class Game extends Canvas { 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 - private SelectLevelScreen selectLevelScreen; - public Game(Frame frame) { _frame = frame; _frame.setTitle(TITLE); @@ -71,12 +60,15 @@ public Game(Frame frame) { _board = new Board(this, _input, screen); addKeyListener(_input); - - initScreen(); } - - - private void renderGame(Graphics g) { + + private void renderGame() { + BufferStrategy bs = getBufferStrategy(); + if (bs == null) { + createBufferStrategy(3); + return; + } + screen.clear(); _board.render(screen); @@ -84,94 +76,47 @@ private void renderGame(Graphics g) { for (int i = 0; i < pixels.length; i++) { pixels[i] = screen._pixels[i]; } - - g.drawImage(image, 0, 0, getWidth(), getHeight(), null); - _board.renderMessages(g); - } - - private void renderScreen(Graphics g) { - screen.clear(); - _board.drawScreen(g); - } - private void initScreen() { - Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN; + Graphics g = bs.getDrawGraphics(); - this.selectLevelScreen = new SelectLevelScreen(_input); - } + g.drawImage(image, 0, 0, getWidth(), getHeight(), null); + _board.renderMessages(g); - private void update() { - _input.update(); - switch (Global.currentScreen) { - case GAME_PLAY_SCREEN: - _board.update(); - break; - case SELECT_LEVEL_SCREEN: - // TODO: call select level screen update - selectLevelScreen.update(); - break; - } + g.dispose(); + bs.show(); } - private void showScreen() { + private void renderScreen() { BufferStrategy bs = getBufferStrategy(); if (bs == null) { createBufferStrategy(3); return; } - Graphics g = bs.getDrawGraphics(); - - switch (Global.currentScreen) { - case GAME_PLAY_SCREEN: - if(_paused) { - if(_screenDelay <= 0) { - _board.setShow(-1); - _paused = false; - } - - renderScreen(g); - } else { - renderGame(g); - } + screen.clear(); - 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; + Graphics g = bs.getDrawGraphics(); - if(_board.getShow() == 2) - --_screenDelay; - } - break; - case SELECT_LEVEL_SCREEN: - // TODO: render select level screen - selectLevelScreen.drawScreen(g); - break; - } + _board.drawScreen(g); g.dispose(); bs.show(); } - private void initGame() { - this.timer = System.currentTimeMillis(); - this.frames = 0; - this.updates = 0; + private void update() { + _input.update(); + _board.update(); } public void start() { _running = true; - initGame(); - - long lastTime = System.nanoTime(); - final double ns = 1000000000.0 / 60.0; //nanosecond, 60 frames per second + long lastTime = System.nanoTime(); + long timer = System.currentTimeMillis(); + final double ns = 1000000000.0 / 60.0; // nanosecond, 60 frames per second double delta = 0; + int frames = 0; + int updates = 0; requestFocus(); while (_running) { long now = System.nanoTime(); @@ -183,7 +128,30 @@ public void start() { delta--; } - showScreen(); + 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()); + _frame.setItemTime(_board.getItemTime()); + timer += 1000; + _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps"); + updates = 0; + frames = 0; + + if (_board.getShow() == 2) + --_screenDelay; + } } } diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 8cbc134..2494ea2 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -4,7 +4,6 @@ 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.*; @@ -23,9 +22,7 @@ public Screen(int width, int height) { _height = height; _pixels = new int[width * height]; - - Global.screenWidth = this.getRealWidth(); - Global.screenHeight = this.getRealHeight(); + } public void clear() { diff --git a/src/uet/oop/bomberman/gui/GameScreen.java b/src/uet/oop/bomberman/gui/GameScreen.java deleted file mode 100644 index 93a79c1..0000000 --- a/src/uet/oop/bomberman/gui/GameScreen.java +++ /dev/null @@ -1,8 +0,0 @@ -package uet.oop.bomberman.gui; - -import java.awt.*; - -public abstract class GameScreen { - public abstract void drawScreen(Graphics g); - public abstract void update(); -} diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index 7026dc9..bb8daad 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -1,23 +1,15 @@ package uet.oop.bomberman.input; -import uet.oop.bomberman.utils.EGameControl; - 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 { - - public interface KeyboardInputCallback { - void onKeyPressed(EGameControl gameControl); - } private boolean[] keys = new boolean[120]; //120 is enough to this game public boolean up, down, left, right, space; - public Optional keyboardInputCallback; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -27,45 +19,13 @@ public void update() { space = keys[KeyEvent.VK_SPACE] || keys[KeyEvent.VK_X]; } - 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 || keyCode == KeyEvent.VK_X) { - return EGameControl.SPACE; - } - - if (keyCode == KeyEvent.VK_ENTER) { - return EGameControl.ENTER; - } - - return EGameControl.NONE; - } - @Override 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 diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java deleted file mode 100644 index 33fb2a1..0000000 --- a/src/uet/oop/bomberman/screen/SelectLevelScreen.java +++ /dev/null @@ -1,114 +0,0 @@ -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.EGameLevel; -import uet.oop.bomberman.utils.EScreenName; -import uet.oop.bomberman.utils.Global; - -import java.awt.*; -import java.awt.event.KeyEvent; -import java.util.ArrayList; - -public class SelectLevelScreen extends GameScreen { - ArrayList levels = new ArrayList(); - int selectorIndex = 0; - private Keyboard _input; - - public SelectLevelScreen(Keyboard input) { - _input = input; - - levels.add(EGameLevel.EASY.getStringLevel()); - levels.add(EGameLevel.MEDIUM.getStringLevel()); - levels.add(EGameLevel.HARD.getStringLevel()); - - _input.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.currentScreen = EScreenName.GAME_PLAY_SCREEN; - 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() {} -} diff --git a/src/uet/oop/bomberman/utils/EGameControl.java b/src/uet/oop/bomberman/utils/EGameControl.java deleted file mode 100644 index fa8cea4..0000000 --- a/src/uet/oop/bomberman/utils/EGameControl.java +++ /dev/null @@ -1,11 +0,0 @@ -package uet.oop.bomberman.utils; - -public enum EGameControl { - NONE, - UP, - DOWN, - LEFT, - RIGHT, - ENTER, - SPACE, -} diff --git a/src/uet/oop/bomberman/utils/EGameLevel.java b/src/uet/oop/bomberman/utils/EGameLevel.java deleted file mode 100644 index 7644772..0000000 --- a/src/uet/oop/bomberman/utils/EGameLevel.java +++ /dev/null @@ -1,17 +0,0 @@ -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/EScreenName.java b/src/uet/oop/bomberman/utils/EScreenName.java deleted file mode 100644 index 515a6e8..0000000 --- a/src/uet/oop/bomberman/utils/EScreenName.java +++ /dev/null @@ -1,6 +0,0 @@ -package uet.oop.bomberman.utils; - -public enum EScreenName { - SELECT_LEVEL_SCREEN, - GAME_PLAY_SCREEN, -} diff --git a/src/uet/oop/bomberman/utils/Global.java b/src/uet/oop/bomberman/utils/Global.java deleted file mode 100644 index 623e0a6..0000000 --- a/src/uet/oop/bomberman/utils/Global.java +++ /dev/null @@ -1,8 +0,0 @@ -package uet.oop.bomberman.utils; - -public class Global { - public static int screenWidth; - public static int screenHeight; - - public static EScreenName currentScreen; -} From 49bc95ca4416ce7c37c31dc246b45d4f1e7b4254 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Tue, 14 May 2024 22:08:03 +0700 Subject: [PATCH 12/28] Revert "Revert "Select level"" This reverts commit e6441d4f5bd241cabfdb99140bb9aae842edccf6. --- src/uet/oop/bomberman/Game.java | 132 +++++++++++------- src/uet/oop/bomberman/graphics/Screen.java | 5 +- src/uet/oop/bomberman/gui/GameScreen.java | 8 ++ src/uet/oop/bomberman/input/Keyboard.java | 42 +++++- .../bomberman/screen/SelectLevelScreen.java | 114 +++++++++++++++ src/uet/oop/bomberman/utils/EGameControl.java | 11 ++ src/uet/oop/bomberman/utils/EGameLevel.java | 17 +++ src/uet/oop/bomberman/utils/EScreenName.java | 6 + src/uet/oop/bomberman/utils/Global.java | 8 ++ 9 files changed, 291 insertions(+), 52 deletions(-) create mode 100644 src/uet/oop/bomberman/gui/GameScreen.java create mode 100644 src/uet/oop/bomberman/screen/SelectLevelScreen.java create mode 100644 src/uet/oop/bomberman/utils/EGameControl.java create mode 100644 src/uet/oop/bomberman/utils/EGameLevel.java create mode 100644 src/uet/oop/bomberman/utils/EScreenName.java create mode 100644 src/uet/oop/bomberman/utils/Global.java diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index f043707..6af2a57 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,6 +3,9 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; +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; @@ -49,8 +52,16 @@ public class Game extends Canvas { 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 + private SelectLevelScreen selectLevelScreen; + public Game(Frame frame) { _frame = frame; _frame.setTitle(TITLE); @@ -60,15 +71,12 @@ public Game(Frame frame) { _board = new Board(this, _input, screen); addKeyListener(_input); - } - - private void renderGame() { - BufferStrategy bs = getBufferStrategy(); - if (bs == null) { - createBufferStrategy(3); - return; - } + initScreen(); + } + + + private void renderGame(Graphics g) { screen.clear(); _board.render(screen); @@ -76,47 +84,94 @@ private void renderGame() { 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); + } + + private void renderScreen(Graphics g) { + screen.clear(); + _board.drawScreen(g); + } - g.dispose(); - bs.show(); + private void initScreen() { + Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN; + + this.selectLevelScreen = new SelectLevelScreen(_input); } - private void renderScreen() { + private void update() { + _input.update(); + switch (Global.currentScreen) { + case GAME_PLAY_SCREEN: + _board.update(); + break; + case SELECT_LEVEL_SCREEN: + // TODO: call select level screen update + selectLevelScreen.update(); + break; + } + } + + private void showScreen() { BufferStrategy bs = getBufferStrategy(); if (bs == null) { createBufferStrategy(3); return; } + Graphics g = bs.getDrawGraphics(); - screen.clear(); + switch (Global.currentScreen) { + case GAME_PLAY_SCREEN: + if(_paused) { + if(_screenDelay <= 0) { + _board.setShow(-1); + _paused = false; + } + + renderScreen(g); + } else { + renderGame(g); + } - Graphics g = bs.getDrawGraphics(); - _board.drawScreen(g); + 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; + } + break; + case SELECT_LEVEL_SCREEN: + // TODO: render select level screen + selectLevelScreen.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) { long now = System.nanoTime(); @@ -128,30 +183,7 @@ public void start() { 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()); - _frame.setItemTime(_board.getItemTime()); - timer += 1000; - _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps"); - updates = 0; - frames = 0; - - if (_board.getShow() == 2) - --_screenDelay; - } + showScreen(); } } diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 2494ea2..8cbc134 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -4,6 +4,7 @@ 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.*; @@ -22,7 +23,9 @@ public Screen(int width, int height) { _height = height; _pixels = new int[width * height]; - + + Global.screenWidth = this.getRealWidth(); + Global.screenHeight = this.getRealHeight(); } public void clear() { diff --git a/src/uet/oop/bomberman/gui/GameScreen.java b/src/uet/oop/bomberman/gui/GameScreen.java new file mode 100644 index 0000000..93a79c1 --- /dev/null +++ b/src/uet/oop/bomberman/gui/GameScreen.java @@ -0,0 +1,8 @@ +package uet.oop.bomberman.gui; + +import java.awt.*; + +public abstract class GameScreen { + public abstract void drawScreen(Graphics g); + public abstract void update(); +} diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index bb8daad..7026dc9 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -1,15 +1,23 @@ package uet.oop.bomberman.input; +import uet.oop.bomberman.utils.EGameControl; + 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 { + + public interface KeyboardInputCallback { + void onKeyPressed(EGameControl gameControl); + } private boolean[] keys = new boolean[120]; //120 is enough to this game public boolean up, down, left, right, space; + public Optional keyboardInputCallback; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -19,13 +27,45 @@ public void update() { space = keys[KeyEvent.VK_SPACE] || keys[KeyEvent.VK_X]; } + 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 || keyCode == KeyEvent.VK_X) { + return EGameControl.SPACE; + } + + if (keyCode == KeyEvent.VK_ENTER) { + return EGameControl.ENTER; + } + + return EGameControl.NONE; + } + @Override 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 diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java new file mode 100644 index 0000000..33fb2a1 --- /dev/null +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -0,0 +1,114 @@ +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.EGameLevel; +import uet.oop.bomberman.utils.EScreenName; +import uet.oop.bomberman.utils.Global; + +import java.awt.*; +import java.awt.event.KeyEvent; +import java.util.ArrayList; + +public class SelectLevelScreen extends GameScreen { + ArrayList levels = new ArrayList(); + int selectorIndex = 0; + private Keyboard _input; + + public SelectLevelScreen(Keyboard input) { + _input = input; + + levels.add(EGameLevel.EASY.getStringLevel()); + levels.add(EGameLevel.MEDIUM.getStringLevel()); + levels.add(EGameLevel.HARD.getStringLevel()); + + _input.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.currentScreen = EScreenName.GAME_PLAY_SCREEN; + 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() {} +} diff --git a/src/uet/oop/bomberman/utils/EGameControl.java b/src/uet/oop/bomberman/utils/EGameControl.java new file mode 100644 index 0000000..fa8cea4 --- /dev/null +++ b/src/uet/oop/bomberman/utils/EGameControl.java @@ -0,0 +1,11 @@ +package uet.oop.bomberman.utils; + +public enum EGameControl { + NONE, + UP, + DOWN, + LEFT, + RIGHT, + ENTER, + SPACE, +} 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/EScreenName.java b/src/uet/oop/bomberman/utils/EScreenName.java new file mode 100644 index 0000000..515a6e8 --- /dev/null +++ b/src/uet/oop/bomberman/utils/EScreenName.java @@ -0,0 +1,6 @@ +package uet.oop.bomberman.utils; + +public enum EScreenName { + SELECT_LEVEL_SCREEN, + GAME_PLAY_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..623e0a6 --- /dev/null +++ b/src/uet/oop/bomberman/utils/Global.java @@ -0,0 +1,8 @@ +package uet.oop.bomberman.utils; + +public class Global { + public static int screenWidth; + public static int screenHeight; + + public static EScreenName currentScreen; +} From f0a9bcd660dade615c472c67025dceb3a8cecdc4 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Tue, 14 May 2024 16:43:18 +0000 Subject: [PATCH 13/28] use constant for TICKS_PER_SECOND --- src/uet/oop/bomberman/Board.java | 2 +- src/uet/oop/bomberman/Game.java | 3 ++- src/uet/oop/bomberman/entities/Message.java | 3 ++- src/uet/oop/bomberman/entities/bomb/Bomb.java | 2 +- src/uet/oop/bomberman/entities/character/enemy/Balloon.java | 4 ++-- src/uet/oop/bomberman/entities/character/enemy/Doll.java | 5 +++-- src/uet/oop/bomberman/entities/character/enemy/Enemy.java | 2 +- src/uet/oop/bomberman/entities/character/enemy/Kondoria.java | 4 ++-- src/uet/oop/bomberman/entities/character/enemy/Minvo.java | 4 ++-- src/uet/oop/bomberman/entities/character/enemy/Oneal.java | 4 ++-- src/uet/oop/bomberman/entities/tile/item/Item.java | 2 +- src/uet/oop/bomberman/gui/InfoPanel.java | 2 +- src/uet/oop/bomberman/input/Keyboard.java | 2 +- 13 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 0bf31f2..5d05ee3 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -348,7 +348,7 @@ public int subtractTime() { public int getItemTime() { int totalTime = 0; for (int i = 0; i < _activeItems.size(); i++) { - totalTime += _activeItems.get(i).getDuration() / 60; + totalTime += _activeItems.get(i).getDuration() / Game.TICKS_PER_SECOND; } return totalTime; } diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index f043707..b217f0b 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -22,6 +22,7 @@ public class Game extends Canvas { public static int SCALE = 3; public static final String TITLE = "BombermanGame"; + public static final int TICKS_PER_SECOND = 60; private static final int BOMBRATE = 1; private static final int BOMBRADIUS = 1; @@ -113,7 +114,7 @@ public void start() { long lastTime = System.nanoTime(); long timer = System.currentTimeMillis(); - final double ns = 1000000000.0 / 60.0; // nanosecond, 60 frames per second + final double ns = 1000000000.0 / TICKS_PER_SECOND; // nanosecond, 60 frames per second double delta = 0; int frames = 0; int updates = 0; diff --git a/src/uet/oop/bomberman/entities/Message.java b/src/uet/oop/bomberman/entities/Message.java index 1e743e7..4bfab68 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; } diff --git a/src/uet/oop/bomberman/entities/bomb/Bomb.java b/src/uet/oop/bomberman/entities/bomb/Bomb.java index 34e1a20..f65b5d7 100644 --- a/src/uet/oop/bomberman/entities/bomb/Bomb.java +++ b/src/uet/oop/bomberman/entities/bomb/Bomb.java @@ -52,7 +52,7 @@ public void render(Screen screen) { _sprite = Sprite.bomb_exploded2; renderFlames(screen); } else - _sprite = Sprite.movingSprite(Sprite.bomb, Sprite.bomb_1, Sprite.bomb_2, _animate, 60); + _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; diff --git a/src/uet/oop/bomberman/entities/character/enemy/Balloon.java b/src/uet/oop/bomberman/entities/character/enemy/Balloon.java index e0d43dc..f8a3ab1 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Balloon.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Balloon.java @@ -25,11 +25,11 @@ protected void chooseSprite() { switch(_direction) { 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..72fbc18 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Doll.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Doll.java @@ -6,6 +6,7 @@ package uet.oop.bomberman.entities.character.enemy; 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.graphics.Sprite; @@ -32,7 +33,7 @@ protected void chooseSprite() { case 0: case 1: if (_moving) { - _sprite = Sprite.movingSprite(Sprite.doll_right1, Sprite.doll_right2, Sprite.doll_right3, _animate, 60); + _sprite = Sprite.movingSprite(Sprite.doll_right1, Sprite.doll_right2, Sprite.doll_right3, _animate, Game.TICKS_PER_SECOND); } else { _sprite = Sprite.doll_left1; } @@ -40,7 +41,7 @@ protected void chooseSprite() { case 2: case 3: if (_moving) { - _sprite = Sprite.movingSprite(Sprite.doll_left1, Sprite.doll_left2, Sprite.doll_left3, _animate, 60); + _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..cabd65d 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java @@ -66,7 +66,7 @@ public void render(Screen screen) { _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); } } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java index 95fe5d4..b7cb406 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java @@ -23,7 +23,7 @@ protected void chooseSprite() { case 1: if (_moving) _sprite = Sprite.movingSprite(Sprite.kondoria_right1, Sprite.kondoria_right2, - Sprite.kondoria_right3, _animate, 60); + Sprite.kondoria_right3, _animate, Game.TICKS_PER_SECOND); else _sprite = Sprite.kondoria_left1; break; @@ -31,7 +31,7 @@ protected void chooseSprite() { case 3: if (_moving) _sprite = Sprite.movingSprite(Sprite.kondoria_left1, Sprite.kondoria_left2, Sprite.kondoria_left3, - _animate, 60); + _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 index e4ad4d7..c16c976 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java @@ -24,7 +24,7 @@ protected void chooseSprite() { case 1: if (_moving) _sprite = Sprite.movingSprite(Sprite.minvo_right1, Sprite.minvo_right2, Sprite.minvo_right3, - _animate, 60); + _animate, Game.TICKS_PER_SECOND); else _sprite = Sprite.minvo_left1; break; @@ -32,7 +32,7 @@ protected void chooseSprite() { case 3: if (_moving) _sprite = Sprite.movingSprite(Sprite.minvo_left1, Sprite.minvo_left2, Sprite.minvo_left3, _animate, - 60); + 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..608255f 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Oneal.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Oneal.java @@ -27,14 +27,14 @@ protected void chooseSprite() { case 0: case 1: if(_moving) - _sprite = Sprite.movingSprite(Sprite.oneal_right1, Sprite.oneal_right2, Sprite.oneal_right3, _animate, 60); + _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); + _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/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index b67655a..59b6ba8 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -8,7 +8,7 @@ import uet.oop.bomberman.sound.Sound; public abstract class Item extends Tile { - protected int _duration = 300; // 5s + protected int _duration = 30 * Game.TICKS_PER_SECOND; // 30s protected boolean _active = false; protected int _level; diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index 166630b..825e741 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -58,7 +58,7 @@ public void setItemTime(int t) { if ((item.getDuration()) == 0) { continue; } - label += item.getDisplayActiveItem() + item.getDuration() / 60 + " "; + 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..d338c50 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -8,7 +8,7 @@ */ public class Keyboard implements KeyListener { - private boolean[] keys = new boolean[120]; //120 is enough to this game + private boolean[] keys = new boolean[65536]; public boolean up, down, left, right, space; public void update() { From 165c802254a7b80cc17a62172990e801e7c4b999 Mon Sep 17 00:00:00 2001 From: 21522098_HuyHoang <21522098@gm.uit.edu.vn> Date: Wed, 15 May 2024 16:35:53 +0700 Subject: [PATCH 14/28] Changes Pause to ESC --- src/uet/oop/bomberman/Game.java | 23 ++++++++--------------- src/uet/oop/bomberman/gui/InfoPanel.java | 20 +------------------- src/uet/oop/bomberman/input/Keyboard.java | 5 +++-- 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index c44c977..55f9388 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,13 +3,13 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; -import uet.oop.bomberman.gui.InfoPanel; import java.awt.*; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; -import javafx.event.ActionEvent; +import javax.swing.JButton; + /** * 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, @@ -47,7 +47,6 @@ public class Game extends Canvas { private boolean _running = false; private boolean _paused = true; private boolean _paused1 = true; - private Board _board; private Screen screen; private Frame _frame; @@ -64,6 +63,7 @@ public Game(Frame frame) { _board = new Board(this, _input, screen); addKeyListener(_input); + } @@ -144,19 +144,12 @@ public void start() { } else { renderGame(); } - if (_paused1) { - _board.setShow(3); - } else { - _board.setShow(-1); - } - if (_input.pause) { - _paused1 = !_paused1; - if (_paused) { - _board.setShow(3); - } else { - } - } + if (_input.resume) { + _paused = false; + _board.setShow(-1); + } + frames++; diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index 2341c67..8d2f9ae 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -10,15 +10,11 @@ * 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 static Board _board; - private boolean gamePaused = false; private JLabel timeLabel; private JLabel pointsLabel; - private JButton pauseButton; - private Game game; + public InfoPanel(Game game) { setLayout(new GridLayout(1, 3)); - this.game = game; timeLabel = new JLabel("Time: " + game.getBoard().getTime()); timeLabel.setForeground(Color.white); timeLabel.setHorizontalAlignment(JLabel.CENTER); @@ -26,23 +22,9 @@ public InfoPanel(Game game) { pointsLabel = new JLabel("Points: " + game.getBoard().getPoints()); pointsLabel.setForeground(Color.white); pointsLabel.setHorizontalAlignment(JLabel.CENTER); - - pauseButton = new JButton("Pause"); - pauseButton.setForeground(Color.WHITE); - pauseButton.setHorizontalAlignment(JButton.CENTER); - pauseButton.setBackground(Color.BLACK); - pauseButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - game.pause(); - gamePaused = !gamePaused; - pauseButton.setText(gamePaused? "Resume" : "Pause"); - } - }); add(timeLabel); add(pointsLabel); - add(pauseButton); setBackground(Color.black); setPreferredSize(new Dimension(0, 40)); } diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index 44fdf07..d3ab986 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -9,7 +9,7 @@ public class Keyboard implements KeyListener { private boolean[] keys = new boolean[120]; //120 is enough to this game - public boolean up, down, left, right, space,pause; + public boolean up, down, left, right, space,pause,resume; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -17,7 +17,8 @@ public void update() { 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]; - pause = keys[KeyEvent.VK_P]; + pause = keys[KeyEvent.VK_ESCAPE]; + resume = keys[KeyEvent.VK_ENTER]; } @Override From a791aafcc64739a537e2db17e75a3b2ef81c05f6 Mon Sep 17 00:00:00 2001 From: 21522098_HuyHoang <21522098@gm.uit.edu.vn> Date: Wed, 15 May 2024 18:15:07 +0700 Subject: [PATCH 15/28] Fixed --- src/uet/oop/bomberman/Game.java | 5 +---- src/uet/oop/bomberman/gui/InfoPanel.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 64c1b08..aaa12d1 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -45,8 +45,7 @@ public class Game extends Canvas { private Keyboard _input; private boolean _running = false; private boolean _paused = true; - private boolean _paused1 = true; - private Board _board; + private static Board _board; private Screen screen; private Frame _frame; @@ -196,11 +195,9 @@ public static void addBombRate(int i) { public void resetScreenDelay() { _screenDelay = SCREENDELAY; } - public static Board getBoard() { return _board; } - public boolean isPaused() { return _paused; } diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index d06a1ed..9958ca3 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -15,7 +15,7 @@ public class InfoPanel extends JPanel { private JLabel timeLabel; private JLabel pointsLabel; private JLabel itemTimeLabel; - + private Game game; public InfoPanel(Game game) { setLayout(new GridLayout()); timeLabel = new JLabel("Time: " + game.getBoard().getTime()); From a228e7c90d6618f912cd83c527fb7f5b9fd86060 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Wed, 15 May 2024 23:30:29 +0700 Subject: [PATCH 16/28] update infopanel --- src/uet/oop/bomberman/Game.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 6af2a57..a95382b 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -139,6 +139,7 @@ private void showScreen() { if(System.currentTimeMillis() - timer > 1000) { _frame.setTime(_board.subtractTime()); _frame.setPoints(_board.getPoints()); + _frame.setItemTime(_board.getItemTime()); timer += 1000; _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps"); updates = 0; From 4042a325aba03efde6aaca8b9887f88dbbfd0c4b Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 13:35:57 +0000 Subject: [PATCH 17/28] extract interface IEntityManager and IMessageManager from Board --- src/uet/oop/bomberman/Board.java | 15 ++++++++++- .../oop/bomberman/base/IEntityManager.java | 26 +++++++++++++++++++ .../oop/bomberman/base/IMessageManager.java | 9 +++++++ src/uet/oop/bomberman/entities/bomb/Bomb.java | 6 ++--- .../oop/bomberman/entities/bomb/Flame.java | 6 ++--- .../bomberman/entities/character/Bomber.java | 16 +++++++----- .../entities/character/Character.java | 7 ++--- .../entities/character/enemy/Doll.java | 2 +- .../entities/character/enemy/Enemy.java | 7 ++++- .../entities/character/enemy/Kondoria.java | 2 +- .../oop/bomberman/level/FileLevelLoader.java | 2 +- 11 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 src/uet/oop/bomberman/base/IEntityManager.java create mode 100644 src/uet/oop/bomberman/base/IMessageManager.java diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 5d05ee3..34b6e49 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -1,5 +1,7 @@ package uet.oop.bomberman; +import uet.oop.bomberman.base.IEntityManager; +import uet.oop.bomberman.base.IMessageManager; import uet.oop.bomberman.entities.Entity; import uet.oop.bomberman.entities.Message; import uet.oop.bomberman.entities.bomb.Bomb; @@ -22,7 +24,7 @@ /** * 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 IRender, IEntityManager, IMessageManager { protected LevelLoader _levelLoader; protected Game _game; protected Keyboard _input; @@ -153,6 +155,7 @@ public void drawScreen(Graphics g) { } } + @Override public Entity getEntity(double x, double y, Character m) { Entity res = null; @@ -174,10 +177,12 @@ public Entity getEntity(double x, double y, Character m) { return res; } + @Override public List getBombs() { return _bombs; } + @Override public Bomb getBombAt(double x, double y) { Iterator bs = _bombs.iterator(); Bomb b; @@ -190,6 +195,7 @@ public Bomb getBombAt(double x, double y) { return null; } + @Override public Bomber getBomber() { Iterator itr = _characters.iterator(); @@ -204,6 +210,7 @@ public Bomber getBomber() { return null; } + @Override public Character getCharacterAtExcluding(int x, int y, Character a) { Iterator itr = _characters.iterator(); @@ -223,6 +230,7 @@ public Character getCharacterAtExcluding(int x, int y, Character a) { return null; } + @Override public FlameSegment getFlameSegmentAt(int x, int y) { Iterator bs = _bombs.iterator(); Bomb b; @@ -238,6 +246,7 @@ public FlameSegment getFlameSegmentAt(int x, int y) { return null; } + @Override public Entity getEntityAt(double x, double y) { return _entities[(int) x + (int) y * _levelLoader.getWidth()]; } @@ -246,18 +255,22 @@ public void addActiveItem(Item item) { _activeItems.add(item); } + @Override public void addEntity(int pos, Entity e) { _entities[pos] = e; } + @Override public void addCharacter(Character e) { _characters.add(e); } + @Override public void addBomb(Bomb e) { _bombs.add(e); } + @Override public void addMessage(Message e) { _messages.add(e); } diff --git a/src/uet/oop/bomberman/base/IEntityManager.java b/src/uet/oop/bomberman/base/IEntityManager.java new file mode 100644 index 0000000..ddf0d77 --- /dev/null +++ b/src/uet/oop/bomberman/base/IEntityManager.java @@ -0,0 +1,26 @@ +package uet.oop.bomberman.base; + +import java.util.List; + +import uet.oop.bomberman.entities.Entity; +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; + +public interface IEntityManager { + + public List getBombs(); + public Bomber getBomber(); + + public Entity getEntity(double x, double y, Character m); + public Entity getEntityAt(double x, double y); + public Bomb getBombAt(double x, double y); + public Character getCharacterAtExcluding(int x, int y, Character a); + public FlameSegment getFlameSegmentAt(int x, int y); + + public void addEntity(int pos, Entity e); + public void addCharacter(Character e); + public void addBomb(Bomb e); + +} \ 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/entities/bomb/Bomb.java b/src/uet/oop/bomberman/entities/bomb/Bomb.java index f65b5d7..6e200ab 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; @@ -15,12 +15,12 @@ public class Bomb extends AnimatedEntitiy { 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) { + public Bomb(int x, int y, IEntityManager board) { _x = x; _y = y; _board = board; diff --git a/src/uet/oop/bomberman/entities/bomb/Flame.java b/src/uet/oop/bomberman/entities/bomb/Flame.java index 721bc25..71f8fd3 100644 --- a/src/uet/oop/bomberman/entities/bomb/Flame.java +++ b/src/uet/oop/bomberman/entities/bomb/Flame.java @@ -1,6 +1,6 @@ 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; @@ -8,7 +8,7 @@ public class Flame extends Entity { - protected Board _board; + protected IEntityManager _board; protected int _direction; private int _radius; protected int xOrigin, yOrigin; @@ -21,7 +21,7 @@ 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 board) { xOrigin = x; yOrigin = y; _x = x; diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index bcc797d..4e34e9c 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -3,6 +3,7 @@ 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.graphics.Screen; @@ -29,9 +30,12 @@ public class Bomber extends Character { */ protected int _timeBetweenPutBombs = 0; - public Bomber(int x, int y, Board board) { - super(x, y, board); - _bombs = _board.getBombs(); + private Board _board; + + public Bomber(int x, int y, IEntityManager entityManager, Board board) { + super(x, y, entityManager); + this._board = board; + _bombs = entityManager.getBombs(); _input = _board.getInput(); _sprite = Sprite.player_right; } @@ -94,8 +98,8 @@ private void detectPlaceBomb() { 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); + Bomb b = new Bomb(x, y, entityManager); + entityManager.addBomb(b); Sound.play("BOM_SET"); } @@ -153,7 +157,7 @@ public boolean canMove(double x, double y) { 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); + Entity a = entityManager.getEntity(xt, yt, this); if(!a.collide(this)) return false; diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 52842a9..2a2335b 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -2,6 +2,7 @@ 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.graphics.Screen; @@ -10,16 +11,16 @@ */ public abstract class Character extends AnimatedEntitiy { - protected Board _board; + protected IEntityManager entityManager; protected int _direction = -1; protected boolean _alive = true; protected boolean _moving = false; public int _timeAfter = 40; - public Character(int x, int y, Board board) { + public Character(int x, int y, IEntityManager entityManager) { _x = x; _y = y; - _board = board; + this.entityManager = entityManager; } @Override diff --git a/src/uet/oop/bomberman/entities/character/enemy/Doll.java b/src/uet/oop/bomberman/entities/character/enemy/Doll.java index 72fbc18..18c2924 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Doll.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Doll.java @@ -22,7 +22,7 @@ public Doll(int x, int y, Board board) { _sprite = Sprite.balloom_left1; - _ai = new AIMedium(_board.getBomber(), this); + _ai = new AIMedium(entityManager.getBomber(), this); _direction = _ai.calculateDirection(); } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java index cabd65d..a3a33f9 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java @@ -2,6 +2,7 @@ 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; @@ -28,9 +29,13 @@ public abstract class Enemy extends Character { protected int _finalAnimation = 30; protected Sprite _deadSprite; + + private Board _board; public Enemy(int x, int y, Board board, Sprite dead, double speed, int points) { super(x, y, board); + + this._board = board; _points = points; _speed = speed; @@ -122,7 +127,7 @@ public boolean canMove(double x, double y) { 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 + Entity a = entityManager.getEntity(xx, yy, this); //entity of the position we want to go return a.collide(this); } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java index b7cb406..a7f20a7 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java @@ -11,7 +11,7 @@ public Kondoria(int x, int y, Board board) { _sprite = Sprite.kondoria_right1; - _ai = new AIMedium(_board.getBomber(), this); + _ai = new AIMedium(entityManager.getBomber(), this); _direction = _ai.calculateDirection(); // this._speed += random.nextDouble()/2; } diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index d7ca60a..d673ca8 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -103,7 +103,7 @@ public void createEntities() { break; // Thêm Bomber case 'p': - _board.addCharacter(new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board)); + _board.addCharacter(new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board, _board)); Screen.setOffset(0, 0); _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass)); break; From e7b5244735d9759bc359d88ec6ae3a8177a7032f Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 14:49:33 +0000 Subject: [PATCH 18/28] decouple Bomber class by adding isPlayer() --- src/uet/oop/bomberman/Board.java | 34 ++++++---------- .../oop/bomberman/base/IEntityManager.java | 7 +++- .../oop/bomberman/entities/bomb/Flame.java | 11 +++-- .../bomberman/entities/bomb/FlameSegment.java | 7 +--- .../entities/character/Character.java | 4 ++ .../entities/character/enemy/Doll.java | 2 +- .../entities/character/enemy/Enemy.java | 16 ++++---- .../entities/character/enemy/Kondoria.java | 2 +- .../entities/character/enemy/Minvo.java | 2 +- .../entities/character/enemy/ai/AIMedium.java | 18 ++++----- .../oop/bomberman/entities/tile/Portal.java | 40 +++++++++---------- .../entities/tile/item/BombItem.java | 3 -- .../entities/tile/item/FlameItem.java | 3 -- .../bomberman/entities/tile/item/Item.java | 5 +-- .../entities/tile/item/SpeedItem.java | 3 -- src/uet/oop/bomberman/graphics/Screen.java | 11 +++-- .../oop/bomberman/level/FileLevelLoader.java | 7 ++-- 17 files changed, 78 insertions(+), 97 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 34b6e49..57561b1 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -6,7 +6,6 @@ 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.entities.tile.item.Item; import uet.oop.bomberman.exceptions.LoadLevelException; @@ -36,6 +35,8 @@ public class Board implements IRender, IEntityManager, IMessageManager { private List _messages = new ArrayList<>(); private List _activeItems = new ArrayList<>(); + private Character player; + public List getActiveItems() { return _activeItems; } @@ -131,14 +132,10 @@ public void endGame() { _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; + @Override + public boolean isEnemyCleared() { + return _characters.stream() + .allMatch(character -> character != getPlayer()); } public void drawScreen(Graphics g) { @@ -196,18 +193,8 @@ public Bomb getBombAt(double x, double y) { } @Override - 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 getPlayer() { + return this.player; } @Override @@ -406,4 +393,9 @@ public int getHeight() { return _levelLoader.getHeight(); } + @Override + public void setPlayer(Character character) { + this.player = character; + } + } diff --git a/src/uet/oop/bomberman/base/IEntityManager.java b/src/uet/oop/bomberman/base/IEntityManager.java index ddf0d77..2135078 100644 --- a/src/uet/oop/bomberman/base/IEntityManager.java +++ b/src/uet/oop/bomberman/base/IEntityManager.java @@ -5,13 +5,11 @@ import uet.oop.bomberman.entities.Entity; 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; public interface IEntityManager { public List getBombs(); - public Bomber getBomber(); public Entity getEntity(double x, double y, Character m); public Entity getEntityAt(double x, double y); @@ -23,4 +21,9 @@ public interface IEntityManager { public void addCharacter(Character e); public void addBomb(Bomb e); + public void setPlayer(Character character); + public Character getPlayer(); + + public boolean isEnemyCleared(); + } \ No newline at end of file diff --git a/src/uet/oop/bomberman/entities/bomb/Flame.java b/src/uet/oop/bomberman/entities/bomb/Flame.java index 71f8fd3..f009521 100644 --- a/src/uet/oop/bomberman/entities/bomb/Flame.java +++ b/src/uet/oop/bomberman/entities/bomb/Flame.java @@ -2,8 +2,7 @@ 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.graphics.Screen; public class Flame extends Entity { @@ -110,9 +109,9 @@ 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).kill(); + } + return true; } } diff --git a/src/uet/oop/bomberman/entities/bomb/FlameSegment.java b/src/uet/oop/bomberman/entities/bomb/FlameSegment.java index 8a28539..4adf084 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,9 +68,7 @@ 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).kill(); return true; } diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 2a2335b..028432b 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -61,5 +61,9 @@ protected double getXMessage() { protected double getYMessage() { return (_y* Game.SCALE) - (_sprite.SIZE / 2 * Game.SCALE); } + + public boolean isPlayer() { + return entityManager.getPlayer() == this; + } } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Doll.java b/src/uet/oop/bomberman/entities/character/enemy/Doll.java index 18c2924..bc60e2c 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Doll.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Doll.java @@ -22,7 +22,7 @@ public Doll(int x, int y, Board board) { _sprite = Sprite.balloom_left1; - _ai = new AIMedium(entityManager.getBomber(), this); + _ai = new AIMedium(entityManager.getPlayer(), this); _direction = _ai.calculateDirection(); } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java index a3a33f9..e205c89 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java @@ -2,11 +2,9 @@ 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; @@ -135,13 +133,13 @@ public boolean canMove(double x, double y) { @Override public boolean collide(Entity e) { if(e instanceof Flame){ - this.kill(); - return false; - } - if(e instanceof Bomber){ - ((Bomber) e).kill(); - return false; - } + this.kill(); + return false; + } + if(e instanceof Character && ((Character)e).isPlayer()){ + ((Character) e).kill(); + return false; + } return true; } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java index a7f20a7..6f2a1f9 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java @@ -11,7 +11,7 @@ public Kondoria(int x, int y, Board board) { _sprite = Sprite.kondoria_right1; - _ai = new AIMedium(entityManager.getBomber(), this); + _ai = new AIMedium(entityManager.getPlayer(), this); _direction = _ai.calculateDirection(); // this._speed += random.nextDouble()/2; } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java index c16c976..5ec04b3 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java @@ -13,7 +13,7 @@ public Minvo(int x, int y, Board board) { _board = board; _sprite = Sprite.minvo_right1; - _ai = new AIMedium(_board.getBomber(), this); + _ai = new AIMedium(_board.getPlayer(), this); _direction = _ai.calculateDirection(); } 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..17a7bfc 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java +++ b/src/uet/oop/bomberman/entities/character/enemy/ai/AIMedium.java @@ -1,21 +1,21 @@ package uet.oop.bomberman.entities.character.enemy.ai; -import uet.oop.bomberman.entities.character.Bomber; +import uet.oop.bomberman.entities.character.Character; import uet.oop.bomberman.entities.character.enemy.Enemy; public class AIMedium extends AI { - Bomber _bomber; + Character player; Enemy _e; - public AIMedium(Bomber bomber, Enemy e) { - _bomber = bomber; + public AIMedium(Character player, Enemy e) { + this.player = player; _e = e; } @Override public int calculateDirection() { // TODO: cài đặt thuật toán tìm đường đi - if(_bomber == null) + if(player == null) return random.nextInt(4); int vertical = random.nextInt(2); @@ -37,18 +37,18 @@ public int calculateDirection() { } } protected int calculateColDirection() { - if(_bomber.getXTile() < _e.getXTile()) + if(player.getXTile() < _e.getXTile()) return 3; - else if(_bomber.getXTile() > _e.getXTile()) + else if(player.getXTile() > _e.getXTile()) return 1; return -1; } protected int calculateRowDirection() { - if(_bomber.getYTile() < _e.getYTile()) + if(player.getYTile() < _e.getYTile()) return 0; - else if(_bomber.getYTile() > _e.getYTile()) + else if(player.getYTile() > _e.getYTile()) return 2; return -1; } diff --git a/src/uet/oop/bomberman/entities/tile/Portal.java b/src/uet/oop/bomberman/entities/tile/Portal.java index 9b077d7..0b42570 100644 --- a/src/uet/oop/bomberman/entities/tile/Portal.java +++ b/src/uet/oop/bomberman/entities/tile/Portal.java @@ -1,40 +1,38 @@ 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) { + 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) + if (e instanceof Character && ((Character)e).isPlayer()) { + + if (!_board.isEnemyCleared()) return false; - - if(e.getXTile() == getX() && e.getYTile() == getY()) { - if(_board.detectNoEnemies()){ + + if (e.getXTile() == getX() && e.getYTile() == getY()) { + if (_board.isEnemyCleared()) { _board.nextLevel(); - Sound.play("CRYST_UP"); - } + Sound.play("CRYST_UP"); + } } - - return true; + } - + 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 cf9b5fc..598202a 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -1,10 +1,7 @@ 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 { diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java index 6507dcf..66fd498 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -1,10 +1,7 @@ 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 { diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index 59b6ba8..5e9f676 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -2,7 +2,7 @@ import uet.oop.bomberman.Game; import uet.oop.bomberman.entities.Entity; -import uet.oop.bomberman.entities.character.Bomber; +import uet.oop.bomberman.entities.character.Character; import uet.oop.bomberman.entities.tile.Tile; import uet.oop.bomberman.graphics.Sprite; import uet.oop.bomberman.sound.Sound; @@ -22,8 +22,7 @@ public Item(int x, int y, Sprite sprite) { @Override public boolean collide(Entity e) { - // TODO: xử lý Bomber ăn Item - if (e instanceof Bomber) { + if (e instanceof Character && ((Character)e).isPlayer()) { Sound.play("Item"); handleItemActive(); _active = true; diff --git a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java index e8ebfd8..bb0bd22 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -1,10 +1,7 @@ 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 { diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 9aa0058..e787942 100644 --- a/src/uet/oop/bomberman/graphics/Screen.java +++ b/src/uet/oop/bomberman/graphics/Screen.java @@ -3,7 +3,6 @@ import uet.oop.bomberman.Board; import uet.oop.bomberman.Game; import uet.oop.bomberman.entities.Entity; -import uet.oop.bomberman.entities.character.Bomber; import java.awt.*; @@ -66,17 +65,17 @@ public static void setOffset(int xO, int yO) { 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; diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index d673ca8..4bfe991 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -1,7 +1,6 @@ package uet.oop.bomberman.level; import java.io.BufferedReader; -import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.List; @@ -101,9 +100,11 @@ public void createEntities() { ) ); break; - // Thêm Bomber + // Thêm Bomber player case 'p': - _board.addCharacter(new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board, _board)); + Bomber bomber = new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board, _board); + _board.addCharacter(bomber); + _board.setPlayer(bomber); Screen.setOffset(0, 0); _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass)); break; From 68cb07d0794ac13e79545459a3d5d28a748545a2 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 15:12:38 +0000 Subject: [PATCH 19/28] move camera snapping from Bomber to Board --- src/uet/oop/bomberman/Board.java | 7 +++++++ src/uet/oop/bomberman/entities/character/Bomber.java | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 57561b1..dad56ea 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -54,6 +54,11 @@ public Board(Game game, Keyboard input, Screen screen) { loadLevel(1); // start in level 1 } + private void snapCameraToPlayer() { + int xScroll = Screen.calculateXOffset(this, getPlayer()); + Screen.setOffset(xScroll, 0); + } + @Override public void update() { if (_game.isPaused()) @@ -66,6 +71,8 @@ public void update() { updateActiveItems(); detectEndGame(); + snapCameraToPlayer(); + for (int i = 0; i < _characters.size(); i++) { Character a = _characters.get(i); if (a.isRemoved()) diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index 4e34e9c..b1c9a9f 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -60,8 +60,6 @@ public void update() { @Override public void render(Screen screen) { - calculateXOffset(); - if (_alive) chooseSprite(); else @@ -70,11 +68,6 @@ 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 */ From 9c7c88ebad47a165310e4c3a663ef17a9285dd08 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 16:58:12 +0000 Subject: [PATCH 20/28] refactor Bomber input --- src/uet/oop/bomberman/Board.java | 29 +++++++++++ .../bomberman/entities/character/Bomber.java | 48 +++++-------------- .../entities/character/Character.java | 12 ++++- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index dad56ea..286ed15 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -6,6 +6,7 @@ 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.entities.tile.item.Item; import uet.oop.bomberman.exceptions.LoadLevelException; @@ -72,6 +73,7 @@ public void update() { detectEndGame(); snapCameraToPlayer(); + processPlayerInput(); for (int i = 0; i < _characters.size(); i++) { Character a = _characters.get(i); @@ -80,6 +82,33 @@ public void update() { } } + private void processPlayerInput() { + Character player = getPlayer(); + if (!player.isAlive()) return; + + processPlayerInputMove(player); + + if (player instanceof Bomber) { + Bomber bomber = (Bomber) player; + if(_input.space) bomber.placeBomb(); + } + } + + private void processPlayerInputMove(Character player) { + 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) { + player.move(xa * Game.getBomberSpeed(), ya * Game.getBomberSpeed()); + player.setMoving(true); + } else { + player.setMoving(false); + } + } + @Override public void render(Screen screen) { if (_game.isPaused()) diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index b1c9a9f..c2b641c 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -8,7 +8,6 @@ import uet.oop.bomberman.entities.bomb.Bomb; 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; @@ -22,13 +21,16 @@ 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; + protected int bombCooldown = 0; + + public int getBombCooldown() { + return bombCooldown; + } private Board _board; @@ -36,7 +38,6 @@ public Bomber(int x, int y, IEntityManager entityManager, Board board) { super(x, y, entityManager); this._board = board; _bombs = entityManager.getBombs(); - _input = _board.getInput(); _sprite = Sprite.player_right; } @@ -48,14 +49,11 @@ public void update() { return; } - if (_timeBetweenPutBombs < -7500) _timeBetweenPutBombs = 0; - else _timeBetweenPutBombs--; + if (bombCooldown < -7500) bombCooldown = 0; + else bombCooldown--; animate(); - calculateMove(); - - detectPlaceBomb(); } @Override @@ -68,16 +66,8 @@ public void render(Screen screen) { screen.renderEntity((int) _x, (int) _y - _sprite.SIZE, this); } - /** - * 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) { + public boolean placeBomb() { + if(Game.getBombRate() > 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 @@ -85,11 +75,13 @@ private void detectPlaceBomb() { placeBomb(xt,yt); Game.addBombRate(-1); - _timeBetweenPutBombs = 30; + bombCooldown = 30; + return true; } + return false; } - protected void placeBomb(int x, int y) { + public 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, entityManager); entityManager.addBomb(b); @@ -127,20 +119,6 @@ protected void afterKill() { @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; - } } @Override diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 028432b..8a71806 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -1,6 +1,5 @@ package uet.oop.bomberman.entities.character; -import uet.oop.bomberman.Board; import uet.oop.bomberman.Game; import uet.oop.bomberman.base.IEntityManager; import uet.oop.bomberman.entities.AnimatedEntitiy; @@ -14,7 +13,16 @@ public abstract class Character extends AnimatedEntitiy { protected IEntityManager entityManager; protected int _direction = -1; protected boolean _alive = true; + public boolean isAlive() { + return _alive; + } + protected boolean _moving = false; + + public void setMoving(boolean moving) { + this._moving = moving; + } + public int _timeAfter = 40; public Character(int x, int y, IEntityManager entityManager) { @@ -34,7 +42,7 @@ public Character(int x, int y, IEntityManager entityManager) { */ protected abstract void calculateMove(); - protected abstract void move(double xa, double ya); + public abstract void move(double xa, double ya); /** * Được gọi khi đối tượng bị tiêu diệt From af1da6684793d522c8ae94fca287092ea9dd4cf8 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 17:52:29 +0000 Subject: [PATCH 21/28] SpeedItem managed by Character instead of global Game --- src/uet/oop/bomberman/Board.java | 6 +-- src/uet/oop/bomberman/Game.java | 2 +- .../bomberman/entities/character/Bomber.java | 4 +- .../entities/character/Character.java | 42 +++++++++++++++---- .../entities/character/enemy/Enemy.java | 2 +- .../bomberman/entities/tile/item/Item.java | 9 +++- .../entities/tile/item/SpeedItem.java | 2 + .../oop/bomberman/level/FileLevelLoader.java | 8 +++- 8 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 286ed15..6346501 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -102,7 +102,7 @@ private void processPlayerInputMove(Character player) { if(_input.right) xa++; if(xa != 0 || ya != 0) { - player.move(xa * Game.getBomberSpeed(), ya * Game.getBomberSpeed()); + player.move(xa * player.getSpeed(), ya * player.getSpeed()); player.setMoving(true); } else { player.setMoving(false); @@ -170,8 +170,8 @@ public void endGame() { @Override public boolean isEnemyCleared() { - return _characters.stream() - .allMatch(character -> character != getPlayer()); + return !_characters.stream() + .anyMatch(character -> character != getPlayer()); } public void drawScreen(Graphics g) { diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index f53ff52..2928cec 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -28,7 +28,7 @@ public class Game extends Canvas { 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 double BOMBERSPEED = 1.0;// toc do bomber private static int itemTime; public static final int TIME = 200; diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index c2b641c..fff1f62 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -34,8 +34,8 @@ public int getBombCooldown() { private Board _board; - public Bomber(int x, int y, IEntityManager entityManager, Board board) { - super(x, y, entityManager); + public Bomber(int x, int y, double baseSpeed, IEntityManager entityManager, Board board) { + super(x, y, baseSpeed, entityManager); this._board = board; _bombs = entityManager.getBombs(); _sprite = Sprite.player_right; diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 8a71806..4adb718 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -1,8 +1,13 @@ package uet.oop.bomberman.entities.character; +import java.util.ArrayList; +import java.util.List; + import uet.oop.bomberman.Game; import uet.oop.bomberman.base.IEntityManager; import uet.oop.bomberman.entities.AnimatedEntitiy; +import uet.oop.bomberman.entities.tile.item.Item; +import uet.oop.bomberman.entities.tile.item.SpeedItem; import uet.oop.bomberman.graphics.Screen; /** @@ -13,22 +18,18 @@ public abstract class Character extends AnimatedEntitiy { protected IEntityManager entityManager; protected int _direction = -1; protected boolean _alive = true; - public boolean isAlive() { - return _alive; - } - protected boolean _moving = false; + public int _timeAfter = 40; - public void setMoving(boolean moving) { - this._moving = moving; - } + private final double baseSpeed; - public int _timeAfter = 40; + private List activeItems = new ArrayList<>(); - public Character(int x, int y, IEntityManager entityManager) { + public Character(int x, int y, double baseSpeed, IEntityManager entityManager) { _x = x; _y = y; this.entityManager = entityManager; + this.baseSpeed = baseSpeed; } @Override @@ -74,4 +75,27 @@ public boolean isPlayer() { return entityManager.getPlayer() == this; } + public boolean isAlive() { + return _alive; + } + + public void setMoving(boolean moving) { + this._moving = moving; + } + + public void addActiveItem(Item item) { + this.activeItems.add(item); + } + + public double getSpeed() { + double speedMultiplier = 1; + for (Item item: activeItems) { + if (!item.isActive()) continue; + if (item instanceof SpeedItem) { + speedMultiplier += SpeedItem.SPEED_MULTIPLIER; + } + } + return speedMultiplier * this.baseSpeed; + } + } diff --git a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java index e205c89..56e05a1 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java @@ -31,7 +31,7 @@ public abstract class Enemy extends Character { private Board _board; public Enemy(int x, int y, Board board, Sprite dead, double speed, int points) { - super(x, y, board); + super(x, y, speed, board); this._board = board; diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index 5e9f676..b2d6ff5 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -10,6 +10,7 @@ public abstract class Item extends Tile { protected int _duration = 30 * Game.TICKS_PER_SECOND; // 30s protected boolean _active = false; + protected int _level; public Item(int x, int y, Sprite sprite) { @@ -23,10 +24,12 @@ public Item(int x, int y, Sprite sprite) { @Override public boolean collide(Entity e) { if (e instanceof Character && ((Character)e).isPlayer()) { + Character player = (Character) e; Sound.play("Item"); handleItemActive(); _active = true; Game.getBoard().addActiveItem(this); + player.addActiveItem(this); remove(); } return false; @@ -48,5 +51,9 @@ public int getDuration() { return _duration; } - public abstract String getDisplayActiveItem(); + 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 bb0bd22..afcbbe9 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -5,6 +5,8 @@ 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); } diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index 4bfe991..7531ff1 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -102,7 +102,13 @@ public void createEntities() { break; // Thêm Bomber player case 'p': - Bomber bomber = new Bomber(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board, _board); + Bomber bomber = new Bomber( + Coordinates.tileToPixel(x), + Coordinates.tileToPixel(y) + Game.TILES_SIZE, + Game.BOMBERSPEED, + _board, + _board + ); _board.addCharacter(bomber); _board.setPlayer(bomber); Screen.setOffset(0, 0); From d49cc1dc6e2e43e1beb91e2c68bd45471c66dda9 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Thu, 16 May 2024 23:17:51 +0000 Subject: [PATCH 22/28] move BombItem to Bomber instead of Game --- src/uet/oop/bomberman/Game.java | 4 +-- .../bomberman/entities/character/Bomber.java | 29 ++++++++++++++----- .../entities/character/Character.java | 5 ++++ .../entities/tile/item/BombItem.java | 4 ++- .../oop/bomberman/level/FileLevelLoader.java | 1 + 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 2928cec..737f8de 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -26,8 +26,8 @@ public class Game extends Canvas { public static final String TITLE = "BombermanGame"; public static final int TICKS_PER_SECOND = 60; - private static final int BOMBRATE = 1; - private static final int BOMBRADIUS = 1; + public static final int BOMBRATE = 1; + public static final int BOMBRADIUS = 1; public static final double BOMBERSPEED = 1.0;// toc do bomber private static int itemTime; diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index fff1f62..96a7343 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -14,6 +14,7 @@ import uet.oop.bomberman.entities.LayeredEntity; import uet.oop.bomberman.entities.bomb.Flame; import uet.oop.bomberman.entities.character.enemy.Enemy; +import uet.oop.bomberman.entities.tile.item.BombItem; import uet.oop.bomberman.entities.tile.item.Item; import uet.oop.bomberman.level.Coordinates; import uet.oop.bomberman.sound.Sound; @@ -22,10 +23,8 @@ public class Bomber extends Character { private List _bombs; 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() - */ + + private final int baseBombLimit; protected int bombCooldown = 0; public int getBombCooldown() { @@ -34,8 +33,9 @@ public int getBombCooldown() { private Board _board; - public Bomber(int x, int y, double baseSpeed, IEntityManager entityManager, Board board) { + public Bomber(int x, int y, double baseSpeed, int baseBombLimit, IEntityManager entityManager, Board board) { super(x, y, baseSpeed, entityManager); + this.baseBombLimit = baseBombLimit; this._board = board; _bombs = entityManager.getBombs(); _sprite = Sprite.player_right; @@ -66,14 +66,28 @@ public void render(Screen screen) { screen.renderEntity((int) _x, (int) _y - _sprite.SIZE, this); } + public int getBombLimit() { + int bombLimitBonus = 0; + for (Item item: getActiveItems()) { + if (!item.isActive()) continue; + if (item instanceof BombItem) { + bombLimitBonus += BombItem.BOMB_LIMIT_BONUS; + } + } + return this.baseBombLimit + bombLimitBonus; + } + + public int getBombRemainingQuota() { + return getBombLimit() - _bombs.size(); + } + public boolean placeBomb() { - if(Game.getBombRate() > 0 && bombCooldown < 0) { + 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); - Game.addBombRate(-1); bombCooldown = 30; return true; @@ -96,7 +110,6 @@ private void clearBombs() { b = bs.next(); if (b.isRemoved()) { bs.remove(); - Game.addBombRate(1); } } diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 4adb718..c2d266d 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -1,6 +1,7 @@ package uet.oop.bomberman.entities.character; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import uet.oop.bomberman.Game; @@ -83,6 +84,10 @@ public void setMoving(boolean moving) { this._moving = moving; } + public List getActiveItems() { + return Collections.unmodifiableList(activeItems); + } + public void addActiveItem(Item item) { this.activeItems.add(item); } diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java index 598202a..6bf1a5a 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -5,7 +5,9 @@ public class BombItem extends Item { - public BombItem(int x, int y, Sprite sprite) { + public static final int BOMB_LIMIT_BONUS = 1; + + public BombItem(int x, int y, Sprite sprite) { super(x, y, sprite); } diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index 7531ff1..e79c447 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -106,6 +106,7 @@ public void createEntities() { Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, Game.BOMBERSPEED, + Game.BOMBRATE, _board, _board ); From 53b74c6ca17e710c541ea9212922e25b7256617d Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Fri, 17 May 2024 06:38:27 +0000 Subject: [PATCH 23/28] move FlameItem to Bomber instead of Game --- src/uet/oop/bomberman/entities/bomb/Bomb.java | 7 ++++-- .../bomberman/entities/character/Bomber.java | 24 ++++++++++++------- .../entities/character/Character.java | 5 ++-- .../entities/tile/item/FlameItem.java | 2 ++ .../oop/bomberman/level/FileLevelLoader.java | 1 + 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/uet/oop/bomberman/entities/bomb/Bomb.java b/src/uet/oop/bomberman/entities/bomb/Bomb.java index 6e200ab..69fe8f1 100644 --- a/src/uet/oop/bomberman/entities/bomb/Bomb.java +++ b/src/uet/oop/bomberman/entities/bomb/Bomb.java @@ -19,12 +19,15 @@ public class Bomb extends AnimatedEntitiy { protected Flame[] _flames; protected boolean _exploded = false; protected boolean _allowedToPassThru = true; + + private final int bombRadius; - public Bomb(int x, int y, IEntityManager board) { + public Bomb(int x, int y, int bombRadius, IEntityManager board) { _x = x; _y = y; _board = board; _sprite = Sprite.bomb; + this.bombRadius = bombRadius; } @Override @@ -86,7 +89,7 @@ protected void explode() {//nổ // 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); + _flames[i] = new Flame((int) _x, (int) _y, i, bombRadius, _board); } Sound.play("BOM_11_M"); } diff --git a/src/uet/oop/bomberman/entities/character/Bomber.java b/src/uet/oop/bomberman/entities/character/Bomber.java index 96a7343..2d6bd58 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -15,6 +15,7 @@ import uet.oop.bomberman.entities.bomb.Flame; import uet.oop.bomberman.entities.character.enemy.Enemy; 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.level.Coordinates; import uet.oop.bomberman.sound.Sound; @@ -27,15 +28,19 @@ public class Bomber extends Character { private final int baseBombLimit; protected int bombCooldown = 0; + private final int baseBombRadius; + private int bombRadius; + public int getBombCooldown() { return bombCooldown; } private Board _board; - public Bomber(int x, int y, double baseSpeed, int baseBombLimit, IEntityManager entityManager, Board board) { + public Bomber(int x, int y, double baseSpeed, int baseBombLimit, int baseBombRadius, IEntityManager entityManager, Board board) { super(x, y, baseSpeed, entityManager); this.baseBombLimit = baseBombLimit; + this.baseBombRadius = baseBombRadius; this._board = board; _bombs = entityManager.getBombs(); _sprite = Sprite.player_right; @@ -67,13 +72,8 @@ public void render(Screen screen) { } public int getBombLimit() { - int bombLimitBonus = 0; - for (Item item: getActiveItems()) { - if (!item.isActive()) continue; - if (item instanceof BombItem) { - bombLimitBonus += BombItem.BOMB_LIMIT_BONUS; - } - } + int countActiveItem = (int) getActiveItems().filter(item -> item instanceof BombItem).count(); + int bombLimitBonus = countActiveItem * BombItem.BOMB_LIMIT_BONUS; return this.baseBombLimit + bombLimitBonus; } @@ -81,6 +81,12 @@ public int getBombRemainingQuota() { return getBombLimit() - _bombs.size(); } + public int getBombRadius() { + int countActiveItem = (int) getActiveItems().filter(item -> item instanceof FlameItem).count(); + int bombRadiusBonus = countActiveItem * FlameItem.BOMB_RADIUS_BONUS; + return this.baseBombRadius + bombRadiusBonus; + } + public boolean placeBomb() { if(getBombRemainingQuota() > 0 && bombCooldown < 0) { @@ -97,7 +103,7 @@ public boolean placeBomb() { public 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, entityManager); + Bomb b = new Bomb(x, y, getBombRadius(), entityManager); entityManager.addBomb(b); Sound.play("BOM_SET"); } diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index c2d266d..47aea17 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import uet.oop.bomberman.Game; import uet.oop.bomberman.base.IEntityManager; @@ -84,8 +85,8 @@ public void setMoving(boolean moving) { this._moving = moving; } - public List getActiveItems() { - return Collections.unmodifiableList(activeItems); + public Stream getActiveItems() { + return activeItems.stream().filter(Item::isActive); } public void addActiveItem(Item item) { diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java index 66fd498..590201b 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -5,6 +5,8 @@ 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); } diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index e79c447..c14974f 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -107,6 +107,7 @@ public void createEntities() { Coordinates.tileToPixel(y) + Game.TILES_SIZE, Game.BOMBERSPEED, Game.BOMBRATE, + Game.BOMBRADIUS, _board, _board ); From 53f10aa19471a37f69ee30c5449fc45a2c8d47d2 Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Sat, 18 May 2024 06:46:35 +0000 Subject: [PATCH 24/28] decouple bomber stats from global Game --- src/uet/oop/bomberman/Board.java | 23 ++++---- src/uet/oop/bomberman/Game.java | 57 ++----------------- .../bomberman/base/IActiveItemManager.java | 12 ++++ .../oop/bomberman/base/IEntityManager.java | 2 +- .../oop/bomberman/base/IGameInfoManager.java | 11 ++++ .../entities/character/Character.java | 2 +- .../entities/character/enemy/Kondoria.java | 2 +- .../entities/character/enemy/Minvo.java | 2 +- .../entities/tile/item/BombItem.java | 2 - .../entities/tile/item/FlameItem.java | 2 - .../bomberman/entities/tile/item/Item.java | 1 - .../entities/tile/item/SpeedItem.java | 2 - src/uet/oop/bomberman/gui/Frame.java | 6 +- src/uet/oop/bomberman/gui/InfoPanel.java | 18 +++--- 14 files changed, 55 insertions(+), 87 deletions(-) create mode 100644 src/uet/oop/bomberman/base/IActiveItemManager.java create mode 100644 src/uet/oop/bomberman/base/IGameInfoManager.java diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 6346501..5e09cfd 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -1,6 +1,7 @@ package uet.oop.bomberman; import uet.oop.bomberman.base.IEntityManager; +import uet.oop.bomberman.base.IGameInfoManager; import uet.oop.bomberman.base.IMessageManager; import uet.oop.bomberman.entities.Entity; import uet.oop.bomberman.entities.Message; @@ -20,11 +21,12 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; /** * 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, IEntityManager, IMessageManager { +public class Board implements IRender, IEntityManager, IMessageManager, IGameInfoManager { protected LevelLoader _levelLoader; protected Game _game; protected Keyboard _input; @@ -38,8 +40,9 @@ public class Board implements IRender, IEntityManager, IMessageManager { private Character player; + @Override public List getActiveItems() { - return _activeItems; + return getPlayer().getActiveItems().collect(Collectors.toList()); } private int _screenToShow = -1; // 1:endgame, 2:changelevel, 3:paused @@ -132,9 +135,6 @@ public void render(Screen screen) { } public void nextLevel() { - Game.setBombRadius(1); - Game.setBombRate(1); - Game.setBomberSpeed(1.0); loadLevel(_levelLoader.getLevel() + 1); } @@ -274,6 +274,7 @@ public Entity getEntityAt(double x, double y) { return _entities[(int) x + (int) y * _levelLoader.getWidth()]; } + @Override public void addActiveItem(Item item) { _activeItems.add(item); } @@ -374,6 +375,7 @@ protected void updateMessages() { } } + @Override public int subtractTime() { if (!_game.isPaused() && _time > 0) return --_time; @@ -381,14 +383,6 @@ public int subtractTime() { return _time; } - public int getItemTime() { - int totalTime = 0; - for (int i = 0; i < _activeItems.size(); i++) { - totalTime += _activeItems.get(i).getDuration() / Game.TICKS_PER_SECOND; - } - return totalTime; - } - public Keyboard getInput() { return _input; } @@ -409,14 +403,17 @@ public void setShow(int i) { _screenToShow = i; } + @Override public int getTime() { return _time; } + @Override public int getPoints() { return _points; } + @Override public void addPoints(int points) { this._points += points; } diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 737f8de..d5ee103 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -1,5 +1,6 @@ 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; @@ -8,9 +9,6 @@ import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; -import javax.swing.JButton; - - /** * 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, * Gọi phương thức render(), update() cho tất cả các entity @@ -29,24 +27,18 @@ public class Game extends Canvas { public static final int BOMBRATE = 1; public static final int BOMBRADIUS = 1; public static final double BOMBERSPEED = 1.0;// toc do bomber - private static int itemTime; public static final int TIME = 200; - public static final int ITEM_TIME = 20; 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 static Board _board; + private Board _board; private Screen screen; private Frame _frame; @@ -153,7 +145,7 @@ public void start() { if (System.currentTimeMillis() - timer > 1000) { _frame.setTime(_board.subtractTime()); _frame.setPoints(_board.getPoints()); - _frame.setItemTime(_board.getItemTime()); + _frame.renderItemTime(); timer += 1000; _frame.setTitle(TITLE + " | " + updates + " rate, " + frames + " fps"); updates = 0; @@ -165,40 +157,9 @@ public void start() { } } - public static int getItemTime() { - return itemTime; - } - - 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; } - public static Board getBoard() { - return _board; - } public boolean isPaused() { return _paused; } @@ -207,16 +168,8 @@ public void pause() { _paused = !_paused; } - public static void setBombRate(int bombRate) { - Game.bombRate = bombRate; - } - - public static void setBombRadius(int bombRadius) { - Game.bombRadius = bombRadius; - } - - public static void setBomberSpeed(double bomberSpeed) { - Game.bomberSpeed = bomberSpeed; + public IGameInfoManager getGameInfoManager() { + return _board; } } diff --git a/src/uet/oop/bomberman/base/IActiveItemManager.java b/src/uet/oop/bomberman/base/IActiveItemManager.java new file mode 100644 index 0000000..dc86201 --- /dev/null +++ b/src/uet/oop/bomberman/base/IActiveItemManager.java @@ -0,0 +1,12 @@ +package uet.oop.bomberman.base; + +import java.util.List; + +import uet.oop.bomberman.entities.tile.item.Item; + +public interface IActiveItemManager { + + public List getActiveItems(); + public void addActiveItem(Item item); + +} \ No newline at end of file diff --git a/src/uet/oop/bomberman/base/IEntityManager.java b/src/uet/oop/bomberman/base/IEntityManager.java index 2135078..46f23ce 100644 --- a/src/uet/oop/bomberman/base/IEntityManager.java +++ b/src/uet/oop/bomberman/base/IEntityManager.java @@ -7,7 +7,7 @@ import uet.oop.bomberman.entities.bomb.FlameSegment; import uet.oop.bomberman.entities.character.Character; -public interface IEntityManager { +public interface IEntityManager extends IActiveItemManager { public List getBombs(); diff --git a/src/uet/oop/bomberman/base/IGameInfoManager.java b/src/uet/oop/bomberman/base/IGameInfoManager.java new file mode 100644 index 0000000..ce0b57b --- /dev/null +++ b/src/uet/oop/bomberman/base/IGameInfoManager.java @@ -0,0 +1,11 @@ +package uet.oop.bomberman.base; + +public interface IGameInfoManager extends IActiveItemManager { + + public int subtractTime(); + public int getTime(); + + public int getPoints(); + public void addPoints(int points); + +} \ 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 47aea17..75191db 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -1,7 +1,6 @@ package uet.oop.bomberman.entities.character; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.stream.Stream; @@ -91,6 +90,7 @@ public Stream getActiveItems() { public void addActiveItem(Item item) { this.activeItems.add(item); + entityManager.addActiveItem(item); } public double getSpeed() { diff --git a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java index 6f2a1f9..478c97b 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Kondoria.java @@ -7,7 +7,7 @@ public class Kondoria extends Enemy { public Kondoria(int x, int y, Board board) { - super(x, y, board, Sprite.balloom_dead, Game.getBomberSpeed() / 4, 1000); + super(x, y, board, Sprite.balloom_dead, Game.BOMBERSPEED / 4, 1000); _sprite = Sprite.kondoria_right1; diff --git a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java index 5ec04b3..677f3ba 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Minvo.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Minvo.java @@ -9,7 +9,7 @@ public class Minvo extends Enemy { private Board _board; public Minvo(int x, int y, Board board) { - super(x, y, board, Sprite.minvo_dead, Game.getBomberSpeed() * 1.5, 800); + super(x, y, board, Sprite.minvo_dead, Game.BOMBERSPEED * 1.5, 800); _board = board; _sprite = Sprite.minvo_right1; diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java index 6bf1a5a..4413976 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -13,12 +13,10 @@ public BombItem(int x, int y, Sprite sprite) { @Override protected void handleItemActive() { - Game.addBombRate(1); } @Override protected void handleItemInactive() { - Game.addBombRate(-1); } @Override diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java index 590201b..8e7f17a 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -13,12 +13,10 @@ public FlameItem(int x, int y, Sprite sprite) { @Override protected void handleItemActive() { - Game.addBombRadius(1); } @Override protected void handleItemInactive() { - Game.addBombRadius(-1); } @Override diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index b2d6ff5..3f78feb 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -28,7 +28,6 @@ public boolean collide(Entity e) { Sound.play("Item"); handleItemActive(); _active = true; - Game.getBoard().addActiveItem(this); player.addActiveItem(this); remove(); } diff --git a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java index afcbbe9..9094772 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -13,12 +13,10 @@ public SpeedItem(int x, int y, Sprite sprite) { @Override protected void handleItemActive() { - Game.addBomberSpeed(0.5); } @Override protected void handleItemInactive() { - Game.addBomberSpeed(-0.5); } @Override diff --git a/src/uet/oop/bomberman/gui/Frame.java b/src/uet/oop/bomberman/gui/Frame.java index 0ccb41c..99a635b 100644 --- a/src/uet/oop/bomberman/gui/Frame.java +++ b/src/uet/oop/bomberman/gui/Frame.java @@ -20,7 +20,7 @@ public Frame() { _containerpane = new JPanel(new BorderLayout()); _gamepane = new GamePanel(this); - _infopanel = new InfoPanel(_gamepane.getGame()); + _infopanel = new InfoPanel(_gamepane.getGame().getGameInfoManager()); _containerpane.add(_infopanel, BorderLayout.PAGE_START); _containerpane.add(_gamepane, BorderLayout.PAGE_END); @@ -46,8 +46,8 @@ public void setPoints(int points) { _infopanel.setPoints(points); } - public void setItemTime(int itemTime) { - _infopanel.setItemTime(itemTime); + public void renderItemTime() { + _infopanel.renderItemTime(); } } diff --git a/src/uet/oop/bomberman/gui/InfoPanel.java b/src/uet/oop/bomberman/gui/InfoPanel.java index bd9e183..b6eb091 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -1,11 +1,10 @@ package uet.oop.bomberman.gui; -import uet.oop.bomberman.Board; 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.awt.event.*; import java.util.List; /** @@ -15,14 +14,17 @@ public class InfoPanel extends JPanel { private JLabel timeLabel; private JLabel pointsLabel; private JLabel itemTimeLabel; - private Game game; - public InfoPanel(Game game) { + + private final IGameInfoManager gameInfoManager; + + public InfoPanel(IGameInfoManager gameInfoManager) { + this.gameInfoManager = gameInfoManager; setLayout(new GridLayout()); - timeLabel = new JLabel("Time: " + game.getBoard().getTime()); + timeLabel = new JLabel("Time: " + gameInfoManager.getTime()); timeLabel.setForeground(Color.white); timeLabel.setHorizontalAlignment(JLabel.CENTER); - pointsLabel = new JLabel("Points: " + game.getBoard().getPoints()); + pointsLabel = new JLabel("Points: " + gameInfoManager.getPoints()); pointsLabel.setForeground(Color.white); pointsLabel.setHorizontalAlignment(JLabel.CENTER); @@ -46,9 +48,9 @@ public void setPoints(int t) { pointsLabel.setText("Score: " + t); } - public void setItemTime(int t) { + public void renderItemTime() { String label = ""; - List items = game.getBoard().getActiveItems(); + List items = gameInfoManager.getActiveItems(); for (int i = 0; i < items.size(); i++) { Item item = items.get(i); if ((item.getDuration()) == 0) { From 0320c2d117a6fb0f7743a8741cb29f34710722c2 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Sun, 19 May 2024 20:09:42 +0700 Subject: [PATCH 25/28] update selected level --- src/uet/oop/bomberman/Board.java | 3 ++- src/uet/oop/bomberman/Game.java | 2 +- src/uet/oop/bomberman/screen/SelectLevelScreen.java | 7 ++++++- src/uet/oop/bomberman/utils/Global.java | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 5e09cfd..7e133cd 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -16,6 +16,7 @@ import uet.oop.bomberman.input.Keyboard; import uet.oop.bomberman.level.FileLevelLoader; import uet.oop.bomberman.level.LevelLoader; +import uet.oop.bomberman.utils.Global; import java.awt.*; import java.util.ArrayList; @@ -55,7 +56,7 @@ public Board(Game game, Keyboard input, Screen screen) { _input = input; _screen = screen; - loadLevel(1); // start in level 1 + loadLevel(Global.gameLevel); // start in level 1 } private void snapCameraToPlayer() { diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 15c16a3..4cefe1b 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -93,7 +93,7 @@ private void renderScreen(Graphics g) { private void initScreen() { Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN; - this.selectLevelScreen = new SelectLevelScreen(_input); + this.selectLevelScreen = new SelectLevelScreen(_input, _board); } private void update() { diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java index 33fb2a1..8813815 100644 --- a/src/uet/oop/bomberman/screen/SelectLevelScreen.java +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -1,5 +1,6 @@ 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; @@ -16,9 +17,11 @@ public class SelectLevelScreen extends GameScreen { ArrayList levels = new ArrayList(); int selectorIndex = 0; private Keyboard _input; + private Board _board; - public SelectLevelScreen(Keyboard input) { + public SelectLevelScreen(Keyboard input, Board board) { _input = input; + _board = board; levels.add(EGameLevel.EASY.getStringLevel()); levels.add(EGameLevel.MEDIUM.getStringLevel()); @@ -36,6 +39,8 @@ public void onKeyPressed(EGameControl gameControl) { break; case ENTER: Global.currentScreen = EScreenName.GAME_PLAY_SCREEN; + Global.gameLevel = selectorIndex + 1; + _board.loadLevel(Global.gameLevel); break; } diff --git a/src/uet/oop/bomberman/utils/Global.java b/src/uet/oop/bomberman/utils/Global.java index 623e0a6..9c3329c 100644 --- a/src/uet/oop/bomberman/utils/Global.java +++ b/src/uet/oop/bomberman/utils/Global.java @@ -5,4 +5,7 @@ public class Global { public static int screenHeight; public static EScreenName currentScreen; + + // GAME PLAY + public static int gameLevel = 1; } From 35a14321c246596a180ae3c45b91cd66273c1058 Mon Sep 17 00:00:00 2001 From: Hang Le Thi Bich <21522041@gm.uit.edu.vn> Date: Mon, 20 May 2024 01:14:07 +0700 Subject: [PATCH 26/28] select game mode screen --- src/uet/oop/bomberman/Game.java | 30 +++-- src/uet/oop/bomberman/gui/GameScreen.java | 1 + .../screen/SelectGameModeScreen.java | 124 ++++++++++++++++++ .../bomberman/screen/SelectLevelScreen.java | 19 ++- src/uet/oop/bomberman/utils/EGameMode.java | 16 +++ src/uet/oop/bomberman/utils/EScreenName.java | 1 + src/uet/oop/bomberman/utils/Global.java | 4 +- 7 files changed, 181 insertions(+), 14 deletions(-) create mode 100644 src/uet/oop/bomberman/screen/SelectGameModeScreen.java create mode 100644 src/uet/oop/bomberman/utils/EGameMode.java diff --git a/src/uet/oop/bomberman/Game.java b/src/uet/oop/bomberman/Game.java index 4cefe1b..3d050c0 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -4,6 +4,7 @@ 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.SelectLevelScreen; import uet.oop.bomberman.utils.EScreenName; import uet.oop.bomberman.utils.Global; @@ -56,6 +57,7 @@ public class Game extends Canvas { // game screens private SelectLevelScreen selectLevelScreen; + private SelectGameModeScreen selectGameModeScreen; public Game(Frame frame) { _frame = frame; @@ -91,26 +93,30 @@ private void renderScreen(Graphics g) { } private void initScreen() { - Global.currentScreen = EScreenName.SELECT_LEVEL_SCREEN; + Global.currentScreen = EScreenName.SELECT_GAME_MODE; - this.selectLevelScreen = new SelectLevelScreen(_input, _board); + this.selectGameModeScreen = new SelectGameModeScreen(); + this.selectLevelScreen = new SelectLevelScreen(_board); } private void update() { _input.update(); switch (Global.currentScreen) { case GAME_PLAY_SCREEN: - _board.update(); - if (_input.pause) { // Kiểm tra nếu phím "p" được nhấn - _board.setShow(3); // Hiển thị màn hình tạm dừng - _paused = true; // Đặt trạng thái game là tạm dừng - return; - } + _board.update(); + if (_input.pause) { // Kiểm tra nếu phím "p" được nhấn + _board.setShow(3); // Hiển thị màn hình tạm dừng + _paused = true; // Đặt trạng thái game là tạm dừng + return; + } break; case SELECT_LEVEL_SCREEN: // TODO: call select level screen update selectLevelScreen.update(); break; + case SELECT_GAME_MODE: + selectGameModeScreen.update(); + break; } } @@ -155,8 +161,16 @@ private void showScreen() { break; case SELECT_LEVEL_SCREEN: // TODO: render select level screen + if (Global.currentScreen != Global.previousScreen) { + selectLevelScreen.setInput(_input); + } selectLevelScreen.drawScreen(g); break; + case SELECT_GAME_MODE: + if (Global.currentScreen != Global.previousScreen) { + selectGameModeScreen.setInput(_input); + } + selectGameModeScreen.drawScreen(g); } g.dispose(); diff --git a/src/uet/oop/bomberman/gui/GameScreen.java b/src/uet/oop/bomberman/gui/GameScreen.java index 93a79c1..a473496 100644 --- a/src/uet/oop/bomberman/gui/GameScreen.java +++ b/src/uet/oop/bomberman/gui/GameScreen.java @@ -5,4 +5,5 @@ 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/screen/SelectGameModeScreen.java b/src/uet/oop/bomberman/screen/SelectGameModeScreen.java new file mode 100644 index 0000000..fce9572 --- /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 = null; + } +} diff --git a/src/uet/oop/bomberman/screen/SelectLevelScreen.java b/src/uet/oop/bomberman/screen/SelectLevelScreen.java index 8813815..716c860 100644 --- a/src/uet/oop/bomberman/screen/SelectLevelScreen.java +++ b/src/uet/oop/bomberman/screen/SelectLevelScreen.java @@ -10,24 +10,27 @@ import uet.oop.bomberman.utils.Global; import java.awt.*; -import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.Optional; public class SelectLevelScreen extends GameScreen { ArrayList levels = new ArrayList(); int selectorIndex = 0; - private Keyboard _input; + private Optional _input; private Board _board; - public SelectLevelScreen(Keyboard input, Board board) { - _input = input; + 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.keyboardInputCallback = java.util.Optional.of(new Keyboard.KeyboardInputCallback() { + _input.get().keyboardInputCallback = java.util.Optional.of(new Keyboard.KeyboardInputCallback() { @Override public void onKeyPressed(EGameControl gameControl) { switch (gameControl) { @@ -41,6 +44,7 @@ public void onKeyPressed(EGameControl gameControl) { Global.currentScreen = EScreenName.GAME_PLAY_SCREEN; Global.gameLevel = selectorIndex + 1; _board.loadLevel(Global.gameLevel); + onDestroy(); break; } @@ -116,4 +120,9 @@ private void drawSelector(Graphics g) { @Override public void update() {} + + @Override + public void onDestroy() { + this._input = null; + } } diff --git a/src/uet/oop/bomberman/utils/EGameMode.java b/src/uet/oop/bomberman/utils/EGameMode.java new file mode 100644 index 0000000..9efd976 --- /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 Players"); + + 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 index 515a6e8..be8c6be 100644 --- a/src/uet/oop/bomberman/utils/EScreenName.java +++ b/src/uet/oop/bomberman/utils/EScreenName.java @@ -1,6 +1,7 @@ package uet.oop.bomberman.utils; public enum EScreenName { + SELECT_GAME_MODE, SELECT_LEVEL_SCREEN, GAME_PLAY_SCREEN, } diff --git a/src/uet/oop/bomberman/utils/Global.java b/src/uet/oop/bomberman/utils/Global.java index 9c3329c..ff4616e 100644 --- a/src/uet/oop/bomberman/utils/Global.java +++ b/src/uet/oop/bomberman/utils/Global.java @@ -4,8 +4,10 @@ public class Global { public static int screenWidth; public static int screenHeight; - public static EScreenName currentScreen; + 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; } From ef3a9884a382465105f66eee078712ffef3210be Mon Sep 17 00:00:00 2001 From: phuonnngminh Date: Mon, 20 May 2024 15:59:23 +0000 Subject: [PATCH 27/28] refactor collision logic: split into collide and canBePassedThroughBy --- res/levels/Level3.txt | 2 +- src/uet/oop/bomberman/Board.java | 18 ++++ .../oop/bomberman/base/IEntityManager.java | 1 + src/uet/oop/bomberman/entities/Entity.java | 16 +++- .../oop/bomberman/entities/LayeredEntity.java | 23 +++-- src/uet/oop/bomberman/entities/Message.java | 5 ++ src/uet/oop/bomberman/entities/bomb/Bomb.java | 34 ++++---- .../oop/bomberman/entities/bomb/Flame.java | 33 ++++++-- .../bomberman/entities/bomb/FlameSegment.java | 8 +- .../bomberman/entities/character/Bomber.java | 64 +++----------- .../entities/character/Character.java | 83 +++++++++++++++++-- .../entities/character/enemy/Enemy.java | 73 ++++------------ .../oop/bomberman/entities/tile/Grass.java | 7 +- .../entities/tile/NonDestroyableTile.java | 16 ++++ .../oop/bomberman/entities/tile/Portal.java | 24 ++++-- src/uet/oop/bomberman/entities/tile/Tile.java | 8 ++ src/uet/oop/bomberman/entities/tile/Wall.java | 2 +- .../tile/destroyable/DestroyableTile.java | 10 +++ .../bomberman/entities/tile/item/Item.java | 10 ++- src/uet/oop/bomberman/sound/Sound.java | 4 +- 20 files changed, 282 insertions(+), 159 deletions(-) create mode 100644 src/uet/oop/bomberman/entities/tile/NonDestroyableTile.java diff --git a/res/levels/Level3.txt b/res/levels/Level3.txt index 40a9bf4..5a6ca2f 100644 --- a/res/levels/Level3.txt +++ b/res/levels/Level3.txt @@ -11,4 +11,4 @@ # **** *2 # # # # # # # # # # #*# # # # #*# # ** ** * 5 # -############################### \ No newline at end of file +############################### diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 5e09cfd..71415c4 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -16,6 +16,7 @@ import uet.oop.bomberman.input.Keyboard; import uet.oop.bomberman.level.FileLevelLoader; import uet.oop.bomberman.level.LevelLoader; +import uet.oop.bomberman.sound.Sound; import java.awt.*; import java.util.ArrayList; @@ -431,4 +432,21 @@ public void setPlayer(Character character) { this.player = character; } + @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(); + addPoints(points); + Message msg = new Message("+" + points, messageX, messageY, 2, Color.white, 14); + addMessage(msg); + Sound.play("AA126_11"); + } + } + } diff --git a/src/uet/oop/bomberman/base/IEntityManager.java b/src/uet/oop/bomberman/base/IEntityManager.java index 46f23ce..de47e76 100644 --- a/src/uet/oop/bomberman/base/IEntityManager.java +++ b/src/uet/oop/bomberman/base/IEntityManager.java @@ -25,5 +25,6 @@ public interface IEntityManager extends IActiveItemManager { public Character getPlayer(); public boolean isEnemyCleared(); + public void handleOnDeath(Character character, Character killer); } \ 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..6e9317a 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; 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 4bfab68..74cc779 100644 --- a/src/uet/oop/bomberman/entities/Message.java +++ b/src/uet/oop/bomberman/entities/Message.java @@ -65,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 69fe8f1..8863a87 100644 --- a/src/uet/oop/bomberman/entities/bomb/Bomb.java +++ b/src/uet/oop/bomberman/entities/bomb/Bomb.java @@ -83,9 +83,9 @@ protected void explode() {//nổ _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(); - } + if(x != null){ + x.handleOnDeath(); + } // TODO: tạo các Flame _flames = new Flame[4]; for (int i = 0; i < _flames.length; i++) { @@ -93,7 +93,7 @@ protected void explode() {//nổ } Sound.play("BOM_11_M"); } - public void time_explode() { + public void handleChainExplode() { _timeToExplode = 0; } public FlameSegment flameAt(int x, int y) { @@ -110,11 +110,20 @@ public FlameSegment flameAt(int x, int y) { @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()); + // 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; @@ -122,11 +131,8 @@ public boolean collide(Entity e) { 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 f009521..4e2ac84 100644 --- a/src/uet/oop/bomberman/entities/bomb/Flame.java +++ b/src/uet/oop/bomberman/entities/bomb/Flame.java @@ -3,11 +3,13 @@ import uet.oop.bomberman.base.IEntityManager; import uet.oop.bomberman.entities.Entity; import uet.oop.bomberman.entities.character.Character; +import uet.oop.bomberman.entities.tile.Tile; +import uet.oop.bomberman.entities.tile.destroyable.DestroyableTile; import uet.oop.bomberman.graphics.Screen; public class Flame extends Entity { - protected IEntityManager _board; + protected IEntityManager entityManager; protected int _direction; private int _radius; protected int xOrigin, yOrigin; @@ -20,14 +22,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, IEntityManager 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(); } @@ -59,6 +61,10 @@ private void createFlameSegments() { case 3: x--; break; } _flameSegments[i] = new FlameSegment(x, y, _direction, last); + Entity entity = entityManager.getEntity(x, y, null); + if (entity!=null) { + entity.collide(this); + } } } @@ -77,17 +83,26 @@ private int calculatePermitedDistance() { if(_direction == 2) y++; if(_direction == 3) x--; - Entity a = _board.getEntity(x, y, null); + Entity a = entityManager.getEntity(x, y, null); 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; } 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,8 +125,14 @@ public void render(Screen screen) { @Override public boolean collide(Entity e) { if (e instanceof Character) { - ((Character)e).kill(); + ((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 4adf084..cbbb2a5 100644 --- a/src/uet/oop/bomberman/entities/bomb/FlameSegment.java +++ b/src/uet/oop/bomberman/entities/bomb/FlameSegment.java @@ -68,9 +68,13 @@ public void update() {} @Override public boolean collide(Entity e) { - if (e instanceof Character) ((Character)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 2d6bd58..af2572a 100644 --- a/src/uet/oop/bomberman/entities/character/Bomber.java +++ b/src/uet/oop/bomberman/entities/character/Bomber.java @@ -29,7 +29,6 @@ public class Bomber extends Character { protected int bombCooldown = 0; private final int baseBombRadius; - private int bombRadius; public int getBombCooldown() { return bombCooldown; @@ -47,16 +46,10 @@ public Bomber(int x, int y, double baseSpeed, int baseBombLimit, int baseBombRad } @Override - public void update() { - clearBombs(); - if (!_alive) { - afterKill(); - return; - } - + public void handleUpdate() { + clearExpiredBombs(); if (bombCooldown < -7500) bombCooldown = 0; else bombCooldown--; - animate(); } @@ -108,7 +101,7 @@ public void placeBomb(int x, int y) { Sound.play("BOM_SET"); } - private void clearBombs() { + private void clearExpiredBombs() { Iterator bs = _bombs.iterator(); Bomb b; @@ -122,18 +115,8 @@ private void clearBombs() { } @Override - public void kill() { - if (!_alive) return; - _alive = false; - Sound.play("endgame3"); - } - - @Override - protected void afterKill() { - if (_timeAfter > 0) --_timeAfter; - else { - _board.endGame(); - } + protected void handleAfterDeath() { + _board.endGame(); } @Override @@ -149,7 +132,7 @@ public boolean canMove(double x, double y) { Entity a = entityManager.getEntity(xt, yt, this); - if(!a.collide(this)) + if(!a.canBePassedThroughBy(this)) return false; } @@ -157,37 +140,9 @@ public boolean canMove(double x, double y) { //return false; } - @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; - } - } - @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(); - return false; - } - if(e instanceof Enemy){ - this.kill(); - return true; - } - if( e instanceof LayeredEntity) return(e.collide(this)); + if (!super.collide(e)) return false; return true; } @@ -226,4 +181,9 @@ private void chooseSprite() { break; } } + + @Override + public int getPoints() { + return 0; + } } diff --git a/src/uet/oop/bomberman/entities/character/Character.java b/src/uet/oop/bomberman/entities/character/Character.java index 75191db..a630f79 100644 --- a/src/uet/oop/bomberman/entities/character/Character.java +++ b/src/uet/oop/bomberman/entities/character/Character.java @@ -7,20 +7,24 @@ 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.tile.item.Item; import uet.oop.bomberman.entities.tile.item.SpeedItem; 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 IEntityManager entityManager; + protected final IEntityManager entityManager; protected int _direction = -1; protected boolean _alive = true; protected boolean _moving = false; - public int _timeAfter = 40; + protected int timerDeathAnimation = 40; private final double baseSpeed; @@ -34,7 +38,19 @@ public Character(int x, int y, double baseSpeed, IEntityManager entityManager) { } @Override - public abstract void update(); + public final void update() { + if (!_alive) { + if (timerDeathAnimation > 0) { + timerDeathAnimation -= 1; + } else { + handleAfterDeath(); + } + return; + } + handleUpdate(); + }; + + protected abstract void handleUpdate(); @Override public abstract void render(Screen screen); @@ -44,17 +60,44 @@ public Character(int x, int y, double baseSpeed, IEntityManager entityManager) { */ protected abstract void calculateMove(); - public abstract void move(double xa, double ya); + /** Check if can be moved with vector (xa, ya). + * @param xa + * @param ya + */ + public void move(double xa, double ya) { + if(xa > 0) _direction = 1; + if(xa < 0) _direction = 3; + if(ya > 0) _direction = 2; + if(ya < 0) _direction = 0; + + if(canMove(0, ya)) _y += ya; + if(canMove(xa, 0)) _x += xa; + + Entity collidingEntity = entityManager.getEntity( + 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.handleOnDeath(this, null); + } /** * Xử lý hiệu ứng bị tiêu diệt */ - protected abstract void afterKill(); + protected abstract void handleAfterDeath(); /** * Kiểm tra xem đối tượng có di chuyển tới vị trí đã tính toán hay không @@ -104,4 +147,32 @@ public double getSpeed() { return speedMultiplier * this.baseSpeed; } + public abstract int getPoints(); + + @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/enemy/Enemy.java b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java index 56e05a1..adb5562 100644 --- a/src/uet/oop/bomberman/entities/character/enemy/Enemy.java +++ b/src/uet/oop/bomberman/entities/character/enemy/Enemy.java @@ -1,19 +1,14 @@ 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.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; @@ -28,13 +23,9 @@ public abstract class Enemy extends Character { protected int _finalAnimation = 30; protected Sprite _deadSprite; - private Board _board; - - public Enemy(int x, int y, Board board, Sprite dead, double speed, int points) { - super(x, y, speed, board); + public Enemy(int x, int y, IEntityManager entityManager, Sprite dead, double speed, int points) { + super(x, y, speed, entityManager); - this._board = board; - _points = points; _speed = speed; @@ -42,21 +33,14 @@ 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; + timerDeathAnimation = 20; _deadSprite = dead; } @Override - public void update() { + public void handleUpdate() { animate(); - - if(!_alive) { - afterKill(); - return; - } - - if(_alive) - calculateMove(); + calculateMove(); } @Override @@ -65,7 +49,7 @@ public void render(Screen screen) { if(_alive) chooseSprite(); else { - if(_timeAfter > 0) { + if(timerDeathAnimation > 0) { _sprite = _deadSprite; _animate = 0; } else { @@ -104,13 +88,6 @@ public void calculateMove() { } } - @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 @@ -127,44 +104,24 @@ public boolean canMove(double x, double y) { Entity a = entityManager.getEntity(xx, yy, this); //entity of the position we want to go - return a.collide(this); + return a.canBePassedThroughBy(this); } @Override public boolean collide(Entity e) { - if(e instanceof Flame){ - this.kill(); - return false; - } - if(e instanceof Character && ((Character)e).isPlayer()){ - ((Character) e).kill(); - return false; - } + if (!super.collide(e)) return false; return true; } @Override - public void kill() { - if(!_alive) return; - _alive = false; - - _board.addPoints(_points); - - Message msg = new Message("+" + _points, getXMessage(), getYMessage(), 2, Color.white, 14); - _board.addMessage(msg); - Sound.play("AA126_11"); + protected void handleAfterDeath() { + remove(); } - + protected abstract void chooseSprite(); + @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/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 0b42570..6a5d13e 100644 --- a/src/uet/oop/bomberman/entities/tile/Portal.java +++ b/src/uet/oop/bomberman/entities/tile/Portal.java @@ -6,7 +6,7 @@ import uet.oop.bomberman.graphics.Sprite; import uet.oop.bomberman.sound.Sound; -public class Portal extends Tile { +public class Portal extends NonDestroyableTile { protected Board _board; public Portal(int x, int y, Board board, Sprite sprite) { @@ -21,18 +21,28 @@ public boolean collide(Entity e) {// xu li khi 2 entity va cham // TODO: xử lý khi Bomber đi vào 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.isEnemyCleared()) return false; - if (e.getXTile() == getX() && e.getYTile() == getY()) { - if (_board.isEnemyCleared()) { - _board.nextLevel(); - Sound.play("CRYST_UP"); - } + if (other.getXTile() == getX() && other.getYTile() == getY()) { + 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/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index 3f78feb..a028765 100644 --- a/src/uet/oop/bomberman/entities/tile/item/Item.java +++ b/src/uet/oop/bomberman/entities/tile/item/Item.java @@ -3,11 +3,11 @@ import uet.oop.bomberman.Game; import uet.oop.bomberman.entities.Entity; import uet.oop.bomberman.entities.character.Character; -import uet.oop.bomberman.entities.tile.Tile; +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 { +public abstract class Item extends NonDestroyableTile { protected int _duration = 30 * Game.TICKS_PER_SECOND; // 30s protected boolean _active = false; @@ -23,6 +23,7 @@ public Item(int x, int y, Sprite sprite) { @Override public boolean collide(Entity e) { + if (isRemoved()) return false; if (e instanceof Character && ((Character)e).isPlayer()) { Character player = (Character) e; Sound.play("Item"); @@ -34,6 +35,11 @@ public boolean collide(Entity e) { return false; } + @Override + public boolean canBePassedThroughBy(Entity e) { + return (e instanceof Character && ((Character)e).isPlayer()); + } + @Override public void update() { if (!_active) diff --git a/src/uet/oop/bomberman/sound/Sound.java b/src/uet/oop/bomberman/sound/Sound.java index efafdc1..1993f37 100644 --- a/src/uet/oop/bomberman/sound/Sound.java +++ b/src/uet/oop/bomberman/sound/Sound.java @@ -18,7 +18,7 @@ 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(); @@ -34,7 +34,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(); From 1585ee6f5601a95da4786076d8543a0ec2c480f1 Mon Sep 17 00:00:00 2001 From: Huy010302 <111289985+Huy010302@users.noreply.github.com> Date: Wed, 22 May 2024 23:21:24 +0700 Subject: [PATCH 28/28] fix move player 2 --- res/levels/Level1.txt | 2 +- res/levels/Level2.txt | 2 +- src/uet/oop/bomberman/Board.java | 73 ++++++++++++--- src/uet/oop/bomberman/entities/bomb/Bomb.java | 89 ++++++++++--------- src/uet/oop/bomberman/input/Keyboard.java | 28 ++++-- .../oop/bomberman/level/FileLevelLoader.java | 51 +++++++---- 6 files changed, 165 insertions(+), 80 deletions(-) diff --git a/res/levels/Level1.txt b/res/levels/Level1.txt index 6f00589..254063f 100644 --- a/res/levels/Level1.txt +++ b/res/levels/Level1.txt @@ -10,7 +10,7 @@ # # # # #*# # # #*#*# # # # # # #* ** * * # # #*# # # # # # #*# # # # # # # -# * * * # +#a * * * # ############################### diff --git a/res/levels/Level2.txt b/res/levels/Level2.txt index f76a558..b01dcf7 100644 --- a/res/levels/Level2.txt +++ b/res/levels/Level2.txt @@ -10,7 +10,7 @@ # # # # #*# # # # # # #*# #*# # # **** *1 # # # # # # # # # # #*# # # # #*# -# ** * * 3 # +#a ** * * 3 # ############################### diff --git a/src/uet/oop/bomberman/Board.java b/src/uet/oop/bomberman/Board.java index 08fcfd9..2cb6fd1 100644 --- a/src/uet/oop/bomberman/Board.java +++ b/src/uet/oop/bomberman/Board.java @@ -41,6 +41,7 @@ public class Board implements IRender, IEntityManager, IMessageManager, IGameInf private List _activeItems = new ArrayList<>(); private Character player; + private Character player2; @Override public List getActiveItems() { @@ -61,9 +62,9 @@ public Board(Game game, Keyboard input, Screen screen) { } private void snapCameraToPlayer() { - int xScroll = Screen.calculateXOffset(this, getPlayer()); - Screen.setOffset(xScroll, 0); - } + int xScroll = Screen.calculateXOffset(this, getPlayer()); + Screen.setOffset(xScroll, 0); + } @Override public void update() { @@ -79,6 +80,7 @@ public void update() { snapCameraToPlayer(); processPlayerInput(); + processPlayer2Input(); for (int i = 0; i < _characters.size(); i++) { Character a = _characters.get(i); @@ -89,24 +91,44 @@ public void update() { private void processPlayerInput() { Character player = getPlayer(); - if (!player.isAlive()) return; + if (!player.isAlive()) + return; processPlayerInputMove(player); if (player instanceof Bomber) { Bomber bomber = (Bomber) player; - if(_input.space) bomber.placeBomb(); + if (_input.player1_space) + bomber.placeBomb(); + } + } + + private void processPlayer2Input() { + Character player2 = getPlayer2(); + if (!player2.isAlive()) + return; + + processPlayer2InputMove(player2); + + if (player2 instanceof Bomber) { + Bomber bomber2 = (Bomber) player2; + if (_input.player2_space) + bomber2.placeBomb(); } } private void processPlayerInputMove(Character player) { 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) { + if (_input.player1_up) + ya--; + if (_input.player1_down) + ya++; + if (_input.player1_left) + xa--; + if (_input.player1_right) + xa++; + + if (xa != 0 || ya != 0) { player.move(xa * player.getSpeed(), ya * player.getSpeed()); player.setMoving(true); } else { @@ -114,6 +136,25 @@ private void processPlayerInputMove(Character player) { } } + private void processPlayer2InputMove(Character player2) { + int xa = 0, ya = 0; + if (_input.player2_up) + ya--; + if (_input.player2_down) + ya++; + if (_input.player2_left) + xa--; + if (_input.player2_right) + xa++; + + if (xa != 0 || ya != 0) { + player2.move(xa * player2.getSpeed(), ya * player2.getSpeed()); + player2.setMoving(true); + } else { + player2.setMoving(false); + } + } + @Override public void render(Screen screen) { if (_game.isPaused()) @@ -173,7 +214,7 @@ public void endGame() { @Override public boolean isEnemyCleared() { return !_characters.stream() - .anyMatch(character -> character != getPlayer()); + .anyMatch(character -> character != getPlayer()); } public void drawScreen(Graphics g) { @@ -235,6 +276,10 @@ public Character getPlayer() { return this.player; } + public Character getPlayer2() { + return this.player2; + } + @Override public Character getCharacterAtExcluding(int x, int y, Character a) { Iterator itr = _characters.iterator(); @@ -433,6 +478,10 @@ public void setPlayer(Character character) { this.player = character; } + public void setPlayer2(Character character2) { + this.player2 = character2; + } + @Override public void handleOnDeath(Character character, Character killer) { if (character.isPlayer()) { diff --git a/src/uet/oop/bomberman/entities/bomb/Bomb.java b/src/uet/oop/bomberman/entities/bomb/Bomb.java index 8863a87..b2da0a2 100644 --- a/src/uet/oop/bomberman/entities/bomb/Bomb.java +++ b/src/uet/oop/bomberman/entities/bomb/Bomb.java @@ -10,18 +10,19 @@ 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 IEntityManager _board; protected Flame[] _flames; protected boolean _exploded = false; protected boolean _allowedToPassThru = true; private final int bombRadius; - + public Bomb(int x, int y, int bombRadius, IEntityManager board) { _x = x; _y = y; @@ -29,89 +30,94 @@ public Bomb(int x, int y, int bombRadius, IEntityManager 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, Game.TICKS_PER_SECOND); - - int xt = (int)_x << 4; - int yt = (int)_y << 4; - - screen.renderEntity(xt, yt , this); + + 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){ + Character x = _board.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, bombRadius, _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 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) { // Xử lý va chạm với Flame của Bomb khác: chain explosion - if(e instanceof Flame) { + if (e instanceof Flame) { handleChainExplode(); return true; } @@ -120,15 +126,16 @@ public boolean collide(Entity e) { @Override public boolean canBePassedThroughBy(Entity other) { - // Xử lý khi Bomber đi ra sau khi vừa đặt bom (_allowedToPassThru) - if(other instanceof Bomber) { + // 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 + + 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; } diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index f1828aa..ac42490 100644 --- a/src/uet/oop/bomberman/input/Keyboard.java +++ b/src/uet/oop/bomberman/input/Keyboard.java @@ -14,17 +14,32 @@ public class Keyboard implements KeyListener { public interface KeyboardInputCallback { void onKeyPressed(EGameControl gameControl); } - - private boolean[] keys = new boolean[120]; //120 is enough to this game - public boolean up, down, left, right, space,pause,resume; + + private boolean[] keys = new boolean[65536]; + public boolean up, down, left, right, space, pause, resume; + public boolean player1_up, player2_up, player1_down, player2_down, player1_left, player2_left, player1_right, + player2_right, player1_space, player2_space; public Optional keyboardInputCallback; - + 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]; + + player1_up = keys[KeyEvent.VK_UP]; + player1_down = keys[KeyEvent.VK_DOWN]; + player1_left = keys[KeyEvent.VK_LEFT]; + player1_right = keys[KeyEvent.VK_RIGHT]; + player1_space = keys[KeyEvent.VK_SPACE]; + + player2_up = keys[KeyEvent.VK_W]; + player2_down = keys[KeyEvent.VK_S]; + player2_left = keys[KeyEvent.VK_A]; + player2_right = keys[KeyEvent.VK_D]; + player2_space = keys[KeyEvent.VK_X]; + pause = keys[KeyEvent.VK_ESCAPE]; resume = keys[KeyEvent.VK_ENTER]; } @@ -58,7 +73,8 @@ private EGameControl keyToGameControl(int keyCode) { } @Override - public void keyTyped(KeyEvent e) {} + public void keyTyped(KeyEvent e) { + } @Override public void keyPressed(KeyEvent e) { @@ -73,7 +89,7 @@ public void keyPressed(KeyEvent e) { @Override public void keyReleased(KeyEvent e) { keys[e.getKeyCode()] = false; - + } } diff --git a/src/uet/oop/bomberman/level/FileLevelLoader.java b/src/uet/oop/bomberman/level/FileLevelLoader.java index c14974f..da2285c 100644 --- a/src/uet/oop/bomberman/level/FileLevelLoader.java +++ b/src/uet/oop/bomberman/level/FileLevelLoader.java @@ -40,13 +40,13 @@ public void loadLevel(int level) { // 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 + FileReader fr = new FileReader("res/levels/Level" + level + ".txt");// doc tep luu map BufferedReader br = new BufferedReader(fr); String line = br.readLine(); while (!line.equals("")) { list.add(line); line = br.readLine(); - //doc file txt luu vao list + // doc file txt luu vao list } } catch (Exception e) { e.printStackTrace(); @@ -61,7 +61,7 @@ public void loadLevel(int level) { _map[i][j] = list.get(i + 1).charAt(j); } } - //gan cac phan tu cho mang + // gan cac phan tu cho mang } @Override @@ -96,44 +96,57 @@ public void createEntities() { _board.addEntity(x + y * _width, new LayeredEntity(x, y, new Grass(x, y, Sprite.grass), - new Brick(x, y, Sprite.brick) - ) - ); + new Brick(x, y, Sprite.brick))); break; // Thêm Bomber player case 'p': Bomber bomber = new Bomber( - Coordinates.tileToPixel(x), - Coordinates.tileToPixel(y) + Game.TILES_SIZE, - Game.BOMBERSPEED, - Game.BOMBRATE, - Game.BOMBRADIUS, - _board, - _board - ); + Coordinates.tileToPixel(x), + Coordinates.tileToPixel(y) + Game.TILES_SIZE, + Game.BOMBERSPEED, + Game.BOMBRATE, + Game.BOMBRADIUS, + _board, + _board); _board.addCharacter(bomber); _board.setPlayer(bomber); Screen.setOffset(0, 0); _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass)); break; - + case 'a': + Bomber bomber2 = new Bomber( + Coordinates.tileToPixel(x), + Coordinates.tileToPixel(y) + Game.TILES_SIZE, + Game.BOMBERSPEED, + Game.BOMBRATE, + Game.BOMBRADIUS, + _board, + _board); + _board.addCharacter(bomber2); + _board.setPlayer2(bomber2); + Screen.setOffset(0, 0); + _board.addEntity(x + y * _width, new Grass(x, y, Sprite.grass)); + break; // Thêm balloon case '1': - _board.addCharacter(new Balloon(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board)); + _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)); break; // Thêm oneal case '2': - _board.addCharacter(new Oneal(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board)); + _board.addCharacter(new Oneal(Coordinates.tileToPixel(x), + Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board)); _board.addEntity(pos, new Grass(x, y, Sprite.grass)); break; // Thêm doll case '3': - _board.addCharacter(new Doll(Coordinates.tileToPixel(x), Coordinates.tileToPixel(y) + Game.TILES_SIZE, _board)); + _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)); break; // Thêm oneal - // Thêm BomItem + // Thêm BomItem case 'b': LayeredEntity layer = new LayeredEntity(x, y, new Grass(x, y, Sprite.grass),