diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..38f5d98 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM openjdk:8-slim-buster + +COPY . . +RUN apt update && \ + apt install -y vim git && \ + apt install -y libxext6 libxrender1 libxtst6 libfreetype6 libfontconfig1 && \ + echo "Done!" + +# Dev environment: +# docker run -d --name bom-ai -e DISPLAY="host.docker.internal:0" -v /tmp/.X11-unix:/tmp/.X11-unix -v $HOME:/root openjdk:8-slim-buster sleep 999999999 \ No newline at end of file diff --git a/res/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/Board.java b/src/uet/oop/bomberman/Board.java index 4130228..0bf31f2 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; @@ -26,69 +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 int _screenToShow = -1; //1:endgame, 2:changelevel, 3:paused - + private List _activeItems = new ArrayList<>(); + + 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; @@ -97,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: @@ -142,166 +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; + Iterator itr = _activeItems.iterator(); + + 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); @@ -309,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() { @@ -346,7 +384,7 @@ public int getPoints() { public void addPoints(int points) { this._points += points; } - + public int getWidth() { return _levelLoader.getWidth(); } @@ -354,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 53e5c53..aaa12d1 100644 --- a/src/uet/oop/bomberman/Game.java +++ b/src/uet/oop/bomberman/Game.java @@ -3,102 +3,102 @@ import uet.oop.bomberman.graphics.Screen; import uet.oop.bomberman.gui.Frame; import uet.oop.bomberman.input.Keyboard; - import java.awt.*; import java.awt.image.BufferStrategy; 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 */ 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 Board _board; + 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(); @@ -108,75 +108,86 @@ 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; - 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(); } - - + + if (_input.resume) { + _paused = false; + _board.setShow(-1); + } 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; } @@ -184,27 +195,27 @@ public static void addBombRate(int i) { public void resetScreenDelay() { _screenDelay = SCREENDELAY; } - - public Board getBoard() { + public static Board getBoard() { return _board; } - public boolean isPaused() { return _paused; } - + public void pause() { - _paused = true; + _paused = !_paused; } + 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/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; + // } + // } +} diff --git a/src/uet/oop/bomberman/entities/tile/item/BombItem.java b/src/uet/oop/bomberman/entities/tile/item/BombItem.java index cfdceba..cf9b5fc 100644 --- a/src/uet/oop/bomberman/entities/tile/item/BombItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/BombItem.java @@ -13,15 +13,18 @@ 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); + } + + @Override + public String getDisplayActiveItem() { + return "Bomb:"; } } diff --git a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java index e251754..6507dcf 100644 --- a/src/uet/oop/bomberman/entities/tile/item/FlameItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/FlameItem.java @@ -13,14 +13,17 @@ 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); + } + + @Override + public String getDisplayActiveItem() { + return "Flame:"; } } diff --git a/src/uet/oop/bomberman/entities/tile/item/Item.java b/src/uet/oop/bomberman/entities/tile/item/Item.java index b3a1b8f..b67655a 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,46 @@ 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; + } + } + + 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 7bc50b7..e8ebfd8 100644 --- a/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java +++ b/src/uet/oop/bomberman/entities/tile/item/SpeedItem.java @@ -13,14 +13,17 @@ 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); + } + + @Override + public String getDisplayActiveItem() { + return "Speed:"; } } diff --git a/src/uet/oop/bomberman/graphics/Screen.java b/src/uet/oop/bomberman/graphics/Screen.java index 2494ea2..9aa0058 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; @@ -63,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/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..9958ca3 100644 --- a/src/uet/oop/bomberman/gui/InfoPanel.java +++ b/src/uet/oop/bomberman/gui/InfoPanel.java @@ -1,36 +1,43 @@ package uet.oop.bomberman.gui; - +import uet.oop.bomberman.Board; import uet.oop.bomberman.Game; +import uet.oop.bomberman.entities.tile.item.Item; import javax.swing.*; import java.awt.*; +import java.awt.event.*; +import java.util.List; /** * Swing Panel hiển thị thông tin thời gian, điểm mà người chơi đạt được */ public class InfoPanel extends JPanel { - private JLabel timeLabel; private JLabel pointsLabel; - + private JLabel itemTimeLabel; + private Game game; public InfoPanel(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 +45,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); + } + } diff --git a/src/uet/oop/bomberman/input/Keyboard.java b/src/uet/oop/bomberman/input/Keyboard.java index bb8daad..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; + public boolean up, down, left, right, space,pause,resume; public void update() { up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W]; @@ -17,6 +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_ESCAPE]; + resume = keys[KeyEvent.VK_ENTER]; } @Override 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("")) {