diff --git a/core/app/GameController.java b/core/app/GameController.java index e4f22ec33fa450540bd805d719a36533f1f6c6aa..eb7218f704d9c195fe65d2a100d024c42d7edc98 100644 --- a/core/app/GameController.java +++ b/core/app/GameController.java @@ -1,6 +1,8 @@ package app; import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import exceptions.GameRunningException; @@ -14,14 +16,16 @@ import mapobjs.movobjs.Player; import view.View; import view.ViewElement; -public class GameController { +public class GameController implements PropertyChangeListener{ private View view; private ArrayList<IElement>[][] map; + @SuppressWarnings("unchecked") public GameController(View view, int width, int height) { this.view = view; - map = InitController.map; + map = new ArrayList[InitController.map.length][InitController.map[0].length]; + Model.getInstance().addPropertyChangeListener(this); } public void startGameProcess() throws GameRunningException @@ -220,56 +224,32 @@ public class GameController { private void move(Player player) { player.step(); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void turn(Player player, Direction dir) { player.setDirection(dir); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void shoot(Player player, PortalColor color) { player.fire(color); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void boxDown(Player player) { player.putBoxDown(); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void boxUp(Player player) { player.getBoxUp(); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void moveReplicator() { Model.getInstance().getReplicator().setDirection(Direction.getRandomDir()); Model.getInstance().getReplicator().step(); - updateGameControllerMap(); - ArrayList<ViewElement>[][] viewMap = uploadToView(); - - view.setMap(viewMap); } private void endProcess() @@ -278,6 +258,32 @@ public class GameController { InitController.startJaffaZPMs += Model.getInstance().getJaffa().getZpmCount(); } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if(evt.getPropertyName().equals("error")) // update the whole map as before + { + updateGameControllerMap(); + ArrayList<ViewElement>[][] viewMap = uploadToView(); + view.setMap(viewMap); + + return; + } + + // update only the changed field + int coord = (int)evt.getNewValue(); + int xCoord = coord / map[0].length; + int yCoord = coord % map[0].length; + Field changedField = (Field)evt.getOldValue(); + ArrayList<ViewElement> fieldView = new ArrayList<>(); + + for(int i = 0; i < changedField.getElementNum(); i++) + { + fieldView.add(Controller.getViewOf(changedField.getElement(i))); + } + + view.setElement(yCoord, xCoord, fieldView); + } + @SuppressWarnings("unchecked") private void updateGameControllerMap() { @@ -328,5 +334,5 @@ public class GameController { } return mapView; - } + } } diff --git a/core/app/InitController.java b/core/app/InitController.java index 5be97e95520821016d46fc0df99106598aaede7f..a5fa007fab80297d3194ed3d369fb1f76cecefe7 100644 --- a/core/app/InitController.java +++ b/core/app/InitController.java @@ -514,7 +514,7 @@ public class InitController { if(map[x][y].get(i) instanceof Portal) { Portal tmp = (Portal)map[x][y].get(i); - if(tmp.side() == convertToDir(params.get(4))) + if(tmp.getSide() == convertToDir(params.get(4))) { return false; } @@ -556,11 +556,11 @@ public class InitController { tmpNew.setDirection(convertToDir(params.get(4))); if(tmpPair != null) { - tmpPair.setOtherSide(tmpNew); - tmpNew.setOtherSide(tmpPair); + tmpNew.setOtherSide(tmpPair, false); } map[x][y].add(tmpNew); - ((Wall)map[x][y].get(hasWall)).meet(new Bullet(null, convertToColor(params.get(3)), convertToInverse(convertToDir(params.get(4))))); + ((Wall)map[x][y].get(hasWall)).meet( + new Bullet(null, convertToColor(params.get(3)), Direction.convertToInverse(convertToDir(params.get(4))))); } } } @@ -948,17 +948,4 @@ public class InitController { default: throw new InvalidParameterFormatException(); } } - - // TODO: belerakni Directionbe - private static Direction convertToInverse(Direction dir) - { - switch(dir) - { - case UP: return Direction.DOWN; - case DOWN: return Direction.UP; - case RIGHT: return Direction.LEFT; - case LEFT: return Direction.RIGHT; - default: return null; - } - } } \ No newline at end of file diff --git a/core/game/Direction.java b/core/game/Direction.java index 24a3b4765e0a421b7e0f144cef029dae61728be7..286cb155a73aa8938d626b5838815706c77a450d 100644 --- a/core/game/Direction.java +++ b/core/game/Direction.java @@ -23,6 +23,18 @@ public enum Direction { default: return UP; } } + + public static Direction convertToInverse(Direction dir) + { + switch(dir) + { + case UP: return Direction.DOWN; + case DOWN: return Direction.UP; + case RIGHT: return Direction.LEFT; + case LEFT: return Direction.RIGHT; + default: return null; + } + } @Override public String toString() diff --git a/core/game/Model.java b/core/game/Model.java index 6bc7b33ef445fcec858e5c3d29863d3e0ae57540..2f1df3320353acb8480a66beb00f207c148aa90c 100644 --- a/core/game/Model.java +++ b/core/game/Model.java @@ -1,5 +1,8 @@ package game; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Random; @@ -10,8 +13,10 @@ import mapobjs.defobjs.ZPM; import mapobjs.movobjs.Player; import mapobjs.movobjs.Replicator; -public class Model +public class Model implements PropertyChangeListener { + private final PropertyChangeSupport propSupp = new PropertyChangeSupport(this); + private ArrayList<Field> map = new ArrayList<Field>(); private Player colonel; private Player jaffa; @@ -19,7 +24,6 @@ public class Model private Door specDoor; private int specOpen = 1; private Replicator replicator; - //private Gate mainGate; private boolean isMapFinished = false; public void setSpecDoor(Door specDoor) { @@ -37,7 +41,14 @@ public class Model } } return instance; - + } + + public void addPropertyChangeListener(PropertyChangeListener listener) + { + if(listener != null) + { + propSupp.addPropertyChangeListener(listener); + } } public void setColonel(Player colonel) @@ -53,6 +64,7 @@ public class Model public void addMapElement(Field field) { + field.addProperyChangeListener(this); map.add(field); } @@ -136,6 +148,21 @@ public class Model } return true; } + + public boolean openWormhole(Portal portal) + { + int i = 0; + while(i<map.size()) + { + if(map.get(i).openWormhole(portal)) + { + return true; + } + i++; + } + + return false; + } public void setSpecOpenNum(int num) { @@ -158,10 +185,6 @@ public class Model return replicator; } - /*public void setMainGate(Gate mainGate) { - this.mainGate = mainGate; - }*/ - public int getSpecOpen() { return this.specOpen; @@ -180,4 +203,25 @@ public class Model { return this.isMapFinished; } + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + int place = findField((Field)evt.getNewValue()); + if(place < 0 || place >= map.size()) + { + //propSupp.firePropertyChange("error", null, null); + System.err.println("changed field not found"); + } + else + { + propSupp.firePropertyChange("change", evt.getNewValue(), place); + } + } + + private int findField(Field field) + { + return map.indexOf(field); + + } } \ No newline at end of file diff --git a/core/mapobjs/defobjs/Door.java b/core/mapobjs/defobjs/Door.java index 863df7f1073ec140dbbcd0522a743007d4e903ee..8093101cf45e145eb3fae4c572a9cea52f34d834 100644 --- a/core/mapobjs/defobjs/Door.java +++ b/core/mapobjs/defobjs/Door.java @@ -24,7 +24,7 @@ public class Door extends DefaultElement implements IElement{ return true; } -} + } @Override public boolean meet(Replicator replicator) { @@ -38,6 +38,7 @@ public class Door extends DefaultElement implements IElement{ } } + @Override public boolean meet(Player colonel) { if(isOpen == false) @@ -50,9 +51,16 @@ public class Door extends DefaultElement implements IElement{ } } + @Override + public boolean leave(Player player) + { + return true; + } + public void setOpen(boolean isOpen) { this.isOpen=isOpen; + this.getField().iChangedMyState(); } } diff --git a/core/mapobjs/defobjs/Field.java b/core/mapobjs/defobjs/Field.java index 7460db20afab94de1234f1d8ab708af2890493fb..71f83dbde18920ce210f70c15bf2150c4ae228b0 100644 --- a/core/mapobjs/defobjs/Field.java +++ b/core/mapobjs/defobjs/Field.java @@ -1,5 +1,7 @@ package mapobjs.defobjs; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.ArrayList; import exceptions.DamagedException; @@ -9,12 +11,21 @@ import mapobjs.movobjs.Player; import mapobjs.movobjs.Replicator; public class Field implements IElement { - + private final PropertyChangeSupport propSupp = new PropertyChangeSupport(this); + private ArrayList<DefaultElement> toRemove = new ArrayList<>(); - private ArrayList<DefaultElement> elements = new ArrayList<DefaultElement>(); + private ArrayList<DefaultElement> toInsert = new ArrayList<>(); + private ArrayList<DefaultElement> elements = new ArrayList<>(); public Field[] neighbours = new Field[4]; - public Field() { + public Field() { } + + public void addProperyChangeListener(PropertyChangeListener listener) + { + if(listener != null) + { + propSupp.addPropertyChangeListener(listener); + } } public boolean addElement (DefaultElement elem){ @@ -42,7 +53,8 @@ public class Field implements IElement { } } - public Field getNeighbour(Direction dir){ + public Field getNeighbour(Direction dir) + { switch (dir) { case UP: return neighbours[0]; @@ -55,8 +67,8 @@ public class Field implements IElement { default: return null; } - } + @Override public boolean meet(Player colonel) { boolean isValid = true; @@ -74,22 +86,14 @@ public class Field implements IElement { } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } if(isValid) { - this.elements.add(colonel); + addToInsert(colonel); } + insertInsertables(); + removeRemovables(); + return isValid; } @@ -102,17 +106,9 @@ public class Field implements IElement { } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } + + insertInsertables(); + removeRemovables(); /* * No need to add bullet to the list of elements, * because it moves through the field in atomic time. @@ -143,18 +139,10 @@ public class Field implements IElement { return true; } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } - this.elements.add(box); + addToInsert(box); + + insertInsertables(); + removeRemovables(); return true; } @@ -166,24 +154,14 @@ public class Field implements IElement { isValid = false; } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } if(isValid) { - this.elements.remove(colonel); - return true; + addToRemove(colonel); } - else - return false; + + removeRemovables(); + + return isValid; } @Override @@ -195,26 +173,14 @@ public class Field implements IElement { tmp = box; } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } if(tmp != null) { - this.elements.remove(tmp); - return tmp; - } - else - { - return null; + addToRemove(tmp); } + + removeRemovables(); + + return tmp; } public boolean leave(Portal portal) { @@ -225,23 +191,14 @@ public class Field implements IElement { break; } } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) - { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } - } - toRemove.clear(); - } if(tmp != null) { - this.elements.remove(tmp); - return true; + addToRemove(tmp); } - return false; + + removeRemovables(); + + return tmp!=null ? true : false; // if tmp != null then return true, other cases return false } @@ -249,7 +206,10 @@ public class Field implements IElement { public void damaged() {} public boolean leave(Replicator replicator) { - this.elements.remove(replicator); + addToRemove(replicator); + + removeRemovables(); + return true; } @@ -264,25 +224,17 @@ public class Field implements IElement { } if(isValid) { - this.elements.add(replicator); + addToInsert(replicator); - if(toRemove.size() == 1) // TODO: bűn ronda, és hibához vezethet - { - toRemove.add(replicator); - } - } - if(!toRemove.isEmpty()) - { - for(DefaultElement toRemElement : toRemove) + if(toRemove.size() == 2) // TODO: bűn ronda, és hibához vezethet { - if(elements.contains(toRemElement)) - { - elements.remove(toRemElement); - } + addToRemove(replicator); } - toRemove.clear(); } + insertInsertables(); + removeRemovables(); + return isValid; } @@ -308,8 +260,86 @@ public class Field implements IElement { toRemove.add(element); } + public void addToInsert(DefaultElement element) + { + toInsert.add(element); + } + + private void insertInsertables() + { + if(!toInsert.isEmpty()) + { + boolean anyChanged = false; + for(DefaultElement toInsElement : toInsert) + { + if(!elements.contains(toInsElement)) + { + elements.add(toInsElement); + anyChanged = true; + } + } + toInsert.clear(); + + if(anyChanged) + { + propSupp.firePropertyChange("insert", null, this); + } + } + } + + private void removeRemovables() + { + if(!toRemove.isEmpty()) + { + boolean anyChanged = false; + for(DefaultElement toRemElement : toRemove) + { + if(elements.contains(toRemElement)) + { + elements.remove(toRemElement); + anyChanged = true; + } + } + toRemove.clear(); + + if(anyChanged) + { + propSupp.firePropertyChange("remove", null, this); + } + } + } + + public void iChangedMyState() + { + propSupp.firePropertyChange("playerChanged", null, this); + } + public boolean hasElementOn() { return !elements.isEmpty(); } + + public int getElementNum() + { + return elements.size(); + } + + public DefaultElement getElement(int index) + { + return elements.get(index); + } + + public boolean openWormhole(Portal portal) + { + for (DefaultElement defElement : elements) { + if(defElement instanceof Portal) // TODO: más megoldás + { + Portal ownPortal = (Portal)defElement; + + return ownPortal.setOtherSide(portal, false); // return true if success, false if portals are not from same player + } + } + + return false; + } } diff --git a/core/mapobjs/defobjs/Portal.java b/core/mapobjs/defobjs/Portal.java index 75e2f6d5b3216e8ba5eb5254fa2a56d7d99f65b7..c9677f8e1aea028b62942ed95088182368134e48 100644 --- a/core/mapobjs/defobjs/Portal.java +++ b/core/mapobjs/defobjs/Portal.java @@ -2,7 +2,6 @@ package mapobjs.defobjs; import game.Direction; import game.PortalColor; -import mapobjs.movobjs.Player; import mapobjs.movobjs.Replicator; /** @@ -14,25 +13,37 @@ import mapobjs.movobjs.Replicator; * @author Temesvári Fanni */ public class Portal extends DefaultElement { - /* - * Color is not used. - * Is this attribute useful? - * TODO getter - */ private PortalColor color; private Direction side; private Portal otherSide = null; - public void setOtherSide(Portal otherSide) { - this.otherSide = otherSide; + public void setOtherSide() + { + this.getField().getNeighbour(side).setNeighbour(Direction.convertToInverse(side), this.getField()); + otherSide.getField().getNeighbour(otherSide.side).setNeighbour(Direction.convertToInverse(otherSide.side), otherSide.getField()); } - - // TODO is it possible to create a portal without color? - public Portal(Field ownField){ - super(ownField); + + public boolean setOtherSide(Portal otherSide, boolean isSecondTurn) { + if(isSecondTurn) + { + this.otherSide = otherSide; + this.getField().getNeighbour(side).setNeighbour(Direction.convertToInverse(side), this.getOtherSideField()); + otherSide.getField().getNeighbour(otherSide.side) + .setNeighbour(Direction.convertToInverse(otherSide.side), otherSide.getOtherSideField()); + return true; + } + + if(PortalColor.convertToInverse(otherSide.getColor()).equals(this.color)) + { + this.otherSide = otherSide; + otherSide.setOtherSide(this, true); + + return true; + } + + return false; } - // TODO is it useful to create a portal without direction? public Portal(Field ownField, PortalColor color) { super(ownField); this.color = color; @@ -44,16 +55,6 @@ public class Portal extends DefaultElement { this.side = side; } - @Override - public boolean meet(Player colonel){ - if(otherSide == null) { - colonel.damaged(); - }else{ - return this.otherSide.getField().getNeighbour(otherSide.side).meet(colonel); - } - return true; - } - @Override public boolean meet(Replicator replicator){ if(otherSide == null) { @@ -67,12 +68,9 @@ public class Portal extends DefaultElement { @Override public void damaged(){ this.getField().addToRemove(this); - //this.getField().deleteElement(this); - //this.setField(null); } - - // TODO I assume getSide() instead of side() - public Direction side() + + public Direction getSide() { return side; } @@ -81,8 +79,6 @@ public class Portal extends DefaultElement { public boolean leave(Portal portal) { if(portal.equals(this)) { this.getField().addToRemove(this); - //this.getField().deleteElement(this); - //this.setField(null); return true; }else { return false; @@ -108,4 +104,14 @@ public class Portal extends DefaultElement { return false; } + + public PortalColor getColor() + { + return this.color; + } + + public Field getOtherSideField() + { + return otherSide.getField().getNeighbour(otherSide.side); + } } diff --git a/core/mapobjs/defobjs/Ravine.java b/core/mapobjs/defobjs/Ravine.java index d452034353dcc6da085d7809a830e1530870870f..df263a4ff30143e15a590ec646f3ad12db7da9c4 100644 --- a/core/mapobjs/defobjs/Ravine.java +++ b/core/mapobjs/defobjs/Ravine.java @@ -35,7 +35,6 @@ public class Ravine extends DefaultElement { public boolean meet(Replicator replicator) { replicator.damaged(); this.getField().addToRemove(this); - //this.getField().deleteElement(this); return true; } } \ No newline at end of file diff --git a/core/mapobjs/defobjs/Wall.java b/core/mapobjs/defobjs/Wall.java index fc55030e957524ebabf6708931d7c18685b31b9f..06206fdefe75fd93b9cf6369c472941c1df0a59a 100644 --- a/core/mapobjs/defobjs/Wall.java +++ b/core/mapobjs/defobjs/Wall.java @@ -2,6 +2,7 @@ package mapobjs.defobjs; import game.Direction; +import game.Model; import mapobjs.movobjs.*; public class Wall extends DefaultElement{ @@ -55,7 +56,8 @@ public class Wall extends DefaultElement{ portals[3] = portal; break; } - this.getField().addElement(portal); + this.getField().addToInsert(portal); + Model.getInstance().openWormhole(portal); } return false; } @@ -72,9 +74,15 @@ public class Wall extends DefaultElement{ return false; for (Portal myportal : this.portals) { if(portal.equals(myportal)) { + closeWormhole(myportal); myportal = null; } } return false; } + + private void closeWormhole(Portal portal) + { + portal.setOtherSide(); + } } diff --git a/core/mapobjs/movobjs/Player.java b/core/mapobjs/movobjs/Player.java index ed2841b55a8abecaaa0b4afc41eb9d32389490c4..d38ecc0c0b352927644bac1bc3a1f05a2b136cea 100644 --- a/core/mapobjs/movobjs/Player.java +++ b/core/mapobjs/movobjs/Player.java @@ -70,7 +70,7 @@ public class Player extends DefaultElement implements IMovable { { if(originField.meet(this)) { - this.getField().leave(this); + this.getField().addToRemove(this); this.setField(originField); } } @@ -78,16 +78,17 @@ public class Player extends DefaultElement implements IMovable { @Override public boolean step() { - Field nextField = this.getField().getNeighbour(dir); - boolean success = nextField.meet(this); - if(success) + Field nextField = this.getField().getNeighbour(dir); + boolean success = nextField.meet(this); + if(success) { - this.getField().leave(this); - this.setField(nextField); - return true; + this.getField().leave(this); + this.setField(nextField); + return true; } - return false; + return false; } + public boolean getBoxUp() { // cannot take more boxes @@ -96,29 +97,41 @@ public class Player extends DefaultElement implements IMovable { Field newField = this.getField().getNeighbour(dir); Box box = newField.leave(); if(box == null) + { return false; + } + box.setField(null); this.box = box; + this.getField().iChangedMyState(); + return true; } + public boolean putBoxDown() { if(this.box == null) return false; Field newField = this.getField().getNeighbour(dir); boolean success = newField.meet(this.box); - if(success) { - this.box = null; - return true; - } + if(success) + { + this.box = null; + this.getField().iChangedMyState(); + + return true; + } + return false; } + public boolean fire(PortalColor color) { Model.getInstance().portalClose(new Portal(null, color)); Bullet bullet = new Bullet(this.getField(), color, this.dir); return bullet.step(); } + public Direction getDirection() { return this.dir; @@ -145,6 +158,7 @@ public class Player extends DefaultElement implements IMovable { public void setDirection(Direction dir) { this.dir = dir; + this.getField().iChangedMyState(); } public void setPlayerLives(int playerLives) { diff --git a/core/mapobjs/movobjs/Replicator.java b/core/mapobjs/movobjs/Replicator.java index f53329dfcb72674b8e3694f9513989b5455ed9af..f86c0bbc0986ae6a923e6187ad5fad9c31aa53de 100644 --- a/core/mapobjs/movobjs/Replicator.java +++ b/core/mapobjs/movobjs/Replicator.java @@ -1,6 +1,7 @@ package mapobjs.movobjs; import game.Direction; +import game.Model; import mapobjs.defobjs.Box; import mapobjs.defobjs.DefaultElement; import mapobjs.defobjs.Field; @@ -16,16 +17,17 @@ public class Replicator extends DefaultElement implements IMovable { public boolean meet(Player colonel) { return true; } + @Override - public boolean meet(Box box) { - return false; + public boolean leave(Player player) + { + return true; } @Override public void damaged() { - this.getField().addToRemove(this); - //this.getField().deleteElement(this); - //this.setField(null); + this.getField().getNeighbour(dir).addToRemove(this); + Model.getInstance().setReplicator(null); } @Override @@ -54,6 +56,7 @@ public class Replicator extends DefaultElement implements IMovable { public void setDirection(Direction dir) { this.dir = dir; + this.getField().iChangedMyState(); } } diff --git a/core/maps/testmap.txt b/core/maps/testmap.txt index 149c4e94cd3714c614523c463e27ce5c827f3103..f434365752b7f4c2e4cd1d156c61d0382551e2f9 100644 --- a/core/maps/testmap.txt +++ b/core/maps/testmap.txt @@ -2,8 +2,17 @@ create map 10 10 create colonel 1 1 create gate 2 3 create ra 0 0 -create re 5 5 create jaffa 1 0 create door 2 2 3 3 create box 3 2 -create zpm 2 0 \ No newline at end of file +create zpm 2 0 +create wall 5 0 +create wall 5 1 +create wall 5 2 +create wall 5 3 +create wall 5 4 +create wall 5 5 +create wall 0 5 +create wall 1 5 +create wall 2 5 +create wall 3 5 \ No newline at end of file