diff --git a/Cahier_d'initialisation.pdf b/Cahier_d'initialisation.pdf new file mode 100644 index 0000000..0cae8d5 Binary files /dev/null and b/Cahier_d'initialisation.pdf differ diff --git a/src/main/java/fr/sae/terraria/Terraria.java b/src/main/java/fr/sae/terraria/Terraria.java index bbdc080..2de8c97 100644 --- a/src/main/java/fr/sae/terraria/Terraria.java +++ b/src/main/java/fr/sae/terraria/Terraria.java @@ -8,27 +8,29 @@ import java.io.File; import java.io.IOException; - import java.net.URL; public class Terraria extends Application { - // TODO: effet de profondeur dans la terre - private String titleWindow = "Terraria-Like"; - private int widthWindow = 1280; - private int heightWindow = 720; + // Constants + public static final String srcPath = "src/main/resources/fr/sae/terraria/"; + public static final double TARGET_FPS = .017; + public static final int DISPLAY_RENDERING_WIDTH = 465; + public static final int DISPLAY_RENDERING_HEIGHT = 256; + + private final String titleWindow = "Terraria-Like"; + private final int widthWindow = 1280; + private final int heightWindow = 720; public static void main(String[] args) { launch(); } public void start(Stage stage) throws IOException { - /* TODO: Commencer par le menu */ - URL pathFxml = Terraria.class.getResource("vue/game.fxml"); if (pathFxml == null) - pathFxml = new File("src/main/resources/fr/sae/terraria/vue/game.fxml").toURI().toURL(); + pathFxml = new File(srcPath + "vue/game.fxml").toURI().toURL(); FXMLLoader fxmlLoader = new FXMLLoader(pathFxml); Controller ctrl = new Controller(stage); diff --git a/src/main/java/fr/sae/terraria/controller/Controller.java b/src/main/java/fr/sae/terraria/controller/Controller.java index e75cc2b..5bbc3ae 100644 --- a/src/main/java/fr/sae/terraria/controller/Controller.java +++ b/src/main/java/fr/sae/terraria/controller/Controller.java @@ -1,162 +1,190 @@ package fr.sae.terraria.controller; +import fr.sae.terraria.Terraria; +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.TileMaps; import fr.sae.terraria.modele.blocks.Dirt; import fr.sae.terraria.modele.blocks.Stone; +import fr.sae.terraria.modele.entities.Player; import fr.sae.terraria.modele.entities.entity.Entity; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; +import fr.sae.terraria.vue.View; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.geometry.Rectangle2D; +import javafx.scene.Node; import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.ScrollEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.stage.Stage; -import javafx.fxml.FXML; -import javafx.fxml.Initializable; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; - -import java.util.ResourceBundle; import java.net.URL; - -import fr.sae.terraria.Terraria; -import fr.sae.terraria.modele.Environment; -import fr.sae.terraria.modele.TileMaps; +import java.util.Objects; +import java.util.ResourceBundle; public class Controller implements Initializable { + @FXML + private HBox title; @FXML private BorderPane root; @FXML - private HBox title; + private Pane displayHUD; @FXML - private Pane display; - - private IntegerProperty tileWidth = new SimpleIntegerProperty(); - private IntegerProperty tileHeight = new SimpleIntegerProperty(); + private Pane displayTiledMap; + private Stage primaryStage; private Environment environment; - private TileMaps tiles; - private int ticks = 0; + // TODO: plutot mettre un DoubleProperty a c'est deux variables + private double scaleMultiplicatorWidth = .0; // Permet de scale correctement une image selon la largeur de l'écran + private double scaleMultiplicatorHeight = .0; // Permet de scale correctement une image selon la hauteur de l'écran public Controller(Stage primaryStage) { - environment = new Environment(); - tiles = new TileMaps(); + this.primaryStage = primaryStage; - primaryStage.addEventFilter(KeyEvent.KEY_PRESSED, key -> { - environment.getKeysInput().put(key.getCode(), true); - key.consume(); - }); - - primaryStage.addEventFilter(KeyEvent.KEY_RELEASED, key -> { - environment.getKeysInput().put(key.getCode(), false); - key.consume(); - }); - - primaryStage.heightProperty().addListener((obs, oldV, newV) -> tileHeight.setValue((int) (TileMaps.tileDefaultSize*((newV.intValue()-title.getPrefHeight()) / 256)))); - primaryStage.widthProperty().addListener((obs, oldV, newV) -> tileWidth.setValue((int) (TileMaps.tileDefaultSize*((newV.intValue() / 465))))); + primaryStage.widthProperty().addListener((obs, oldV, newV) -> scaleMultiplicatorWidth = (newV.intValue() / Terraria.DISPLAY_RENDERING_WIDTH)); + primaryStage.heightProperty().addListener((obs, oldV, newV) -> scaleMultiplicatorHeight = ((newV.intValue()-title.getPrefHeight()) / Terraria.DISPLAY_RENDERING_HEIGHT)); } - @Override public void initialize(URL location, ResourceBundle resources) { - tiles.load("src/main/resources/fr/sae/terraria/maps/map_0.json"); - - tileHeight.setValue((int) (TileMaps.tileDefaultSize*((root.getPrefHeight()-title.getPrefHeight()) / 256))); - tileWidth.setValue((int) (TileMaps.tileDefaultSize*((root.getPrefWidth() / 465)))); - - InputStream floorTopPath = Terraria.class.getResourceAsStream("tiles/floor-top.png"); - if (floorTopPath == null) try { - floorTopPath = new FileInputStream("src/main/resources/fr/sae/terraria/tiles/floor-top.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - Image floorTopImg = new Image(floorTopPath, tileWidth.get(), tileHeight.get(), false, false); - - InputStream floorLeftPath = Terraria.class.getResourceAsStream("tiles/floor-left.png"); - if (floorLeftPath == null) try { - floorLeftPath = new FileInputStream("src/main/resources/fr/sae/terraria/tiles/floor-left.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - Image floorLeftImg = new Image(floorLeftPath, tileWidth.get(), tileHeight.get(), false, false); - - InputStream floorRightPath = Terraria.class.getResourceAsStream("tiles/floor-right.png"); - if (floorRightPath == null) try { - floorRightPath = new FileInputStream("src/main/resources/fr/sae/terraria/tiles/floor-right.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - Image floorRightImg = new Image(floorRightPath, tileWidth.get(), tileHeight.get(), false, false); - - InputStream stonePath = Terraria.class.getResourceAsStream("tiles/rock-fill.png"); - if (stonePath == null) try { - stonePath = new FileInputStream("src/main/resources/fr/sae/terraria/tiles/rock-fill.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - Image stoneImg = new Image(stonePath, tileWidth.get(), tileHeight.get(), false, false); - - InputStream dirtPath = Terraria.class.getResourceAsStream("tiles/dirt-top.png"); - if (dirtPath == null) try { - dirtPath = new FileInputStream("src/main/resources/fr/sae/terraria/tiles/dirt-top.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - Image dirtImg = new Image(dirtPath, tileWidth.get(), tileHeight.get(), false, false); - - InputStream playerPath = Terraria.class.getResourceAsStream("sprites/player/player_idle.png"); - if (playerPath == null) try { - playerPath = new FileInputStream("src/main/resources/fr/sae/terraria/sprites/player/player_idle.png"); - } catch (FileNotFoundException e) { throw new RuntimeException(e); } - - for (int y = 0; y < tiles.getHeight() ; y++) - for (int x = 0 ; x < tiles.getWidth() ; x++) - switch (tiles.getTile(y,x)) - { - case TileMaps.STONE: - Stone stoneSprite = new Stone(x*tileWidth.get(), y*tileHeight.get()); - stoneSprite.setRect((int) stoneImg.getWidth(), (int) stoneImg.getHeight()); - display.getChildren().add(createImageView(stoneSprite, stoneImg)); - environment.getEntities().add(stoneSprite); - break; - case TileMaps.DIRT: - Dirt dirtSprite = new Dirt(x*tileWidth.get(), y*tileHeight.get()); - dirtSprite.setRect((int) dirtImg.getWidth(), (int) dirtImg.getHeight()); - display.getChildren().add(createImageView(dirtSprite, dirtImg)); - environment.getEntities().add(dirtSprite); - break; - case TileMaps.FLOOR_TOP: - Dirt floorTopSprite = new Dirt(x*tileWidth.get(), y*tileHeight.get()); - floorTopSprite.setRect((int) floorTopImg.getWidth(), (int) floorTopImg.getHeight()); - display.getChildren().add(createImageView(floorTopSprite, floorTopImg)); - environment.getEntities().add(floorTopSprite); - break; - case TileMaps.FLOOR_LEFT: - Dirt floorLeftSprite = new Dirt(x*tileWidth.get(), y*tileHeight.get()); - floorLeftSprite.setRect((int) floorLeftImg.getWidth(), (int) floorLeftImg.getHeight()); - display.getChildren().add(createImageView(floorLeftSprite, floorLeftImg)); - environment.getEntities().add(floorLeftSprite); - break; - case TileMaps.FLOOR_RIGHT: - Dirt floorRightSprite = new Dirt(x*tileWidth.get(), y*tileHeight.get()); - floorRightSprite.setRect((int) floorRightImg.getWidth(), (int) floorRightImg.getHeight()); - display.getChildren().add(createImageView(floorRightSprite, floorRightImg)); - environment.getEntities().add(floorRightSprite); - break; - } + scaleMultiplicatorWidth = (root.getPrefWidth() / Terraria.DISPLAY_RENDERING_WIDTH); + scaleMultiplicatorHeight = ((root.getPrefHeight()-title.getPrefHeight()) / Terraria.DISPLAY_RENDERING_HEIGHT); - ImageView playerImgView = new ImageView(new Image(playerPath, tileWidth.get(), tileHeight.get()*2, false, false)); - environment.getPlayer().setRect((int) playerImgView.getFitWidth(), (int) playerImgView.getFitHeight()); - playerImgView.translateYProperty().bind(environment.getPlayer().getYProperty()); - playerImgView.translateXProperty().bind(environment.getPlayer().getXProperty()); - display.getChildren().add(playerImgView); + this.environment = new Environment(scaleMultiplicatorWidth, scaleMultiplicatorHeight); + new View(environment, displayTiledMap, displayHUD, scaleMultiplicatorWidth, scaleMultiplicatorHeight); + + this.addKeysEventListener(primaryStage); } - private ImageView createImageView(Entity entity, Image img) + /** + * Ajoute la fonctionnalité des listeners des event du clavier + * @param stage Specifier l'application + */ + private void addKeysEventListener(Stage stage) { - ImageView imageView = new ImageView(img); - imageView.translateXProperty().bind(entity.getXProperty()); - imageView.translateYProperty().bind(entity.getYProperty()); + Player player = this.environment.getPlayer(); + + stage.addEventFilter(KeyEvent.KEY_PRESSED, key -> { + player.getKeysInput().put(key.getCode(), true); + key.consume(); + }); + + stage.addEventFilter(KeyEvent.KEY_RELEASED, key -> { + player.getKeysInput().put(key.getCode(), false); + key.consume(); + }); - return imageView; + stage.addEventFilter(ScrollEvent.SCROLL, scroll -> { + boolean scrollUp = scroll.getDeltaY() > 0; + if (scrollUp) + player.positionOfCursorInventoryBar.setValue(player.positionOfCursorInventoryBar.get() + 1); + boolean scrollDown = scroll.getDeltaY() < 0; + if (scrollDown) + player.positionOfCursorInventoryBar.setValue(player.positionOfCursorInventoryBar.get() - 1); + + if (player.positionOfCursorInventoryBar.get() > 8) + player.positionOfCursorInventoryBar.setValue(0); + if (player.positionOfCursorInventoryBar.get() < 0) + player.positionOfCursorInventoryBar.setValue(8); + }); + + stage.addEventFilter(MouseEvent.MOUSE_CLICKED, click -> { + double scaleMultiplicativeWidth = (root.getPrefWidth() / Terraria.DISPLAY_RENDERING_WIDTH); + double scaleMultiplicativeHeight = ((root.getPrefHeight()-title.getPrefHeight()) / Terraria.DISPLAY_RENDERING_HEIGHT); + int tileWidth = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicativeWidth); + int tileHeight = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicativeHeight); + // La position correcte sur le Pane + double mouseX = click.getSceneX(); + double mouseY = click.getSceneY()-title.getPrefHeight(); + Rectangle2D rectangle = new Rectangle2D(mouseX, mouseY, scaleMultiplicativeWidth, scaleMultiplicativeHeight); + // Le bloc où la souris à clicker + int xBlock = (int) (mouseX/tileWidth); + int yBlock = (int) (mouseY/tileHeight); + // La position du joueur + int xPlayer = (int) ((player.getX()+(tileWidth/2))/tileWidth); + int yPlayer = (int) ((player.getY()+(tileHeight/2))/tileHeight); + // La distance entre le bloc et le joueur + int distanceBetweenBlockPlayerAxisX = Math.abs(xPlayer - xBlock); + int distanceBetweenBlockPlayerAxisY = Math.abs(yPlayer - yBlock); + + boolean isOneBlockDistance = distanceBetweenBlockPlayerAxisY >= 0 && distanceBetweenBlockPlayerAxisY <= Player.BREAK_BLOCK_DISTANCE && distanceBetweenBlockPlayerAxisX >= 0 && distanceBetweenBlockPlayerAxisX <= Player.BREAK_BLOCK_DISTANCE; + if (isOneBlockDistance) + { + // Casse les blocs + if (click.getButton().equals(MouseButton.PRIMARY)) + // Commence a cherché l'entité ciblée + for (Entity entity : environment.getEntities()) { + // La position de l'entité + int xEntity = (int) (entity.getRect().get().getMinX()); + int yEntity = (int) (entity.getRect().get().getMinY()); + + if (entity.getRect().collideRect(rectangle)) { + player.pickup((StowableObjectType) entity); + + Node nodeAtDelete = null; int i = 0; + // Tant qu'on n'a pas trouvé l'objet sur le Pane, il continue la boucle. + do { + Node node = displayTiledMap.getChildren().get(i); + int xNode = (int) (node.getTranslateX()); + int yNode = (int) (node.getTranslateY()); + + if (xNode == xEntity && yNode == yEntity) { + nodeAtDelete = node; + environment.getTileMaps().setTile(TileMaps.SKY, yNode/tileHeight, xNode/tileWidth); + // Supprime dans le modele et dans la vue + environment.getEntities().remove(entity); + displayTiledMap.getChildren().remove(nodeAtDelete); + } + i++; + } while (i < displayTiledMap.getChildren().size() && Objects.isNull(nodeAtDelete)); + + // Quand tous c'est bien déroulés, aprés avoir trouvé l'entité et l'objet sur l'écran, il arrête de chercher d'autre entité d'où le break + break; + } + } + + // Pose les blocs + if (click.getButton().equals(MouseButton.SECONDARY)) { + boolean haveAnItemOnHand = !Objects.isNull(player.getItemSelected()); + if (haveAnItemOnHand) { + Entity entity = null; + if (player.getItemSelected() instanceof Dirt) { + entity = new Dirt(xBlock*tileWidth, yBlock*tileHeight); + environment.getTileMaps().setTile(TileMaps.DIRT, yBlock, xBlock); + } else if (player.getItemSelected() instanceof Stone) { + entity = new Stone(xBlock*tileWidth, yBlock*tileHeight); + environment.getTileMaps().setTile(TileMaps.STONE, yBlock, xBlock); + } + + if(!Objects.isNull(entity)) { + entity.setRect(tileWidth, tileHeight); + environment.getEntities().add(0, entity); + + // Si on le pose sur le joueur + boolean isIntoABlock = player.getRect().collideRect(entity.getRect()); + if (isIntoABlock) { + // Place le joueur au-dessus du block posé. + player.setY(entity.getY() - player.getRect().getHeight()); + player.getGravity().yInit = player.getY(); + player.getGravity().xInit = player.getX(); + } + + player.getInventory().get(player.positionOfCursorInventoryBar.get()).remove(player.getItemSelected()); + if (player.getInventory().get(player.positionOfCursorInventoryBar.get()).size()-1 >= 0) + player.setItemSelected(player.getInventory().get(player.positionOfCursorInventoryBar.get()).get(player.getInventory().get(player.positionOfCursorInventoryBar.get()).size()-1)); + } + } + } + } + }); } } \ No newline at end of file diff --git a/src/main/java/fr/sae/terraria/modele/Clock.java b/src/main/java/fr/sae/terraria/modele/Clock.java new file mode 100644 index 0000000..631fa97 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/Clock.java @@ -0,0 +1,37 @@ +package fr.sae.terraria.modele; + +import javafx.beans.property.SimpleIntegerProperty; + + +public class Clock +{ + public static final int ONE_MINUTE_INGAME = 37; + public static final int ONE_DAY_INGAME = 1440; + private final SimpleIntegerProperty minutes; + private final SimpleIntegerProperty days; + + + public Clock() + { + minutes = new SimpleIntegerProperty(0); + days = new SimpleIntegerProperty(0); + } + + public void updates(int ticks) + { + // si environ 1 minute passe irl, le timer dans le jeu augmente de 10 minutes + if (ticks%Clock.ONE_MINUTE_INGAME == 0) { + if (getMinutes()+1 == ONE_DAY_INGAME) { + days.setValue(getDays()+1); + minutes.setValue(0); + } else minutes.setValue(getMinutes()+1); + } + } + + public SimpleIntegerProperty minutesProperty() { return minutes; } + public SimpleIntegerProperty daysProperty() { return days; } + + + public int getMinutes() { return minutes.get(); } + public int getDays() { return days.get(); } +} diff --git a/src/main/java/fr/sae/terraria/modele/Environment.java b/src/main/java/fr/sae/terraria/modele/Environment.java index adb3e4a..dc0d692 100644 --- a/src/main/java/fr/sae/terraria/modele/Environment.java +++ b/src/main/java/fr/sae/terraria/modele/Environment.java @@ -1,74 +1,138 @@ package fr.sae.terraria.modele; -import fr.sae.terraria.modele.entities.*; +import fr.sae.terraria.Terraria; +import fr.sae.terraria.modele.blocks.TallGrass; +import fr.sae.terraria.modele.entities.Player; +import fr.sae.terraria.modele.entities.Rabbit; +import fr.sae.terraria.modele.entities.entity.CollideObjectType; import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.ReproductiveObjectType; +import fr.sae.terraria.vue.View; +import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; -import javafx.scene.input.KeyCode; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.image.Image; import javafx.util.Duration; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import static javafx.scene.input.KeyCode.D; -import static javafx.scene.input.KeyCode.Q; +import java.util.List; public class Environment { - private Player player; - private ArrayList entities; - private Map keysInput = new HashMap<>(); + private Clock clock; + private final ObservableList entities; + + private final TileMaps tileMaps; + private final Player player; + public double scaleMultiplicatorWidth; + public double scaleMultiplicatorHeight; + + public int widthTile; + public int heightTile; private int ticks = 0; - public Environment() + public Environment(double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) { - entities = new ArrayList<>(); + this.scaleMultiplicatorWidth = scaleMultiplicatorWidth; + this.scaleMultiplicatorHeight = scaleMultiplicatorHeight; + + this.tileMaps = new TileMaps(); + this.tileMaps.load(Terraria.srcPath + "maps/map_0.json"); - player = new Player(0,0, 3, 1); - player.setPv(20); - player.setVelocity(2); + this.clock = new Clock(); + this.entities = FXCollections.observableArrayList(); + this.widthTile = (int) (scaleMultiplicatorWidth * TileMaps.TILE_DEFAULT_SIZE); + this.heightTile = (int) (scaleMultiplicatorHeight * TileMaps.TILE_DEFAULT_SIZE); + + this.player = new Player(this, (5*widthTile), (3*heightTile)); + this.player.setVelocity(5); + this.player.setPv(4); + Image image = View.loadAnImage("sprites/player/player_idle.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.player.setRect((int) image.getWidth(), (int) image.getHeight()); + image.cancel(); gameLoop(); } - private void gameLoop() + /** Evite que l'entité sort de la fenêtre. */ + private void worldLimit(Entity entity) { - Timeline loop = new Timeline(); - loop.setCycleCount(Timeline.INDEFINITE); + double widthScreen = (scaleMultiplicatorWidth * Terraria.DISPLAY_RENDERING_WIDTH); - KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.017), (ev -> { - eventInput(); - getPlayer().updates(); + boolean exceedsScreenOnLeft = entity.offset[0] == Entity.IS_MOVING_LEFT && entity.getX() < 0; + boolean exceedsScreenOnRight = entity.offset[0] == Entity.IS_MOVING_RIGHT && entity.getX() > (widthScreen - entity.getRect().getWidth()); + if (exceedsScreenOnLeft || exceedsScreenOnRight) + entity.offset[0] = (entity instanceof Rabbit) ? ((-1) * entity.offset[0]) : Entity.IDLE; + } - ticks++; + /** La boucle principale du jeu */ + private void gameLoop() + { + Timeline loop = new Timeline(); + loop.setCycleCount(Animation.INDEFINITE); + + List entitiesAtAdded = new ArrayList<>(); + KeyFrame keyFrame = new KeyFrame(Duration.seconds(Terraria.TARGET_FPS), (ev -> { + this.player.offset[0] = Entity.IDLE; + this.player.eventInput(); + this.worldLimit(this.player); + + // Ajoute les entités ReproductiveObjectType + for (Entity entity : entitiesAtAdded) + this.entities.add(0, entity); + entitiesAtAdded.clear(); + + // Génère aléatoirement des entités + GenerateEntity.tree(this); + GenerateEntity.tallGrass(this); + GenerateEntity.rabbit(this); + + for (Entity entity : entities) + { + // Fait sauter ou non le lapin + if (entity instanceof Rabbit) { + boolean mustJump = ticks%Rabbit.JUMP_FREQUENCY == 0; + if (mustJump) { + boolean jumpOrNot = Math.random() < Rabbit.LUCK_OF_JUMPING; + if (jumpOrNot && entity.offset[1] != Entity.IS_FALLING) + entity.jump(); + } + } + + if (entity instanceof CollideObjectType) { + this.worldLimit(entity); + ((CollideObjectType) entity).collide(); + } + + if (entity instanceof ReproductiveObjectType) { + // Reproduit les hautes herbes + boolean tallGrassMustReproduce = ticks%TallGrass.REPRODUCTION_RATE == 0; + if (entity instanceof TallGrass && tallGrassMustReproduce) + entitiesAtAdded.addAll(((ReproductiveObjectType) entity).reproduction(this)); + } + entity.updates(); + } + + this.player.collide(); + this.player.updates(); + + this.clock.updates(ticks); + this.ticks++; })); loop.getKeyFrames().add(keyFrame); loop.play(); } - public void eventInput() - { - int countKeys[] = new int[1]; - keysInput.forEach((key, value) -> { - if (key == D && value) - getPlayer().moveRight(); - if (key == Q && value) - getPlayer().moveLeft(); - - if (!value) - countKeys[0]++; - if (countKeys[0] == keysInput.size()) - getPlayer().idle(); - }); - } - - public Map getKeysInput() { return keysInput; } - public ArrayList getEntities() { return entities; } - public Player getPlayer() { return player; } -} + public ObservableList getEntities() { return this.entities; } + public TileMaps getTileMaps() { return this.tileMaps; } + public Player getPlayer() { return this.player; } + public Clock getGameClock() { return this.clock; } + public int getTicks() { return this.ticks; } +} \ No newline at end of file diff --git a/src/main/java/fr/sae/terraria/modele/GenerateEntity.java b/src/main/java/fr/sae/terraria/modele/GenerateEntity.java new file mode 100644 index 0000000..3dfd6f1 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/GenerateEntity.java @@ -0,0 +1,93 @@ +package fr.sae.terraria.modele; + +import fr.sae.terraria.modele.blocks.TallGrass; +import fr.sae.terraria.modele.blocks.Tree; +import fr.sae.terraria.modele.entities.Rabbit; +import fr.sae.terraria.modele.entities.entity.Entity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static fr.sae.terraria.modele.blocks.TallGrass.TALL_GRASS_SPAWN_RATE; +import static fr.sae.terraria.modele.blocks.TallGrass.WHEN_SPAWN_A_TALL_GRASS; +import static fr.sae.terraria.modele.blocks.Tree.TREE_SPAWN_RATE; +import static fr.sae.terraria.modele.blocks.Tree.WHEN_SPAWN_A_TREE; +import static fr.sae.terraria.modele.entities.Rabbit.RABBIT_SPAWN_RATE; +import static fr.sae.terraria.modele.entities.Rabbit.WHEN_SPAWN_A_RABBIT; + + +public class GenerateEntity +{ + private static final Random random = new Random(); + + + /** + * Génère une entité selon de quand il spawn et du pourcent de change qu'il spawn réellement. + * + * @param e L'entité concernée + * @param whenSpawn Le nombre qui determine quand il doit spawn sur la carte + * @param spawnRate Le pourcentage de chance qu'il spawn réellement à l'endroit qu'on souhaite le placer + */ + private static void generateAnEntity(Environment environment, Entity e, int whenSpawn, double spawnRate) + { + List entities = environment.getEntities(); + TileMaps maps = environment.getTileMaps(); + int widthTile = environment.widthTile; + int heightTile = environment.heightTile; + int ticks = environment.getTicks(); + + // Fréquence d'apparition + if (ticks%whenSpawn == 0) + for (int y = 0; y < maps.getHeight(); y++) + // Est-ce que l'arbre doit spawn sur ce 'y' + if (Math.random() < spawnRate) { + List locFloorsOnAxisX = findFloors(maps, y); + // Si il y a du sol sur la ligne + if (!locFloorsOnAxisX.isEmpty()) { + int onWhichFloor = random.nextInt(locFloorsOnAxisX.size()); + int targetFloor = locFloorsOnAxisX.get((onWhichFloor == 0) ? onWhichFloor : onWhichFloor - 1); + int xEntity = targetFloor * widthTile; + int yEntity = ((y == 0) ? y : (y - 1)) * heightTile; + // Verifies au cas où si le tile au-dessus de lui est bien une casse vide (Du ciel) + if (maps.getTile(targetFloor, y - 1) == TileMaps.SKY) { + for (Entity entity : entities) + if (entity instanceof Tree && xEntity == entity.getX() && yEntity == entity.getY()) + // Un arbre est déjà present ? Il ne le génère pas et arrête complétement la fonction + return; + e.setX(xEntity); + e.setY(yEntity); + e.getGravity().setXInit(xEntity); + e.getGravity().setYInit(yEntity); + e.setRect(widthTile, heightTile); + // Une fois une position trouvée, on l'ajoute en tant qu'entité pour qu'il puisse ensuite l'affiché + entities.add(0, e); + } + // Une fois l'arbre généré, il arrête complétement toute la fonction + return; + } + // Sinon on retourne vers la premiere boucle 'for' + } + } + + /** Range les positions du sol sur la ligne 'y' */ + private static List findFloors(TileMaps maps, int y) + { + List localisation = new ArrayList<>(); + for (int x = 0; x < maps.getWidth(); x++) { + int targetTile = maps.getTile(x, y); + + if (targetTile == TileMaps.FLOOR_TOP || targetTile == TileMaps.FLOOR_RIGHT || targetTile == TileMaps.FLOOR_LEFT) + localisation.add(x); + } + + return localisation; + } + + /** À un certain moment, grace au tick, il va générer des arbres +/- grand uniquement sur un sol */ + public static void tree(Environment environment) { generateAnEntity(environment, new Tree(), WHEN_SPAWN_A_TREE, TREE_SPAWN_RATE); } + /** À un certain moment, grace au tick, il va générer des hautes herbes sur un sol */ + public static void tallGrass(Environment environment) { generateAnEntity(environment, new TallGrass(), WHEN_SPAWN_A_TALL_GRASS, TALL_GRASS_SPAWN_RATE); } + /** À un certain moment, grace au tick, il va générer des lapins sur un sol */ + public static void rabbit(Environment environment) { generateAnEntity(environment, new Rabbit(environment), WHEN_SPAWN_A_RABBIT, RABBIT_SPAWN_RATE); } +} diff --git a/src/main/java/fr/sae/terraria/modele/TileMaps.java b/src/main/java/fr/sae/terraria/modele/TileMaps.java index 60ff8e7..a7696be 100644 --- a/src/main/java/fr/sae/terraria/modele/TileMaps.java +++ b/src/main/java/fr/sae/terraria/modele/TileMaps.java @@ -7,22 +7,24 @@ public class TileMaps { - public final static int tileDefaultSize = 16; - public final static int SKY = 0; - public final static int STONE = 1; - public final static int DIRT = 2; - public final static int FLOOR_TOP = 3; - public final static int FLOOR_LEFT = 4; - public final static int FLOOR_RIGHT = 5; - - private int[][] map; + // Constantes + public static final int TILE_DEFAULT_SIZE = 16; + public static final int SKY = 0; + public static final int STONE = 1; + public static final int DIRT = 2; + public static final int FLOOR_TOP = 3; + public static final int FLOOR_LEFT = 4; + public static final int FLOOR_RIGHT = 5; + + // Qui concerne la carte + private int[][] maps; private int w; private int h; /** * Compte la taille de la carte et ensuite la charge dans - * la variable map + * la variable maps * * @param path Le chemin depuis le root (src) */ @@ -36,7 +38,7 @@ public void load(String path) JsonReader jsonReader = new JsonReader(fileReader)) { jsonReader.beginObject(); - // Deduit la taille de la carte. + // Déduit la taille de la carte. while (jsonReader.hasNext()) { h++; @@ -59,7 +61,7 @@ public void load(String path) try (FileReader fileReader = new FileReader(path); JsonReader jsonReader = new JsonReader(fileReader)) { - map = new int[h][w]; + maps = new int[h][w]; // Ecrit la carte dans la mémoire. jsonReader.beginObject(); while (jsonReader.hasNext()) @@ -68,7 +70,7 @@ public void load(String path) jsonReader.beginArray(); while (jsonReader.hasNext()) { - map[i][j] = jsonReader.nextInt(); + maps[i][j] = jsonReader.nextInt(); j++; } jsonReader.endArray(); @@ -80,40 +82,10 @@ public void load(String path) } catch (Exception e) { e.printStackTrace(); } } - /** - * Crée une variable de la même taille que la carte couramment utilisé - * La copie et renvoie la variable qui a copié la carte du jeu - * - * @return Un tableau 2D qui contient la carte qui est utilisé dans le jeu. - */ - public int[][] copy() - { - int[][] mapCopy = new int[map.length][map[0].length]; - - for (int i = 0; i < this.map.length; i++) - for (int j = 0; j < this.map[i].length; j++) - mapCopy[i][j] = this.map[i][j]; - - return mapCopy; - } - - public void clear() - { - for (int y = 0; y < getHeight(); y++) - for (int x = 0; x < getWidth(); x++) - map[y][x] = SKY; - } - - public void fill(int tileIndex) - { - for (int y = 0; y < getHeight(); y++) - for (int x = 0; x < getWidth(); x++) - map[y][x] = tileIndex; - } + public int getHeight() { return maps.length; } + public int getWidth() { return maps[0].length; } + public int getTile(int x, int y) { return maps[y][x]; } - public int getHeight() { return map.length; } - public int getWidth() { return map[0].length; } - public int getTile(int y, int x) { return map[y][x]; } - public void setTile(int tileIndex, int y, int x) { map[y][x] = tileIndex; } + public void setTile(int tileIndex, int y, int x) { maps[y][x] = tileIndex; } } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/Block.java b/src/main/java/fr/sae/terraria/modele/blocks/Block.java index 1517d84..659d28c 100644 --- a/src/main/java/fr/sae/terraria/modele/blocks/Block.java +++ b/src/main/java/fr/sae/terraria/modele/blocks/Block.java @@ -1,16 +1,14 @@ package fr.sae.terraria.modele.blocks; import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; -public abstract class Block extends Entity +public abstract class Block extends Entity implements StowableObjectType { - public Block(int x, int y) - { - super(x, y); - } + protected Block(int x, int y) { super(x, y); } public abstract void updates(); } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/Dirt.java b/src/main/java/fr/sae/terraria/modele/blocks/Dirt.java index aab69c1..72db2af 100644 --- a/src/main/java/fr/sae/terraria/modele/blocks/Dirt.java +++ b/src/main/java/fr/sae/terraria/modele/blocks/Dirt.java @@ -3,10 +3,12 @@ public class Dirt extends Block { + + public Dirt(int x, int y) { super(x, y); } - public void updates() {} + public void updates() { } } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/Grass.java b/src/main/java/fr/sae/terraria/modele/blocks/Grass.java index 44d996a..605996b 100644 --- a/src/main/java/fr/sae/terraria/modele/blocks/Grass.java +++ b/src/main/java/fr/sae/terraria/modele/blocks/Grass.java @@ -8,7 +8,8 @@ public Grass(int x, int y){ } @Override - public void updates() { + public void updates() + { } } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/Stone.java b/src/main/java/fr/sae/terraria/modele/blocks/Stone.java index 081974c..a94ae39 100644 --- a/src/main/java/fr/sae/terraria/modele/blocks/Stone.java +++ b/src/main/java/fr/sae/terraria/modele/blocks/Stone.java @@ -17,7 +17,7 @@ public Stone(int x, int y){ } @Override - public void updates() { - + public void updates() + { } } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/TallGrass.java b/src/main/java/fr/sae/terraria/modele/blocks/TallGrass.java index 4a0c3b2..c93ff26 100644 --- a/src/main/java/fr/sae/terraria/modele/blocks/TallGrass.java +++ b/src/main/java/fr/sae/terraria/modele/blocks/TallGrass.java @@ -1,14 +1,74 @@ package fr.sae.terraria.modele.blocks; -public class TallGrass +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.ReproductiveObjectType; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +import java.util.ArrayList; +import java.util.List; + + +public class TallGrass extends Block implements ReproductiveObjectType { - /* - TODO: Donne de la fibre au joueur de manière aléatoire - Peut ne pas drop ou drop juste 1 (Pas plus) - (Optionnel) Faire que l'herbe au passage du joueur provoque un bruitage - (Optionnel) Faire une animation lorsque le joueur passe dedans - */ - public TallGrass(int x, int y){ + public static final int WHEN_SPAWN_A_TALL_GRASS = 2_500; + public static final double TALL_GRASS_SPAWN_RATE = .3; + public static final double REPRODUCTION_RATE = 500; + public static final double GROWTH_SPEED = .0005; + public static final int GROWTH_TALL_GRASS_STEP = 6; + public static final int LOOTS_FIBRE_MAX = 3; + + private DoubleProperty tallGrassGrowth; + + + public TallGrass(int x, int y) + { + super(x, y); + + this.tallGrassGrowth = new SimpleDoubleProperty(0); + } + + public TallGrass() { this(0, 0); } + public void updates() + { + if (tallGrassGrowth.get() < GROWTH_TALL_GRASS_STEP) + tallGrassGrowth.set(tallGrassGrowth.get() + GROWTH_SPEED); } + + public List reproduction(Environment environment) + { + List children = new ArrayList<>(); + List entities = environment.getEntities(); + + int left = 0; + int right = 0; + for (int x = 0; x < entities.size(); x++) { + if (entities.get(x).getX() == (getX() - environment.widthTile) && entities.get(x).getY() == getY()) + left++; + if (entities.get(x).getX() == (getX() + environment.widthTile) && entities.get(x).getY() == getY()) + right++; + } + + int x = -1; + int y = (int) (getY()/environment.heightTile)+1; + if (left == 0) + x = (int) (getX() - environment.widthTile)/environment.widthTile; + else if (right == 0) + x = (int) (getX() + environment.widthTile)/environment.widthTile; + + if ((x >= 0 && x < environment.getTileMaps().getWidth()) && (y >= 0 && y < environment.getTileMaps().getHeight())) { + if (environment.getTileMaps().getTile(x, y) != TileMaps.SKY) { + TallGrass tallGrassChildren = new TallGrass((int) ((left == 0) ? (getX() - environment.widthTile) : (getX() + environment.widthTile)), (int) getY()); + children.add(tallGrassChildren); + } + } + + return children; + } + + + public DoubleProperty getTallGrassGrowthProperty() { return this.tallGrassGrowth; } } diff --git a/src/main/java/fr/sae/terraria/modele/blocks/Tree.java b/src/main/java/fr/sae/terraria/modele/blocks/Tree.java new file mode 100644 index 0000000..9f11d9e --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/blocks/Tree.java @@ -0,0 +1,17 @@ +package fr.sae.terraria.modele.blocks; + + +public class Tree extends Block +{ + public static final int WHEN_SPAWN_A_TREE = 5_000; + public static final double TREE_SPAWN_RATE = .2; + + + public Tree(int x, int y) { super(x, y); } + public Tree() { this(0, 0); } + + public void updates() + { + + } +} diff --git a/src/main/java/fr/sae/terraria/modele/entities/Arrow.java b/src/main/java/fr/sae/terraria/modele/entities/Arrow.java index 33f1583..1e5a702 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/Arrow.java +++ b/src/main/java/fr/sae/terraria/modele/entities/Arrow.java @@ -1,9 +1,10 @@ package fr.sae.terraria.modele.entities; - import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; + -public class Arrow extends Entity +public class Arrow extends Entity implements StowableObjectType { @@ -14,11 +15,5 @@ public Arrow(int x, int y, int velocity) this.velocity = velocity; } - public void updates() - { - this.setX(this.x.get() + this.offset[0] * this.velocity); - this.setY(this.y.get() + this.offset[1] * this.velocity); - - this.rect.update(x.get(), y.get()); - } + public void updates() { } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/Player.java b/src/main/java/fr/sae/terraria/modele/entities/Player.java index 308180d..56474dd 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/Player.java +++ b/src/main/java/fr/sae/terraria/modele/entities/Player.java @@ -1,39 +1,242 @@ package fr.sae.terraria.modele.entities; - +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.blocks.Dirt; +import fr.sae.terraria.modele.blocks.Stone; +import fr.sae.terraria.modele.entities.entity.Animation; +import fr.sae.terraria.modele.entities.entity.CollideObjectType; import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.input.KeyCode; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + -public class Player extends Entity +public class Player extends Entity implements CollideObjectType { - private double frame; // TODO faire une animation + public static final int BREAK_BLOCK_DISTANCE = 1; + public static final int BLOCK_STACKING_MAX = 16; + public static final int NB_CASES_MAX_INVENTORY = 27; + public static final int NB_LINES_INVENTORY = 3; + + private final Map> inventory; + private final EnumMap keysInput; + + public IntegerProperty positionOfCursorInventoryBar; + + private StowableObjectType itemSelected; + private Environment environment; - public Player(int x, int y, int pv, int velocity) + + /** + * @param x La position du joueur en X + * @param y La position du joueur en Y + */ + public Player(Environment environment, int x, int y) { super(x, y); + this.environment = environment; + + this.animation = new Animation(); + this.keysInput = new EnumMap<>(KeyCode.class); + this.inventory = new HashMap<>(); + this.positionOfCursorInventoryBar = new SimpleIntegerProperty(0); - this.pv = pv; - this.velocity = velocity; - this.frame = 1; + for (int i = 0; i < NB_CASES_MAX_INVENTORY; i++) + this.inventory.put(i, FXCollections.observableArrayList()); } - public void moveRight() { - this.offset[0] = 1; + public void updates() + { + // Applique les déplacements selon les valeurs de l'offset + // this.setX(this.x.get() + this.offset[0] * this.velocity); + + if (this.offset[1] == Entity.IDLE && !air) { + this.gravity.xInit = this.x.get(); + this.gravity.yInit = this.y.get(); + this.gravity.vInit = this.velocity; + this.gravity.degInit = -90; + + this.gravity.timer = .0; + } + + this.setX(this.getX() + this.offset[0] * this.getVelocity()); + + if (this.rect != null) + this.rect.updates(x.get(), y.get()); + animation.loop(); } - public void moveLeft() { this.offset[0] = -1; } + public void collide() + { + int widthTile = environment.widthTile; int heightTile = environment.heightTile; + TileMaps tileMaps = environment.getTileMaps(); + + // Detection vide en dessous + int yBottom = (int) (getY()+getRect().getHeight()-COLLISION_TOLERANCE)/heightTile; + int posX = (int) ((getX()+((offset[0] < 0) ? COLLISION_TOLERANCE : -COLLISION_TOLERANCE)) + ((offset[0] > 0) ? getRect().getWidth() : 0))/widthTile; + + boolean footInTheVoid = tileMaps.getTile(posX, yBottom+1) == TileMaps.SKY; + if (footInTheVoid) + this.air = true; + + // Detection collision gauche droite + if (this.offset[0] != Entity.IDLE) { + int yTop = (int) (getY()+COLLISION_TOLERANCE)/heightTile; + int futurePositionX = (int) ((getX()+((offset[0] < 0) ? COLLISION_TOLERANCE : -COLLISION_TOLERANCE)+(velocity*offset[0])) + ((offset[0] > 0) ? getRect().getWidth() : 0))/widthTile; + + // Il gère les deux car futurePositionX change dynamiquement suivant l'offset + boolean isCollideLeftOrRight = tileMaps.getTile(futurePositionX, yTop) != TileMaps.SKY || tileMaps.getTile(futurePositionX, yBottom) != TileMaps.SKY; + if (isCollideLeftOrRight) + this.offset[0] = Entity.IDLE; + } + + // Detection collision en bas et en haut + if (this.offset[1] != Entity.IDLE) { + int xLeft = (int) (getX()+COLLISION_TOLERANCE)/widthTile; + int xRight = (int) ((getX()+getRect().getWidth())-COLLISION_TOLERANCE)/widthTile; - public void idle(){ this.offset[0] = 0; this.offset[1] =0;} + // Tombe + if (this.offset[1] == Entity.IS_FALLING) { + this.gravity.degInit = 0; + double futurePositionY = gravity.formulaOfTrajectory() + rect.getHeight(); - public void updates(){ - this.setX(this.x.get() + this.offset[0] * this.velocity); - this.setY(this.y.get() + this.offset[1] * this.velocity); + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + if (isCollideBottom) { + this.setJumpPosInit(); + this.gravity.timer = 0; + this.offset[1] = Entity.IDLE; + } else setY(futurePositionY); + // Saute + } else if (this.offset[1] == Entity.IS_JUMPING) { + double futurePositionY = gravity.formulaOfTrajectory(); + this.air = true; - // TODO faire les frame - if(frame == 4) { - frame = 0; + boolean isCollideTop = tileMaps.getTile(xLeft, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + + // Quand le joueur monte + if ((gravity.flightTime/2) >= gravity.timer) { + if (isCollideTop) { + this.fall(); + } else setY(futurePositionY); + // Quand le joueur decent + } else { + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) ((futurePositionY + rect.getHeight()) - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight,(int) ((futurePositionY + rect.getHeight()) - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + + if (isCollideTop) { + this.fall(); + } else if (isCollideBottom) { + this.setJumpPosInit(); + this.gravity.timer = 0; + this.offset[1] = Entity.IDLE; + this.air = false; + } else setY(futurePositionY); + } + } + } else if (this.air) { + this.gravity.degInit = 0; + int xLeft = (int) (getX()+COLLISION_TOLERANCE)/widthTile; + int xRight = (int) (getX()-COLLISION_TOLERANCE+getRect().getWidth())/widthTile; + double futurePositionY = this.gravity.formulaOfTrajectory() + this.rect.getHeight(); + + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) (futurePositionY - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + if (isCollideBottom) { + this.setJumpPosInit(); + this.offset[1] = Entity.IDLE; + this.air = false; + } else setY(futurePositionY - this.rect.getHeight()); } + } + + /** Lie les inputs au clavier à une ou des actions. */ + public void eventInput() + { + this.keysInput.forEach((key, value) -> { + if (Boolean.TRUE.equals(value)) { + if (key == KeyCode.Z || key == KeyCode.SPACE) + if (this.offset[1] != -1) this.jump(); + + if (key == KeyCode.D) + this.moveRight(); + else if (key == KeyCode.Q) + this.moveLeft(); + + if (key == KeyCode.DIGIT1) + this.positionOfCursorInventoryBar.set(0); + else if (key == KeyCode.DIGIT2) + this.positionOfCursorInventoryBar.set(1); + else if (key == KeyCode.DIGIT3) + this.positionOfCursorInventoryBar.set(2); + else if (key == KeyCode.DIGIT4) + this.positionOfCursorInventoryBar.set(3); + else if (key == KeyCode.DIGIT5) + this.positionOfCursorInventoryBar.set(4); + else if (key == KeyCode.DIGIT6) + this.positionOfCursorInventoryBar.set(5); + else if (key == KeyCode.DIGIT7) + this.positionOfCursorInventoryBar.set(6); + else if (key == KeyCode.DIGIT8) + this.positionOfCursorInventoryBar.set(7); + else if (key == KeyCode.DIGIT9) + this.positionOfCursorInventoryBar.set(8); + } + }); + } + + public int nbStacksIntoInventory() + { + int counter = 0; + for (int i = 0; i < inventory.size(); i++) + counter += (!this.inventory.get(i).isEmpty() && this.inventory.get(i).get(0) != null) ? 1 : 0; - this.rect.update(x.get(), y.get()); + return counter; } + + public void pickup(StowableObjectType pickupObject) + { + int nbStacksInventory = nbStacksIntoInventory(); + boolean estComplet = false; + + if (nbStacksInventory < NB_CASES_MAX_INVENTORY) { + int i = 0; + while (i < this.inventory.size()) { + int beforeSize = this.inventory.get(i).size(); + if (this.inventory.get(i).isEmpty()) { + this.inventory.get(i).add(pickupObject); + this.setItemSelected(pickupObject); + } + else if (this.inventory.get(i).size() == BLOCK_STACKING_MAX) + estComplet = true; + else if (this.inventory.get(i).get(0) instanceof Dirt && pickupObject instanceof Dirt) { + this.inventory.get(i).add(pickupObject); + estComplet = false; + } else if (this.inventory.get(i).get(0) instanceof Stone && pickupObject instanceof Stone) { + this.inventory.get(i).add(pickupObject); + estComplet = false; + } + + // Quand un objet a étais mise dans l'inventaire, il arrête la fonction + if (beforeSize != this.inventory.get(i).size()) return; + i++; + } + + if (estComplet) + this.inventory.get(nbStacksInventory).add(pickupObject); + } + } + + + public Map> getInventory() { return inventory; } + public Map getKeysInput() { return keysInput; } + public StowableObjectType getItemSelected() { return itemSelected; } + + public void setItemSelected(StowableObjectType itemSelected) { this.itemSelected = itemSelected; } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/Rabbit.java b/src/main/java/fr/sae/terraria/modele/entities/Rabbit.java index 73a43f3..ba97c78 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/Rabbit.java +++ b/src/main/java/fr/sae/terraria/modele/entities/Rabbit.java @@ -1,32 +1,156 @@ package fr.sae.terraria.modele.entities; - +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.entities.entity.Animation; +import fr.sae.terraria.modele.entities.entity.CollideObjectType; import fr.sae.terraria.modele.entities.entity.Entity; +import fr.sae.terraria.modele.entities.entity.ReproductiveObjectType; + +import java.util.ArrayList; +import java.util.List; -public class Rabbit extends Entity + +public class Rabbit extends Entity implements CollideObjectType, ReproductiveObjectType { - private int frame; + public static final int WHEN_SPAWN_A_RABBIT = 2_500; + public static final double RABBIT_SPAWN_RATE = .2; + + public static final double REPRODUCTION_RATE = 1_250; + public static final double LUCK_OF_JUMPING = .5; + public static final int JUMP_FREQUENCY = 50; + private Environment environment; + private Animation animation; - public Rabbit(int x, int y, int pv, double velocity) + + public Rabbit(Environment environment, int x, int y) { super(x, y); - this.pv = pv; - this.velocity = velocity; + this.environment = environment; + + this.animation = new Animation(); + this.velocity = 1; + this.offset[0] = (Math.random() <= .5) ? Entity.IS_MOVING_RIGHT : Entity.IS_MOVING_LEFT; + this.gravity.amplitude = 40; } + public Rabbit(Environment environment) { this(environment, 0, 0); } + public void updates() { + if (this.offset[1] == Entity.IDLE && !air) { + this.gravity.xInit = this.x.get(); + this.gravity.yInit = this.y.get(); + this.gravity.vInit = this.velocity; + this.gravity.degInit = -90; + + this.gravity.timer = .0; + } + this.setX(this.x.get() + this.offset[0] * this.velocity); - this.setY(this.y.get() + this.offset[1] * this.velocity); - if(frame == 4) { - frame = 0; - }//TODO faire les frame + if (this.rect != null) + this.rect.updates(x.get(), y.get()); + this.animation.loop(); + } + + public List reproduction(Environment environment) + { + List children = new ArrayList<>(); + + return children; + } + + public void collide() + { + int widthTile = environment.widthTile; int heightTile = environment.heightTile; + TileMaps tileMaps = environment.getTileMaps(); + + // Detection vide en dessous + int yBottom = (int) (getY()+getRect().getHeight()-COLLISION_TOLERANCE)/heightTile; + int posX = (int) ((getX()+((offset[0] < 0) ? COLLISION_TOLERANCE : -COLLISION_TOLERANCE)) + ((offset[0] > 0) ? getRect().getWidth() : 0))/widthTile; + + boolean footInTheVoid = tileMaps.getTile(posX, yBottom+1) == TileMaps.SKY; + if (footInTheVoid) + this.air = true; + + // Detection collision gauche droite + if (this.offset[0] != Entity.IDLE) { + int yTop = (int) (getY()+COLLISION_TOLERANCE)/heightTile; + int futurePositionX = (int) ((getX()+((offset[0] < 0) ? COLLISION_TOLERANCE : -COLLISION_TOLERANCE)+(velocity*offset[0])) + ((offset[0] > 0) ? getRect().getWidth() : 0))/widthTile; + + // Il gère les deux car futurePositionX change dynamiquement suivant l'offset + boolean isCollideLeftOrRight = tileMaps.getTile(futurePositionX, yTop) != TileMaps.SKY || tileMaps.getTile(futurePositionX, yBottom) != TileMaps.SKY; + if (isCollideLeftOrRight) + this.offset[0] = (-1) * this.offset[0]; + } + + // Detection collision en bas et en haut + if (this.offset[1] != Entity.IDLE) { + int xLeft = (int) (getX()+COLLISION_TOLERANCE)/widthTile; + int xRight = (int) ((getX()+getRect().getWidth())-COLLISION_TOLERANCE)/widthTile; - this.rect.update(x.get(), y.get()); + // Tombe + if (this.offset[1] == Entity.IS_FALLING) { + this.gravity.degInit = 0; + double futurePositionY = gravity.formulaOfTrajectory() + rect.getHeight(); + + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + if (isCollideBottom) { + this.setJumpPosInit(); + this.gravity.timer = 0; + this.offset[1] = Entity.IDLE; + } else setY(futurePositionY); + // Saute + } else if (this.offset[1] == Entity.IS_JUMPING) { + double futurePositionY = gravity.formulaOfTrajectory(); + this.air = true; + + boolean isCollideTop = tileMaps.getTile(xLeft, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY + COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + + // Quand le joueur monte + if ((gravity.flightTime/2) >= gravity.timer) { + if (isCollideTop) { + this.fall(); + } else setY(futurePositionY); + // Quand le joueur decent + } else { + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) ((futurePositionY + rect.getHeight()) - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight,(int) ((futurePositionY + rect.getHeight()) - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + + if (isCollideTop) { + this.fall(); + } else if (isCollideBottom) { + this.setJumpPosInit(); + this.gravity.timer = 0; + this.offset[1] = Entity.IDLE; + this.air = false; + } else setY(futurePositionY); + } + } + } else if (this.air) { + this.gravity.degInit = 0; + int xLeft = (int) (getX()+COLLISION_TOLERANCE)/widthTile; + int xRight = (int) (getX()-COLLISION_TOLERANCE+getRect().getWidth())/widthTile; + double futurePositionY = this.gravity.formulaOfTrajectory() + this.rect.getHeight(); + + boolean isCollideBottom = tileMaps.getTile(xLeft, (int) (futurePositionY - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY || tileMaps.getTile(xRight, (int) (futurePositionY - COLLISION_TOLERANCE)/heightTile) != TileMaps.SKY; + if (isCollideBottom) { + this.setJumpPosInit(); + this.offset[1] = Entity.IDLE; + this.air = false; + } else setY(futurePositionY - this.rect.getHeight()); + } + + // TODO: Ce n'est pas parfait + /* + if (environment.getPlayer().getRect().collideRect(rect)) + offset[0] = (-1) * offset[0]; + */ } + + public Animation getAnimation() { return animation; } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/Slime.java b/src/main/java/fr/sae/terraria/modele/entities/Slime.java index d21265c..edb9664 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/Slime.java +++ b/src/main/java/fr/sae/terraria/modele/entities/Slime.java @@ -1,32 +1,23 @@ package fr.sae.terraria.modele.entities; - +import fr.sae.terraria.modele.entities.entity.CollideObjectType; import fr.sae.terraria.modele.entities.entity.Entity; +import javafx.beans.property.SimpleDoubleProperty; + -public class Slime extends Entity +public class Slime extends Entity implements CollideObjectType { - private int frame; - public Slime(int x, int y, int pv, double velocity) + public Slime(int x, int y, double pv, double velocity) { super(x, y); - this.pv = pv; + this.pv = new SimpleDoubleProperty(pv); this.velocity = velocity; } - public void updates() - { - this.setX(this.x.get() + this.offset[0] * this.velocity); - this.setY(this.y.get() + this.offset[1] * this.velocity); - - // TODO: faire les frame - if(frame == 4) { - frame = 0; - } - - this.rect.update(x.get(), y.get()); - } + public void updates() { } + public void collide() { } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/Animation.java b/src/main/java/fr/sae/terraria/modele/entities/entity/Animation.java new file mode 100644 index 0000000..8b33311 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/Animation.java @@ -0,0 +1,38 @@ +package fr.sae.terraria.modele.entities.entity; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + + +public class Animation +{ + public static final double FRAME_SPEED = .1; + + private final DoubleProperty frame; + private int endFrame; + + + public Animation() + { + this.frame = new SimpleDoubleProperty(); + this.endFrame = 3; + } + + /** Démarre l'animation de l'entité */ + public void loop() + { + if ((int) (this.getFrame()) < this.endFrame) + this.frame.set(this.getFrame() + Animation.FRAME_SPEED); + else this.reset(); + } + + /** Revient au début du Sprite Sheet */ + public void reset() { frame.set(0); } + + + public double getFrame() { return this.frame.get(); } + public DoubleProperty getFrameProperty() { return this.frame; } + + /** Spécifie quand l'animation sur le Sprite Sheet doit s'arrêter */ + public void setEndFrame(int newEndFrame) { this.endFrame = newEndFrame; } +} diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/CollideObjectType.java b/src/main/java/fr/sae/terraria/modele/entities/entity/CollideObjectType.java new file mode 100644 index 0000000..3e18712 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/CollideObjectType.java @@ -0,0 +1,15 @@ +package fr.sae.terraria.modele.entities.entity; + + +/** + * Permet de regrouper et de connaitre les entités qui doivent avoir une collision entre eux + * et avec leurs environment + */ +public interface CollideObjectType +{ + int COLLISION_TOLERANCE = 3; + + + /** Permet à chaque passage de boucle, d'appliquer une collision entre les entités et de son environment */ + void collide(); +} diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/Entity.java b/src/main/java/fr/sae/terraria/modele/entities/entity/Entity.java index c6e2501..4cb84cc 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/entity/Entity.java +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/Entity.java @@ -6,38 +6,75 @@ public abstract class Entity { - protected Rect rect; + public static final int IS_FALLING = -1; + public static final int IS_JUMPING = 1; + public static final int IS_MOVING_LEFT = -1; + public static final int IS_MOVING_RIGHT = 1; + public static final int IDLE = 0; + protected DoubleProperty pv; protected DoubleProperty x; protected DoubleProperty y; - protected int[] offset; - protected int pv = 3; + protected final Gravity gravity = new Gravity(); + protected Animation animation = null; + protected Rect rect = null; + protected double velocity = 1; + protected double pvMax; + public boolean air = false; + public int[] offset; // offset[0] >= -1 && offset[0] <= 1 et offset[1] >= -1 && offset[1] <= 1 - public Entity(int x, int y) + /** + * @param x La localisation de l'entité a l'horizontal + * @param y La localisation de l'entité a la verticale + */ + protected Entity(int x, int y) { this.x = new SimpleDoubleProperty(x); this.y = new SimpleDoubleProperty(y); + this.pv = new SimpleDoubleProperty(0); + this.pvMax = pv.get(); this.offset = new int[2]; } + + /** + * Permet de mettre à jour les valeurs qui concerne l'entité + * et qui doit rester au sain de l'objet + */ public abstract void updates(); - public DoubleProperty getXProperty() { return x; } - public DoubleProperty getYProperty(){ return y; } - public Rect getRect() { return rect; } - public double getX() { return x.get(); } - public double getY() { return y.get(); } - public int getPv() { return pv; } - public double getVelocity() { return velocity; } + /** Modifie le xInit et le yInit pour modifier le point de départ du saut ou de là où il tombe */ + public void setJumpPosInit() { this.gravity.xInit = this.x.get(); this.gravity.yInit = this.y.get(); } + /** Modifie l'offset qui permet de le déplacer vers la droite */ + public void moveRight() { this.offset[0] = Entity.IS_MOVING_RIGHT; } + /** Modifie l'offset qui permet de le déplacer vers la gauche */ + public void moveLeft() { this.offset[0] = Entity.IS_MOVING_LEFT; } + /** Modifie l'offset qui permet de le faire sauter */ + public void jump() { offset[1] = Entity.IS_JUMPING; } + /** Modifie l'offset qui permet de tomber */ + public void fall() { this.offset[1] = Entity.IS_FALLING; } - public void setPv(int pv) { this.pv = pv; } - public void setVelocity(double velocity) { this.velocity = velocity; } + + public DoubleProperty getPvProperty() { return this.pv; } + public DoubleProperty getXProperty() { return this.x; } + public DoubleProperty getYProperty(){ return this.y; } + public Animation getAnimation() { return this.animation; } + public Gravity getGravity() { return this.gravity; } + public Rect getRect() { return this.rect; } + public double getPvMax() { return this.pv.get(); } + public double getPv() { return this.pv.get(); } + public double getX() { return this.x.get(); } + public double getY() { return this.y.get(); } + public double getVelocity() { return this.velocity; } + + public void setPv(double pv) { this.pv.setValue(pv); this.pvMax = pv;} public void setX(double x) { this.x.setValue(x); } public void setY(double y) { this.y.setValue(y); } + public void setVelocity(double velocity) { this.velocity = velocity; } public void setRect(int width, int height) { this.rect = new Rect(x.get(), y.get(), width, height); } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/Gravity.java b/src/main/java/fr/sae/terraria/modele/entities/entity/Gravity.java new file mode 100644 index 0000000..72447b9 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/Gravity.java @@ -0,0 +1,39 @@ +package fr.sae.terraria.modele.entities.entity; + + +public class Gravity +{ + public static final double VALUE = 9.81; + public static final double SPEED = .3; + + public double timer = .0; + public double degInit = -90; + public double vInit; + public double xInit; + public double yInit; + public double flightTime; + + public int amplitude = 10; + + + public double formulaOfTrajectory() + { + flightTime = calcFlightTime(); + // Formule de type ax²+bx+c ( c = yInit ) + double yValue = (((Gravity.VALUE/2) * (timer * timer)) + ((Math.sin(degInit) * (vInit * amplitude)) * timer)) + yInit; + this.timer += SPEED; + + return yValue; + } + + private double calcFlightTime() + { + // résolution de l'équation f'(x) = 0 + if (degInit < 0) + return ((vInit * amplitude) * Math.sin(-degInit)) / Gravity.VALUE; + return ((vInit * amplitude) * Math.sin(degInit)) / Gravity.VALUE; + } + + public void setXInit(double newXInit) { xInit = newXInit; } + public void setYInit(double newYInit) { yInit = newYInit; } +} diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/Rect.java b/src/main/java/fr/sae/terraria/modele/entities/entity/Rect.java index 195eb13..eab0fe6 100644 --- a/src/main/java/fr/sae/terraria/modele/entities/entity/Rect.java +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/Rect.java @@ -1,25 +1,35 @@ package fr.sae.terraria.modele.entities.entity; - import javafx.geometry.Rectangle2D; + public class Rect { - private Rectangle2D rect; + private Rectangle2D value; - private int width; - private int height; + public Rect(double x, double y, int width, int height) { this.value = new Rectangle2D(x, y, width, height); } - public Rect(double x, double y, int width, int height) + /** + * Mets à jour la position du rectangle géré par JavaFX + * @param x La position du Rectangle sur l'axe des abscisses + * @param y La position du Rectangle sur l'axe des ordonnées + */ + public void updates(double x, double y) { - this.rect = new Rectangle2D(x, y, width, height); + double width = this.value.getWidth(); + double height = this.value.getHeight(); - this.width = width; - this.height = height; + this.value = new Rectangle2D(x, y, (int) width, (int) height); } - public void update(double x, double y) { this.rect = new Rectangle2D(x, y, width, height); } + /** Permet de savoir si deux rectangles sont en collision */ + public boolean collideRect(Rect rect) { return this.value.intersects(rect.get()) || this.value.contains(rect.get()); } + /** Permet de savoir si deux rectangles sont en collision */ + public boolean collideRect(Rectangle2D rect) { return this.value.intersects(rect) || this.value.contains(rect); } - public Rectangle2D get() { return this.rect; } + /** Permet d'avoir le Rectangle qui est géré par JavaFX */ + public Rectangle2D get() { return this.value; } + public int getWidth() { return (int) (this.value.getWidth()); } + public int getHeight() { return (int) (this.value.getHeight()); } } diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/ReproductiveObjectType.java b/src/main/java/fr/sae/terraria/modele/entities/entity/ReproductiveObjectType.java new file mode 100644 index 0000000..23306fe --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/ReproductiveObjectType.java @@ -0,0 +1,22 @@ +package fr.sae.terraria.modele.entities.entity; + +import fr.sae.terraria.modele.Environment; + +import java.util.List; + + +/** + * Permet de regrouper les entités qui peuvent se reproduire et d'implémenter cette fonctionnalité. + * + * @see fr.sae.terraria.modele.entities.Rabbit + * @see fr.sae.terraria.modele.blocks.TallGrass + */ +public interface ReproductiveObjectType +{ + + /** + * Reproduit les entités concernées. + * @return Les enfants de l'entité + */ + List reproduction(Environment environment); +} diff --git a/src/main/java/fr/sae/terraria/modele/entities/entity/StowableObjectType.java b/src/main/java/fr/sae/terraria/modele/entities/entity/StowableObjectType.java new file mode 100644 index 0000000..7aa87e9 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/entities/entity/StowableObjectType.java @@ -0,0 +1,10 @@ +package fr.sae.terraria.modele.entities.entity; + + +/** + * Permet de regrouper les objets qui son stockable dans l'inventaire du joueur + * + * @see fr.sae.terraria.modele.blocks.Block + * @see fr.sae.terraria.modele.tools.Tool + */ +public interface StowableObjectType {} diff --git a/src/main/java/fr/sae/terraria/modele/items/Coal.java b/src/main/java/fr/sae/terraria/modele/items/Coal.java new file mode 100644 index 0000000..33fb620 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Coal.java @@ -0,0 +1,3 @@ +package fr.sae.terraria.modele.items; + +public class Coal extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Fibre.java b/src/main/java/fr/sae/terraria/modele/items/Fibre.java new file mode 100644 index 0000000..8a27183 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Fibre.java @@ -0,0 +1,4 @@ +package fr.sae.terraria.modele.items; + + +public class Fibre extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Iron.java b/src/main/java/fr/sae/terraria/modele/items/Iron.java new file mode 100644 index 0000000..cf77836 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Iron.java @@ -0,0 +1,4 @@ +package fr.sae.terraria.modele.items; + + +public class Iron extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Item.java b/src/main/java/fr/sae/terraria/modele/items/Item.java new file mode 100644 index 0000000..d3cf6ea --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Item.java @@ -0,0 +1,6 @@ +package fr.sae.terraria.modele.items; + +import fr.sae.terraria.modele.entities.entity.StowableObjectType; + + +public class Item implements StowableObjectType { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Meat.java b/src/main/java/fr/sae/terraria/modele/items/Meat.java new file mode 100644 index 0000000..998f910 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Meat.java @@ -0,0 +1,3 @@ +package fr.sae.terraria.modele.items; + +public class Meat extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Pierre.java b/src/main/java/fr/sae/terraria/modele/items/Pierre.java new file mode 100644 index 0000000..64a3df8 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Pierre.java @@ -0,0 +1,4 @@ +package fr.sae.terraria.modele.items; + + +public class Pierre extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Silex.java b/src/main/java/fr/sae/terraria/modele/items/Silex.java new file mode 100644 index 0000000..8585133 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Silex.java @@ -0,0 +1,4 @@ +package fr.sae.terraria.modele.items; + + +public class Silex extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/items/Wood.java b/src/main/java/fr/sae/terraria/modele/items/Wood.java new file mode 100644 index 0000000..04a4b42 --- /dev/null +++ b/src/main/java/fr/sae/terraria/modele/items/Wood.java @@ -0,0 +1,3 @@ +package fr.sae.terraria.modele.items; + +public class Wood extends Item { } diff --git a/src/main/java/fr/sae/terraria/modele/tools/Axe.java b/src/main/java/fr/sae/terraria/modele/tools/Axe.java index 96c474d..3901826 100644 --- a/src/main/java/fr/sae/terraria/modele/tools/Axe.java +++ b/src/main/java/fr/sae/terraria/modele/tools/Axe.java @@ -1,9 +1,4 @@ package fr.sae.terraria.modele.tools; -public class Axe extends Tool -{ - public Axe(){ - - } -} +public class Axe extends Tool { } diff --git a/src/main/java/fr/sae/terraria/modele/tools/Bow.java b/src/main/java/fr/sae/terraria/modele/tools/Bow.java index 28f58ca..d4e5f2b 100644 --- a/src/main/java/fr/sae/terraria/modele/tools/Bow.java +++ b/src/main/java/fr/sae/terraria/modele/tools/Bow.java @@ -1,9 +1,4 @@ package fr.sae.terraria.modele.tools; -public class Bow -{ - public Bow(){ - - } -} +public class Bow { } diff --git a/src/main/java/fr/sae/terraria/modele/tools/Pickaxe.java b/src/main/java/fr/sae/terraria/modele/tools/Pickaxe.java index 60e28f5..c7c8bea 100644 --- a/src/main/java/fr/sae/terraria/modele/tools/Pickaxe.java +++ b/src/main/java/fr/sae/terraria/modele/tools/Pickaxe.java @@ -1,9 +1,4 @@ package fr.sae.terraria.modele.tools; -public class Pickaxe extends Tool -{ - public Pickaxe(){ - - } -} +public class Pickaxe extends Tool { } diff --git a/src/main/java/fr/sae/terraria/modele/tools/Sword.java b/src/main/java/fr/sae/terraria/modele/tools/Sword.java index 75fa89d..b835bfe 100644 --- a/src/main/java/fr/sae/terraria/modele/tools/Sword.java +++ b/src/main/java/fr/sae/terraria/modele/tools/Sword.java @@ -1,9 +1,4 @@ package fr.sae.terraria.modele.tools; -public class Sword -{ - public Sword(){ - - } -} +public class Sword {} diff --git a/src/main/java/fr/sae/terraria/modele/tools/Tool.java b/src/main/java/fr/sae/terraria/modele/tools/Tool.java index b3f45bb..8656601 100644 --- a/src/main/java/fr/sae/terraria/modele/tools/Tool.java +++ b/src/main/java/fr/sae/terraria/modele/tools/Tool.java @@ -1,9 +1,6 @@ package fr.sae.terraria.modele.tools; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; -public class Tool -{ - public Tool(){ - } -} +public class Tool implements StowableObjectType {} diff --git a/src/main/java/fr/sae/terraria/vue/HUDView.java b/src/main/java/fr/sae/terraria/vue/HUDView.java new file mode 100644 index 0000000..a1211ee --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/HUDView.java @@ -0,0 +1,225 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.Terraria; +import fr.sae.terraria.modele.Clock; +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.blocks.Dirt; +import fr.sae.terraria.modele.blocks.Stone; +import fr.sae.terraria.modele.blocks.TallGrass; +import fr.sae.terraria.modele.entities.Player; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.ListChangeListener; +import javafx.geometry.Rectangle2D; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Font; +import javafx.scene.transform.Rotate; + +import java.util.Objects; + + +public class HUDView +{ + private final ImageView inventoryBarImgView; + private final ImageView cursorImgView; + + private final Image inventoryBarImg; + private final Image healthBarImg; + private final Image clockImg; + private final Image clockCursorImg; + + private final Rectangle frameInventoryBar; + + private final Clock gameTime; + private final Player player; + private final Pane display; + + private double scaleMultiplicatorWidth; + private double scaleMultiplicatorHeight; + private double windowWidth; + private double windowHeight; + private int tileWidth; + private int tileHeight; + + + /** + * Affiche tout ce qui concerne l'HUD + * + * @param gameTime Pour afficher l'horloge + * @param display Sur quel pane l'HUD doit s'afficher + */ + public HUDView(Player player, Clock gameTime, Pane display, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + this.player = player; + this.display = display; + this.scaleMultiplicatorWidth = scaleMultiplicatorWidth; + this.scaleMultiplicatorHeight = scaleMultiplicatorHeight; + this.gameTime = gameTime; + + new ItemSelectedView(display, player, scaleMultiplicatorWidth, scaleMultiplicatorHeight); + + this.windowWidth = (scaleMultiplicatorWidth * Terraria.DISPLAY_RENDERING_WIDTH); + this.windowHeight = (scaleMultiplicatorHeight * Terraria.DISPLAY_RENDERING_HEIGHT); + this.tileWidth = (int) (scaleMultiplicatorWidth * TileMaps.TILE_DEFAULT_SIZE); + this.tileHeight = (int) (scaleMultiplicatorHeight * TileMaps.TILE_DEFAULT_SIZE); + + this.frameInventoryBar = new Rectangle(); + this.healthBarImg = View.loadAnImage("health.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.inventoryBarImg = View.loadAnImage("inventoryBar.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + Image cursorImg = View.loadAnImage("cursor.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.clockImg = View.loadAnImage("clock.png",scaleMultiplicatorWidth,scaleMultiplicatorHeight); + this.clockCursorImg = View.loadAnImage("clock-cursor.png",scaleMultiplicatorWidth,scaleMultiplicatorHeight); + + this.inventoryBarImgView = new ImageView(inventoryBarImg); + this.cursorImgView = new ImageView(cursorImg); + + this.refreshItemsInventoryBar(); + } + + /** Applique une bordure de couleur noire autour de la barre d'inventaire */ + private Rectangle setFrameInventoryBar(ImageView inventoryBarImgView) + { + frameInventoryBar.setWidth(inventoryBarImg.getWidth() + (2*scaleMultiplicatorWidth)); + frameInventoryBar.setHeight(inventoryBarImg.getHeight() + (2*scaleMultiplicatorHeight)); + frameInventoryBar.setX(inventoryBarImgView.getX() - scaleMultiplicatorWidth); + frameInventoryBar.setY(inventoryBarImgView.getY() - scaleMultiplicatorHeight); + + return frameInventoryBar; + } + + /** Applique sur les toutes les cases de l'inventaire des écouteurs qui permet d'actualiser les images des items */ + private void refreshItemsInventoryBar() + { + for (int i = 0; i < this.player.getInventory().size(); i++) + this.player.getInventory().get(i).addListener((ListChangeListener) c -> { + while(c.next()) + this.displayItemIntoInventoryBar(); + }); + } + + /** Affiche ou supprime les items qui rentrent ou sort de la barre d'inventaire */ + private void displayItemIntoInventoryBar() + { + int itemInventoryWidth = (int) (tileWidth/1.5); + int itemInventoryHeight = (int) (tileHeight/1.5); + + int nbElementDisplayed = Player.NB_CASES_MAX_INVENTORY/Player.NB_LINES_INVENTORY; + if (this.player.nbStacksIntoInventory() <= Player.NB_CASES_MAX_INVENTORY/Player.NB_LINES_INVENTORY) + nbElementDisplayed = this.player.nbStacksIntoInventory(); + + int compteur = 0; + for (int integer = 0 ; integer < nbElementDisplayed; integer++) { + ImageView itemView = new ImageView(); + Image item = null; + + if (this.player.getInventory().get(integer).get(0) instanceof Dirt) + item = View.loadAnImage("tiles/floor-top.png", itemInventoryWidth, itemInventoryHeight); + else if (this.player.getInventory().get(integer).get(0) instanceof Stone) + item = View.loadAnImage("tiles/rock-fill.png", itemInventoryWidth, itemInventoryHeight); + else if (this.player.getInventory().get(integer).get(0) instanceof TallGrass) + item = View.loadAnImage("tiles/tall-grass.png", itemInventoryWidth, itemInventoryHeight); + + if (!Objects.isNull(item)) { + itemView.setImage(item); + itemView.setX(inventoryBarImgView.getX() + (((inventoryBarImgView.getImage().getWidth()/9) - item.getWidth())/2) + ((inventoryBarImgView.getImage().getWidth()/9)*compteur)); + itemView.setY(inventoryBarImgView.getY() + ((inventoryBarImgView.getImage().getHeight() - item.getHeight())/2)); + + int fontSize = (int) (5*scaleMultiplicatorWidth); + Label nbObjects = new Label(); + nbObjects.setId("textInventoryBar"); + nbObjects.setFont(new Font("Arial", fontSize)); + nbObjects.setText(String.valueOf(this.player.getInventory().get(integer).size())); + nbObjects.setLayoutX(itemView.getX()); + nbObjects.setLayoutY(itemView.getY() + item.getHeight() - fontSize); + + StringProperty stringProperty = new SimpleStringProperty(String.valueOf(this.player.getInventory().get(integer).size())); + this.player.getInventory().get(integer).addListener((ListChangeListener) c -> stringProperty.setValue(String.valueOf(c.getList().size()))); + nbObjects.textProperty().bind(stringProperty); + + display.getChildren().add(itemView); + display.getChildren().add(nbObjects); + compteur++; + } + } + } + + /** Affiche la barre d'inventaire */ + public void displayInventoryBar() + { + this.inventoryBarImgView.setX(((windowWidth - inventoryBarImg.getWidth())/2)); + this.inventoryBarImgView.setY((windowHeight - inventoryBarImg.getHeight()) - tileHeight); + + display.getChildren().add(setFrameInventoryBar(inventoryBarImgView)); + display.getChildren().add(inventoryBarImgView); + } + + /** Affiche un carré qui se superpose sur la barre d'inventaire qui permet de savoir où on se situe */ + public void displayCursorInventoryBar() + { + this.cursorImgView.setX(((windowWidth - inventoryBarImg.getWidth())/2 - scaleMultiplicatorWidth)); + this.cursorImgView.setY(((windowHeight - inventoryBarImg.getHeight()) - tileHeight) - scaleMultiplicatorHeight); + + this.player.positionOfCursorInventoryBar.addListener((obs, oldV, newV) -> { + this.cursorImgView.setX(((windowWidth - inventoryBarImg.getWidth())/2 + ((inventoryBarImg.getWidth()/9) * newV.intValue() - scaleMultiplicatorWidth))); + if (newV.intValue() >= 0 && newV.intValue() < (Player.NB_CASES_MAX_INVENTORY/Player.NB_LINES_INVENTORY)) + this.player.setItemSelected((!this.player.getInventory().get(newV.intValue()).isEmpty()) ? this.player.getInventory().get(newV.intValue()).get(0) : null); + }); + + display.getChildren().add(cursorImgView); + } + + /** Affiche la barre de vie du joueur */ + public void displayHealthBar() + { + // Crée et positionne les cœurs dans un tableau de longueur qui correspond à la vie max du joueur. + ImageView[] healths = new ImageView[(int) (player.getPvMax())]; + for (int i = 0; i < player.getPvMax(); i++) { + ImageView healthView = new ImageView(healthBarImg); + Rectangle2D viewPort = new Rectangle2D((healthView.getImage().getWidth()/3)*2, 0, (healthView.getImage().getWidth()/3), healthView.getImage().getHeight()); + + healthView.setViewport(viewPort); + healthView.setX(inventoryBarImgView.getX() + ((healthView.getImage().getWidth()/3)*i)); + healthView.setY((inventoryBarImgView.getY() - healthView.getImage().getHeight()) - (2*scaleMultiplicatorHeight)); + display.getChildren().add(healthView); + healths[i] = healthView; + } + + // Modifie le cœur selon la vie du joueur + player.getPvProperty().addListener((obs, oldPv, newPv) -> { + if (oldPv.intValue() >= 0) { + ImageView healthView = healths[oldPv.intValue()-1]; + + Rectangle2D viewPort = new Rectangle2D((healthView.getImage().getWidth()/3)*0, 0, (healthView.getImage().getWidth()/3), healthView.getImage().getHeight()); + healthView.setViewport(viewPort); + } + }); + } + + /** Affiche une horloge à aiguille visuelle à l'écran. */ + public void displayClock() + { + ImageView clockCursorView = new ImageView(clockCursorImg); + ImageView clockView = new ImageView(clockImg); + Rotate rotate = new Rotate(); + double yClock = inventoryBarImgView.getY() - clockImg.getHeight(); + double xClock = inventoryBarImgView.getX() + (inventoryBarImg.getWidth()/2 - clockImg.getWidth()/2); + + clockCursorView.setX(xClock + (clockImg.getWidth()/2) - (clockCursorImg.getWidth()/2)); + clockCursorView.setY(yClock); + clockView.setX(xClock); + clockView.setY(yClock); + + rotate.setPivotX(xClock + (clockImg.getWidth()/2) - (clockCursorImg.getWidth()/2) + (clockCursorImg.getWidth()/2)); + rotate.setPivotY(yClock + clockCursorImg.getHeight()); + gameTime.minutesProperty().addListener(((obs, oldV, newV) -> rotate.setAngle((newV.intValue()/8) - 90))); + clockCursorView.getTransforms().add(rotate); + + display.getChildren().add(clockView); + display.getChildren().add(clockCursorView); + } +} diff --git a/src/main/java/fr/sae/terraria/vue/ItemSelectedView.java b/src/main/java/fr/sae/terraria/vue/ItemSelectedView.java new file mode 100644 index 0000000..82122da --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/ItemSelectedView.java @@ -0,0 +1,79 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.blocks.Dirt; +import fr.sae.terraria.modele.blocks.Stone; +import fr.sae.terraria.modele.entities.Player; +import fr.sae.terraria.modele.entities.entity.StowableObjectType; +import fr.sae.terraria.modele.items.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Pane; + + + +public class ItemSelectedView +{ + private ImageView itemSelectedImgView; + + private Image stoneItemImg; + private Image dirtItemImg; + private Image coalItemImg; + private Image fibreItemImg; + private Image ironItemImg; + private Image pierreItemImg; + private Image silexItemImg; + private Image meatItemImg; + private Image woodItemImg; + + + public ItemSelectedView(Pane display, Player player, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + int widthTile = (int) (scaleMultiplicatorWidth * TileMaps.TILE_DEFAULT_SIZE); + int heightTile = (int) (scaleMultiplicatorHeight * TileMaps.TILE_DEFAULT_SIZE); + int widthItem = widthTile/2; + int heightItem = heightTile/2; + + this.itemSelectedImgView = new ImageView(); + this.dirtItemImg = View.loadAnImage("tiles/floor-top.png", widthItem, heightItem); + this.stoneItemImg = View.loadAnImage("tiles/rock-fill.png", widthItem, heightItem); + this.coalItemImg = View.loadAnImage("loots/coal.png", widthItem, heightItem); + this.fibreItemImg = View.loadAnImage("loots/fibre.png", widthItem, heightItem); + this.ironItemImg = View.loadAnImage("loots/iron.png", widthItem, heightItem); + this.pierreItemImg = View.loadAnImage("loots/pierre.png", widthItem, heightItem); + this.silexItemImg = View.loadAnImage("loots/silex.png", widthItem, heightItem); + this.meatItemImg = View.loadAnImage("loots/viande.png", widthItem, heightItem); + this.woodItemImg = View.loadAnImage("loots/wood.png", widthItem, heightItem); + + player.positionOfCursorInventoryBar.addListener((obs, oldItemSelected, newItemSelected) -> { + StowableObjectType item = player.getItemSelected(); + + if (item instanceof Dirt) + itemSelectedImgView.setImage(dirtItemImg); + else if (item instanceof Stone) + itemSelectedImgView.setImage(stoneItemImg); + else if (item instanceof Coal) + itemSelectedImgView.setImage(coalItemImg); + else if (item instanceof Fibre) + itemSelectedImgView.setImage(fibreItemImg); + else if (item instanceof Iron) + itemSelectedImgView.setImage(ironItemImg); + else if (item instanceof Pierre) + itemSelectedImgView.setImage(pierreItemImg); + else if (item instanceof Silex) + itemSelectedImgView.setImage(silexItemImg); + else if (item instanceof Meat) + itemSelectedImgView.setImage(meatItemImg); + else if (item instanceof Wood) + itemSelectedImgView.setImage(woodItemImg); + else itemSelectedImgView.setImage(null); + }); + + display.addEventFilter(MouseEvent.MOUSE_MOVED, mouse -> { + itemSelectedImgView.setX(mouse.getX()); + itemSelectedImgView.setY(mouse.getY()); + }); + display.getChildren().add(itemSelectedImgView); + } +} diff --git a/src/main/java/fr/sae/terraria/vue/MouseCursorView.java b/src/main/java/fr/sae/terraria/vue/MouseCursorView.java new file mode 100644 index 0000000..a763660 --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/MouseCursorView.java @@ -0,0 +1,42 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.modele.TileMaps; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; + + +public class MouseCursorView +{ + + + /** + * Un rectangle rouge qui suit la souris + * Permet de savoir où nous cliquons sur l'écran plus précisément sur quel tile + * + * @param display L'afficheur qui se gère du HUD + * @param scaleMultiplicatorWidth Scaling en largeur + * @param scaleMultiplicatorHeight Scaling en hauteur + */ + public MouseCursorView(Pane display, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + int tileWidth = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicatorWidth); + int tileHeight = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicatorHeight); + Rectangle mouseCursorRect = new Rectangle(tileWidth, tileHeight); + + mouseCursorRect.setFill(Color.TRANSPARENT); + mouseCursorRect.setStroke(Color.RED); + mouseCursorRect.setStrokeWidth(2*scaleMultiplicatorWidth); + + display.addEventFilter(MouseEvent.MOUSE_MOVED, mouse -> { + int xCursor = (int) (mouse.getX()/tileWidth) * tileWidth; + int yCursor = (int) (mouse.getY()/tileHeight) * tileHeight; + + mouseCursorRect.setX(xCursor); + mouseCursorRect.setY(yCursor); + + }); + display.getChildren().add(mouseCursorRect); + } +} diff --git a/src/main/java/fr/sae/terraria/vue/PlayerView.java b/src/main/java/fr/sae/terraria/vue/PlayerView.java new file mode 100644 index 0000000..e7ca455 --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/PlayerView.java @@ -0,0 +1,69 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.modele.entities.Player; +import javafx.geometry.Rectangle2D; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; + + +public class PlayerView +{ + private final ImageView playerImgView; + + private final Image playerMoveRightImg; + private final Image playerMoveLeftImg; + private final Image playerIdleImg; + + private final Player player; + + private int widthPlayer; + private int heightPlayer; + + + public PlayerView(Player player, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + this.player = player; + + this.playerIdleImg = View.loadAnImage("sprites/player/player_idle.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.playerMoveRightImg = View.loadAnImage("sprites/player/player_moveRight.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.playerMoveLeftImg = View.loadAnImage("sprites/player/player_moveLeft.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + + this.widthPlayer = (int) this.playerIdleImg.getWidth(); + this.heightPlayer = (int) this.playerIdleImg.getHeight(); + + this.playerImgView = View.createImageView(player, playerIdleImg); + } + + /** Applique l'animation sur le joueur */ + private void setAnimation() + { + // Change la limite de frame de l'animation selon le sprite sheet chargé + this.playerImgView.imageProperty().addListener((obs, oldImg, newImg) -> { + int newEndFrame = (int) (newImg.getWidth() / widthPlayer); + if (this.player.getAnimation().getFrame() >= newEndFrame) + this.player.getAnimation().reset(); + this.player.getAnimation().setEndFrame(newEndFrame); + }); + + player.getAnimation().getFrameProperty().addListener((obs, oldFrame, newFrame) -> { + this.playerImgView.setViewport(new Rectangle2D(0, 0, widthPlayer, heightPlayer)); + if (player.offset[0] == 0 && player.offset[1] == 0) + this.playerImgView.setImage(this.playerIdleImg); + + if (player.offset[0] == 1 || player.offset[0] == -1) { + Rectangle2D frameRect = new Rectangle2D((newFrame.intValue() * widthPlayer), 0, widthPlayer, heightPlayer); + + this.playerImgView.setViewport(frameRect); + this.playerImgView.setImage((player.offset[0] == -1) ? playerMoveLeftImg : playerMoveRightImg); + } + }); + } + + /** Synchronise les coordonnées en x et y du joueur avec l'image et ensuite l'affiche sur le Pane */ + public void displayPlayer(Pane display) + { + this.setAnimation(); + display.getChildren().add(playerImgView); + } +} diff --git a/src/main/java/fr/sae/terraria/vue/RabbitView.java b/src/main/java/fr/sae/terraria/vue/RabbitView.java new file mode 100644 index 0000000..e511271 --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/RabbitView.java @@ -0,0 +1,62 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.entities.Rabbit; +import javafx.geometry.Rectangle2D; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; + + +public class RabbitView +{ + private final ImageView rabbitImgView; + + private final Image rabbitLeftImg; + private final Image rabbitRightImg; + + private final Rabbit rabbit; + + private int widthTile; + private int heightTile; + + + public RabbitView(Rabbit rabbit, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + this.rabbit = rabbit; + + this.widthTile = (int) (scaleMultiplicatorWidth * TileMaps.TILE_DEFAULT_SIZE); + this.heightTile = (int) (scaleMultiplicatorHeight * TileMaps.TILE_DEFAULT_SIZE); + + this.rabbitLeftImg = View.loadAnImage("sprites/rabbit/rabbit_left.png", widthTile*4, heightTile); + this.rabbitRightImg = View.loadAnImage("sprites/rabbit/rabbit_right.png", widthTile*4, heightTile); + this.rabbitImgView = View.createImageView(rabbit, rabbitLeftImg); + } + + private void setAnimation() + { + // Change la limite de frame de l'animation selon le sprite sheet chargé + this.rabbitImgView.imageProperty().addListener((obs, oldImg, newImg) -> { + int newEndFrame = (int) (newImg.getWidth() / widthTile); + if (this.rabbit.getAnimation().getFrame() >= newEndFrame) + this.rabbit.getAnimation().reset(); + this.rabbit.getAnimation().setEndFrame(newEndFrame); + }); + + this.rabbit.getAnimation().getFrameProperty().addListener((obs, oldFrame, newFrame) -> { + this.rabbitImgView.setViewport(new Rectangle2D(0, 0, widthTile, heightTile)); + if (rabbit.offset[0] == 1 || rabbit.offset[0] == -1) { + Rectangle2D frameRect = new Rectangle2D((newFrame.intValue() * widthTile), 0, widthTile, heightTile); + + rabbitImgView.setViewport(frameRect); + rabbitImgView.setImage((rabbit.offset[0] == -1) ? rabbitLeftImg : rabbitRightImg); + } + }); + } + + public void displayRabbit(Pane display) + { + this.setAnimation(); + display.getChildren().add(rabbitImgView); + } +} diff --git a/src/main/java/fr/sae/terraria/vue/TileMapsView.java b/src/main/java/fr/sae/terraria/vue/TileMapsView.java new file mode 100644 index 0000000..1c0fa09 --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/TileMapsView.java @@ -0,0 +1,203 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.TileMaps; +import fr.sae.terraria.modele.blocks.Dirt; +import fr.sae.terraria.modele.blocks.Stone; +import fr.sae.terraria.modele.blocks.TallGrass; +import fr.sae.terraria.modele.blocks.Tree; +import fr.sae.terraria.modele.entities.Rabbit; +import fr.sae.terraria.modele.entities.entity.Entity; +import javafx.collections.ListChangeListener; +import javafx.geometry.Rectangle2D; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; + +import java.time.Clock; +import java.util.ArrayList; +import java.util.List; + + +public class TileMapsView +{ + private Pane display; + + private Environment environment; + + private int tileWidth; + private int tileHeight; + private Clock clock; + + private Image floorTopImg; + private Image floorLeftImg; + private Image floorRightImg; + private Image treeImg; + private Image stoneImg; + private Image dirtImg; + private Image tallGrassImg; + + + public TileMapsView(Environment environment, Pane display, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + this.environment = environment; + this.display = display; + + this.tileHeight = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicatorHeight); + this.tileWidth = (int) (TileMaps.TILE_DEFAULT_SIZE * scaleMultiplicatorWidth); + + this.floorTopImg = View.loadAnImage("tiles/floor-top.png", tileWidth, tileHeight); + this.floorLeftImg = View.loadAnImage("tiles/floor-left.png", tileWidth, tileHeight); + this.floorRightImg = View.loadAnImage("tiles/floor-right.png", tileWidth, tileHeight); + this.stoneImg = View.loadAnImage("tiles/rock-fill.png", tileWidth, tileHeight); + this.dirtImg = View.loadAnImage("tiles/dirt-top.png", tileWidth, tileHeight); + this.treeImg = View.loadAnImage("sprites/tree-sheet.png", scaleMultiplicatorWidth, scaleMultiplicatorHeight); + this.tallGrassImg = View.loadAnImage("tiles/tall-grass.png",tileWidth,tileHeight); + + + + + environment.getEntities().addListener((ListChangeListener) c -> { + + while (c.next()) if (c.wasAdded()) { + if (c.getList().get(0) instanceof Tree) + createTree((Tree) c.getList().get(0)); + if (c.getList().get(0) instanceof TallGrass) + createTallGrass((TallGrass) c.getList().get(0)); + if (c.getList().get(0) instanceof Rabbit) { + RabbitView rabbitView = new RabbitView((Rabbit) c.getList().get(0), scaleMultiplicatorWidth, scaleMultiplicatorHeight); + rabbitView.displayRabbit(display); + } if (c.getList().get(0) instanceof Dirt) + display.getChildren().add(View.createImageView(c.getList().get(0), floorTopImg)); + if (c.getList().get(0) instanceof Stone) + display.getChildren().add(View.createImageView(c.getList().get(0), stoneImg)); + } + }); + } + + public void displayMaps(TileMaps tiles) + { + for (int y = 0; y < tiles.getHeight() ; y++) + for (int x = 0 ; x < tiles.getWidth() ; x++) + switch (tiles.getTile(x, y)) + { + case TileMaps.STONE: + this.createStone(x, y); + break; + case TileMaps.DIRT: + this.createDirt(x, y); + break; + case TileMaps.FLOOR_TOP: + case TileMaps.FLOOR_LEFT: + case TileMaps.FLOOR_RIGHT: + this.createFloor(tiles.getTile(x, y), x, y); + break; + default: + this.errorTile(tiles.getTile(x, y)); + break; + } + } + + private void createTree(Tree tree) + { + List imagesTree = new ArrayList<>(); + + int nbFoliage = ((int) (Math.random()*2))+1; + int nbTrunk = ((int) (Math.random()*3))+1; + + Rectangle2D viewportFirstFrame = new Rectangle2D(0, 0, tileWidth, tileHeight); + ImageView firstFrameView = new ImageView(); + firstFrameView.setImage(treeImg); + firstFrameView.setViewport(viewportFirstFrame); + imagesTree.add(firstFrameView); + for (int f = 0; f < nbFoliage; f++) { + Rectangle2D viewportSecondFrame = new Rectangle2D(0, tileHeight, tileWidth, tileHeight); + ImageView secondFrameView = new ImageView(); + secondFrameView.setImage(treeImg); + secondFrameView.setViewport(viewportSecondFrame); + imagesTree.add(secondFrameView); + } + + if (nbTrunk > 1) { + Rectangle2D viewportEndTrunk = new Rectangle2D(0, (tileHeight*2), tileWidth, tileHeight); + ImageView endTrunkView = new ImageView(); + endTrunkView.setImage(treeImg); + endTrunkView.setViewport(viewportEndTrunk); + imagesTree.add(endTrunkView); + + for (int t = 0; t < nbTrunk-1; t++) { + Rectangle2D viewportTrunk = new Rectangle2D(tileWidth, (tileHeight*2), tileWidth, tileHeight); + ImageView trunkView = new ImageView(); + trunkView.setImage(treeImg); + trunkView.setViewport(viewportTrunk); + imagesTree.add(trunkView); + } + } else { + Rectangle2D viewportTrunk = new Rectangle2D(0, (tileHeight*2), tileWidth, tileHeight); + ImageView trunkView = new ImageView(); + trunkView.setImage(treeImg); + trunkView.setViewport(viewportTrunk); + imagesTree.add(trunkView); + } + Rectangle2D viewportTrunkFoot = new Rectangle2D(0, (tileHeight*3), tileWidth, tileHeight); + ImageView trunkFootView = new ImageView(); + trunkFootView.setImage(treeImg); + trunkFootView.setViewport(viewportTrunkFoot); + imagesTree.add(trunkFootView); + + for (int i = 0; i < imagesTree.size(); i++) { + ImageView treeView = imagesTree.get(i); + + treeView.setY((int) (((tree.getY() + tileHeight) + (i * tileHeight)) - (tileHeight * imagesTree.size()))); + treeView.setX((int) tree.getX()); + + display.getChildren().add(treeView); + } + + tree.setRect(tileWidth, (2+nbFoliage+nbTrunk)*tileHeight); + } + + private void createTallGrass(TallGrass tallGrass) + { + ImageView tallGrassView = new ImageView(tallGrassImg); + tallGrass.setRect(tileWidth, tileHeight); + tallGrassView.setX(tallGrass.getX()); + tallGrassView.setY(tallGrass.getY()); + + // L'animation de la pousse de la haute herbe + tallGrass.getTallGrassGrowthProperty().addListener(((observable, oldValue, newValue) -> { + tallGrassView.setViewport(new Rectangle2D(0, 0, tallGrassImg.getWidth(), (newValue.intValue() < 1) ? 1 : (tallGrassImg.getHeight()/TallGrass.GROWTH_TALL_GRASS_STEP)*newValue.intValue())); + tallGrassView.setY((tallGrass.getY() - (tallGrassImg.getHeight()/TallGrass.GROWTH_TALL_GRASS_STEP)*newValue.intValue()) + tileHeight); + })); + + display.getChildren().add(tallGrassView); + } + + private void createStone(int x, int y) + { + Stone stoneEntity = new Stone(x*tileWidth, y*tileHeight); + stoneEntity.setRect(tileWidth, tileHeight); + display.getChildren().add(View.createImageView(stoneEntity, stoneImg)); + environment.getEntities().add(stoneEntity); + } + + private void createDirt(int x, int y) + { + Dirt dirtSprite = new Dirt(x*tileWidth, y*tileHeight); + dirtSprite.setRect(tileWidth, tileHeight); + display.getChildren().add(View.createImageView(dirtSprite, dirtImg)); + environment.getEntities().add(dirtSprite); + } + + private void createFloor(int typeOfFloor, int x, int y) + { + Dirt floorEntity = new Dirt(x*tileWidth, y*tileHeight); + Image floorImg = (typeOfFloor == TileMaps.FLOOR_TOP) ? floorTopImg : (typeOfFloor == TileMaps.FLOOR_RIGHT) ? floorRightImg : floorLeftImg; + floorEntity.setRect(tileWidth, tileHeight); + display.getChildren().add(View.createImageView(floorEntity, floorImg)); + + environment.getEntities().add(floorEntity); + } + + private void errorTile(int tile) { if (tile != TileMaps.SKY) System.out.println("Le tile '" + tile + "' n'est pas reconnu."); } +} diff --git a/src/main/java/fr/sae/terraria/vue/View.java b/src/main/java/fr/sae/terraria/vue/View.java new file mode 100644 index 0000000..f87de40 --- /dev/null +++ b/src/main/java/fr/sae/terraria/vue/View.java @@ -0,0 +1,87 @@ +package fr.sae.terraria.vue; + +import fr.sae.terraria.Terraria; +import fr.sae.terraria.modele.Environment; +import fr.sae.terraria.modele.entities.entity.Entity; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; + +import java.io.File; +import java.net.URL; + + +public class View +{ + + + /** + * Cette classe lors de l'initialisation, crée et génére toutes les views du jeux + * Contient des fonctions essentiels au chargement des images et des creations de vue + * + * @param environment - + * @param displayTiledMap Le pane qui se charge d'afficher la carte + * @param displayHUD Le pane qui se charge d'afficher les elements du HUD + * @param scaleMultiplicatorWidth Le multiplicateur en largeur qui permet de redimensionner les images + * @param scaleMultiplicatorHeight Le multiplicateur en hauteur qui permet de redimensionner les images + */ + public View(Environment environment, + Pane displayTiledMap, + Pane displayHUD, + double scaleMultiplicatorWidth, + double scaleMultiplicatorHeight) + { + TileMapsView tileMapsView = new TileMapsView(environment, displayTiledMap, scaleMultiplicatorWidth, scaleMultiplicatorHeight); + tileMapsView.displayMaps(environment.getTileMaps()); + + PlayerView playerView = new PlayerView(environment.getPlayer(), scaleMultiplicatorWidth, scaleMultiplicatorHeight); + playerView.displayPlayer(displayHUD); + + HUDView hudView = new HUDView(environment.getPlayer(), environment.getGameClock(), displayHUD, scaleMultiplicatorWidth, scaleMultiplicatorHeight); + hudView.displayInventoryBar(); + hudView.displayCursorInventoryBar(); + hudView.displayHealthBar(); + hudView.displayClock(); + + new MouseCursorView(displayHUD, scaleMultiplicatorWidth, scaleMultiplicatorHeight); + } + + /** Essaye de trouver et de charger l'image sinon renvoie null */ + private static Image foundImage(String path) + { + Image img = null; + try { + URL pathImg = Terraria.class.getResource(path).toURI().toURL(); + if (pathImg == null) + pathImg = new File(Terraria.srcPath + path).toURI().toURL(); + img = new Image(pathImg.toString()); + } catch (Exception ignored) {} + + return img; + } + + /** Charge une image avec une resolution carré (Ex: 16x16) */ + public static Image loadAnImage(String path, int tileWidth, int tileHeight) { return new Image(View.foundImage(path).getUrl(), tileWidth, tileHeight, false, false, false); } + + /** Charge une image avec une resolution non carrée */ + public static Image loadAnImage(String path, double scaleMultiplicatorWidth, double scaleMultiplicatorHeight) + { + Image img = View.foundImage(path); + double width = img.getWidth(); + double height = img.getHeight(); + img.cancel(); + + double widthScaled = width*scaleMultiplicatorWidth; + double heightScaled = height*scaleMultiplicatorHeight; + return new Image(img.getUrl(), widthScaled, heightScaled, false, false, false); + } + + public static ImageView createImageView(Entity entity, Image img) + { + ImageView imageView = new ImageView(img); + imageView.translateXProperty().bind(entity.getXProperty()); + imageView.translateYProperty().bind(entity.getYProperty()); + + return imageView; + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 7b01f17..c9c616d 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -10,4 +10,8 @@ opens fr.sae.terraria.controller to javafx.fxml; exports fr.sae.terraria.modele; opens fr.sae.terraria.modele to javafx.fxml; + exports fr.sae.terraria.modele.entities; + opens fr.sae.terraria.modele.entities to javafx.fxml; + exports fr.sae.terraria.modele.entities.entity; + opens fr.sae.terraria.modele.entities.entity to javafx.fxml; } \ No newline at end of file diff --git a/src/main/resources/fr/sae/terraria/clock-cursor.png b/src/main/resources/fr/sae/terraria/clock-cursor.png new file mode 100644 index 0000000..7303d26 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/clock-cursor.png differ diff --git a/src/main/resources/fr/sae/terraria/clock.png b/src/main/resources/fr/sae/terraria/clock.png new file mode 100644 index 0000000..7939356 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/clock.png differ diff --git a/src/main/resources/fr/sae/terraria/cursor.png b/src/main/resources/fr/sae/terraria/cursor.png new file mode 100644 index 0000000..73efa5f Binary files /dev/null and b/src/main/resources/fr/sae/terraria/cursor.png differ diff --git a/src/main/resources/fr/sae/terraria/health.png b/src/main/resources/fr/sae/terraria/health.png new file mode 100644 index 0000000..80f4e7e Binary files /dev/null and b/src/main/resources/fr/sae/terraria/health.png differ diff --git a/src/main/resources/fr/sae/terraria/inventoryBar.png b/src/main/resources/fr/sae/terraria/inventoryBar.png new file mode 100644 index 0000000..83aca35 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/inventoryBar.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/coal.png b/src/main/resources/fr/sae/terraria/loots/coal.png new file mode 100644 index 0000000..d538fef Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/coal.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/fibre.png b/src/main/resources/fr/sae/terraria/loots/fibre.png new file mode 100644 index 0000000..c462063 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/fibre.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/iron.png b/src/main/resources/fr/sae/terraria/loots/iron.png new file mode 100644 index 0000000..c1bae97 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/iron.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/pierre.png b/src/main/resources/fr/sae/terraria/loots/pierre.png new file mode 100644 index 0000000..c3d71d8 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/pierre.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/silex.png b/src/main/resources/fr/sae/terraria/loots/silex.png new file mode 100644 index 0000000..3134a55 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/silex.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/viande.png b/src/main/resources/fr/sae/terraria/loots/viande.png new file mode 100644 index 0000000..45a4aff Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/viande.png differ diff --git a/src/main/resources/fr/sae/terraria/loots/wood.png b/src/main/resources/fr/sae/terraria/loots/wood.png new file mode 100644 index 0000000..0f4a952 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/loots/wood.png differ diff --git a/src/main/resources/fr/sae/terraria/maps/map_0.json b/src/main/resources/fr/sae/terraria/maps/map_0.json index 8ec3894..cd875b6 100644 --- a/src/main/resources/fr/sae/terraria/maps/map_0.json +++ b/src/main/resources/fr/sae/terraria/maps/map_0.json @@ -4,12 +4,12 @@ "2": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "3": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "4": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "5": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "6": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "7": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "8": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - "9": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0], - "10": [4,5,0,0,0,0,0,0,0,0,0,0,0,0,4,2,2,5,0,0,0,0,0,0,0,0,0,0,0,0], + "5": [0,0,0,0,0,0,4,3,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "6": [0,0,0,0,0,4,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "7": [0,0,0,0,0,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "8": [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "9": [0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0], + "10": [3,5,0,0,0,0,0,0,0,0,0,0,0,0,4,2,2,5,0,0,0,0,0,0,0,0,0,0,0,0], "11": [2,2,3,5,0,0,0,0,0,0,4,3,3,3,2,1,1,2,3,3,5,0,0,0,0,0,0,0,0,0], "12": [1,1,2,2,3,3,3,3,3,3,2,2,2,2,1,1,1,1,2,2,2,3,3,3,5,0,4,3,3,3], "13": [1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,3,2,2,2,2], diff --git a/src/main/resources/fr/sae/terraria/sprites/arrow.png b/src/main/resources/fr/sae/terraria/sprites/arrow.png new file mode 100644 index 0000000..0ae411a Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/arrow.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/player/player_idle.png b/src/main/resources/fr/sae/terraria/sprites/player/player_idle.png index a69f97d..df371ad 100644 Binary files a/src/main/resources/fr/sae/terraria/sprites/player/player_idle.png and b/src/main/resources/fr/sae/terraria/sprites/player/player_idle.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/player/player_moveLeft.png b/src/main/resources/fr/sae/terraria/sprites/player/player_moveLeft.png new file mode 100644 index 0000000..c875698 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/player/player_moveLeft.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/player/player_moveRight.png b/src/main/resources/fr/sae/terraria/sprites/player/player_moveRight.png new file mode 100644 index 0000000..f45e1c7 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/player/player_moveRight.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_left.png b/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_left.png new file mode 100644 index 0000000..46f9f3c Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_left.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_right.png b/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_right.png new file mode 100644 index 0000000..c712903 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/rabbit/rabbit_right.png differ diff --git a/src/main/resources/fr/sae/terraria/sprites/tree-sheet.png b/src/main/resources/fr/sae/terraria/sprites/tree-sheet.png new file mode 100644 index 0000000..77a150d Binary files /dev/null and b/src/main/resources/fr/sae/terraria/sprites/tree-sheet.png differ diff --git a/src/main/resources/fr/sae/terraria/tiles/tall-grass.png b/src/main/resources/fr/sae/terraria/tiles/tall-grass.png new file mode 100644 index 0000000..3675196 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/tiles/tall-grass.png differ diff --git a/src/main/resources/fr/sae/terraria/tiles/torch.png b/src/main/resources/fr/sae/terraria/tiles/torch.png new file mode 100644 index 0000000..b70b372 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/tiles/torch.png differ diff --git a/src/main/resources/fr/sae/terraria/tools/bow.png b/src/main/resources/fr/sae/terraria/tools/bow.png new file mode 100644 index 0000000..f9a12c2 Binary files /dev/null and b/src/main/resources/fr/sae/terraria/tools/bow.png differ diff --git a/src/main/resources/fr/sae/terraria/tools/pickaxe.png b/src/main/resources/fr/sae/terraria/tools/pickaxe.png new file mode 100644 index 0000000..596520e Binary files /dev/null and b/src/main/resources/fr/sae/terraria/tools/pickaxe.png differ diff --git a/src/main/resources/fr/sae/terraria/tools/sword.png b/src/main/resources/fr/sae/terraria/tools/sword.png new file mode 100644 index 0000000..599eeea Binary files /dev/null and b/src/main/resources/fr/sae/terraria/tools/sword.png differ diff --git a/src/main/resources/fr/sae/terraria/vue/game.css b/src/main/resources/fr/sae/terraria/vue/game.css index d87cf98..c81dcde 100644 --- a/src/main/resources/fr/sae/terraria/vue/game.css +++ b/src/main/resources/fr/sae/terraria/vue/game.css @@ -14,4 +14,9 @@ { -fx-fill: white; -fx-font-size: 23px; +} + +#textInventoryBar +{ + -fx-text-fill: white; } \ No newline at end of file diff --git a/src/main/resources/fr/sae/terraria/vue/game.fxml b/src/main/resources/fr/sae/terraria/vue/game.fxml index 7529a44..d2279b7 100644 --- a/src/main/resources/fr/sae/terraria/vue/game.fxml +++ b/src/main/resources/fr/sae/terraria/vue/game.fxml @@ -1,35 +1,41 @@ - + - + xmlns="http://javafx.com/javafx/11" + xmlns:fx="http://javafx.com/fxml/1"> - + - + text="Groupe: BOUCHE Antoine, CHRZASZCZ Naulan, NARCISO Tiago" />
- + + + + + +