Skip to content

GHManu/Game

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SimpleGame

Semplice gioco, con un limite da 500 righe(questo gioco ne ha circa 407), sviluppato con la libreria grafica javafx; IDE: IntelliJ IDEA

Screenshot del gioco

Descrizione

Sconfiggi il nemico con dei proiettili, mirando e sparando con il mouse e muovendoti in 8 direzioni! Attenzione: il nemico non starà fermo a guardare! Utilizza lo sprint e non avvicinarti troppo al nemico, se vuoi vivere a lungo... Gameplay

Codice e Struttura

Il gioco è composto da 9 classi(esclusa GameApplication) e una interfaccia:

  1. Player
    • rappresenta il Player con cui l'utente interagisce
  2. Enemy
    • rappresenta il nemico da sconfiggere
  3. GameUpdate
    • rappresenta il cuore del gioco, dove si ha il loop e si controllano tutti gli aspetti legati all'esecuzione del gioco
  4. Projectile
    • rappresentano i colpi che ha a disposizione il Player e l'Enemy
  5. Character
    • rappresenta un personaggio astratto
  6. CharacterPlayable
    • rappresenta un personaggio astratto giocabile
  7. Entity
    • rappresenta ogni oggetto, personaggio, ecc... qualsiasi cosa del gioco
  8. Collider
    • rappresenta il collider che ha ogni oggetto e personaggio
  9. ScreenSettings
    • rappresenta le caratteristiche per la finestra di gioco
  10. GameScene
    • Rappresenta la scena del gioco
  11. GameApplication
    • rappresenta la classe di inizio del gioco

GameApplication

In questa classe imposto lo scheletro dell'applicazione; imposto il Group, al quale attccherò tutti i componenti del gioco, la Scene con la mia classe GameScene per settare il mondo di gioco e infine dato che estendo la classe Application ho uno stage predefinito, nel quale setto la scena,la faccio apparire a schermo e istanzio l'oggetto GameUpdate, il quale inizierà il cosiddetto loop del gioco, cioè un metodo che viene chiamato ad ogni frame.

    public class GameApplication extends Application {
    //8 righe
    @Override
    public void start(Stage stage) throws Exception {
        //Parent root = FXMLLoader.load(getClass().getResource("Prova.fxml"));
        Group root = new Group();
        GameScene gameScene = new GameScene(root,GameScene.screenWidth, GameScene.screenHeight, Color.BLACK);
        //stage.setFullScreen(true);
        stage.setScene(gameScene);
        stage.show();
        GameUpdate gameUpdate = new GameUpdate(root);
        gameUpdate.startGameLoop(gameScene, root); //corpo del gioco
        stage.setResizable(false);
        stage.setOnCloseRequest(event -> System.exit(0));  //quando chiudo con la x, termina anche l'esecuzione, lo stato !=0 indica un
        // uscita non normale
    }
    public static void main(String[] args){
        launch();   //lavora con i thread
    }
}

GameScene

Imposto la scena con dei parametri fissati da me nell'interfaccia ScreenSettings, richiamando il costruttore di Scene.

public class GameScene extends Scene implements ScreenSettings{
    public GameScene(Parent parent, double width, double height, Paint colorBackground) {
        super(parent,width, height, colorBackground);
    }
}

ScreenSettings

Settaggi per la grandezza della scena.

   public interface ScreenSettings{
    //static e final sono ridondanti per le interfacce
    //cioè tutte le immagini (player, alberi, ecc...) saranno 16x16 pixel
    //dobbiamo scegliere una risoluzione giusta, perchè ad esempio il nostro 16x16 pixel con la 1920x1080 risulterà piccolo
    //quindi scegliamone una molto minore, ma ci servirà scalarla poichè il monitor avrà la risoluzione alta
    int initialSizeTile = 16;  //sarà la dimensione standard dei vari assets
    int scale = 3;    //16*3=48

    int maxScreenWidth = 16;
    int maxScreenHeight = 12;

    int sizeTile = initialSizeTile*scale;  //48x48, con questo ci faremo l'immagine del player e tutte le altre PERò
    //dell'imageView ovvero del contenitore
    // che deve essere 48x48
    int screenWidth = sizeTile * maxScreenWidth;  //768 pixel
    int screenHeight = sizeTile * maxScreenHeight;    //576 pixel
}

GameUpdate

Il metodo startGameLoop() aggiunge come "figlie" i vari componenti grafici al gruppo root e fa iniziare l'esecuzione del Thread con il metodo start(), il quale richiama run() in automatico, ovvero l'esecuzione del Thread; nel metodo run() ci sarà il loop del gioco, il codice che va aeseguito ogni frame, così da aggiornaere movimenti, vita, ecc...; questo ciclo l'ho creato usando il concetto di deltatime ovvero il tempo trascorso tra un fotogramma (frame) e l’altro durante l’esecuzione del gioco, serve a rendere il comportamento del gioco indipendente dal frame rate (messo come costante 60 FPS) e l'ho calcolato grazie al tempo di creazione del Thread, così so di quanto spostare un immagine a schermo. I due metodi principali sono gameMethodMovementHandler() e gameMethodAttackHandler() che gestiscono rispettivamente il movimento e l'attacco del Player con dei gestori degli eventi. kill_Enemy() e player_Died() sono rispetivamente per la morte del nemico e del player. L'attacco del Player si basa su dove era il cursore al momento del click. Il movimento avviene con WASD o con le frecce e in 8 versi.

public class GameUpdate implements Runnable{
    private Player plr;
    Thread currentThread;   //per tenere conto del tempo del processo
    GameScene gameScene;
    final float FPS = 60; //Frame Per Second
    Enemy enemy;


    public GameUpdate(Group root){
        currentThread = new Thread(this);
        plr = new Player();
        enemy = new Enemy();

    }


    //inizializzare le varie cose
    public void startGameLoop(GameScene gameScene, Group root){
        plr.setRoot(root);

        root.getChildren().addAll(plr.vBox,plr.cld.ret, plr.imgView); //per far si che l'immagine stia sopra al rettangolo
        this.gameScene = gameScene;
        root.getChildren().addAll(enemy.vBox, enemy.cld.ret, enemy.imgView);
        currentThread.start(); //chiama implicitamente run, eseguo il processo
        plr.setEnemy(enemy);

    }

    @Override
    public void run() { //processo in esecuzione
        /*
        Il deltaTime rappresenta il tempo trascorso tra due frame consecutivi, e serve a rendere il movimento indipendente
        dal frame rate. In parole semplici: se il gioco va a 30 FPS o 60 FPS, il player si muoverà alla stessa velocità percepita.
        * */
        double deltatime = 0;
        long currentTime;    //tempo corrente del processo
        long lastUpdate = System.currentTimeMillis();
        //creo un Set di KeyCode, per salvare tutti gli eventi relativi all'input da tastiera
        Set<KeyCode> keysPressed = new HashSet<>();



        //gestisco gli eventi e aggiungo/rimuovo il codice del tasto premuto nel mio Set
        //event -> è la dichiarazione di un parametro che la lambda riceve (in questo caso, è un oggetto KeyEvent).
        //keysPressed.add(event.getCode()); è il corpo della lambda.
        //Non c'è bisogno di dichiarare esplicitamente event da parte tua, perché è fornito automaticamente dal metodo setOnKeyPressed
        //EventHandler<KeyEvent> è l'interfaccia che viene implementata per gestire l'evento,
        // ma l'oggetto che viene passato alla lambda è di tipo KeyEvent (che è l'oggetto che contiene i dettagli dell'evento di tastiera
        //quindi tutto questo: event -> keysPressed.add(event.getCode()) è un EventHandler<KeyEvent>
        if(plr.progressBar.getProgress() > 0.1) gameScene.setOnKeyPressed((event) -> keysPressed.add(event.getCode()));
        if(plr.progressBar.getProgress() > 0.1) gameScene.setOnKeyReleased(event -> keysPressed.remove(event.getCode()));


        //gameLoop
        while(currentThread.isAlive()){
            currentTime = System.currentTimeMillis();
            //(currentTime - lastUpdate) è il tempo passato tra due frame
            //1000 / FPS → è la durata ideale di un frame, sempre in millisecondi (es: 1000 / 60 = 16.67ms).
            /*Quindi stai dicendo:
                “Quanto tempo è passato rispetto a quanto dovrebbe passare?”
               È un valore relativo, utile per capire quando è il momento di aggiornare il gioco.
            * */
            //System.out.println(currentTime);
            deltatime += (currentTime - lastUpdate) / (1000.0 / FPS);
            lastUpdate = currentTime;
            //System.out.println(lastUpdate);
            if(deltatime >= 1){ //un secondo
                //System.out.println(deltatime);

                if(plr.progressBar.getProgress() > 0.1) gameMethodMovementHandler(deltatime, this.gameScene, keysPressed);
                if(plr.progressBar.getProgress() > 5.551115123125783E-17) gameMethodAttackHandler(deltatime);
                if(enemy != null && enemy.progressBar.getProgress() <= 0.1) {   kill_Enemy(); }//perchè è 1.1368683772161603E-13

                if(plr != null && plr.progressBar.getProgress() <= 0.1)    player_Died();
                System.out.println(plr.progressBar.getProgress());

                enemy.attack(deltatime, plr);
                if(!enemy.attack_flag)  enemy.shot(deltatime,plr, enemy.p);
                deltatime--;
            }
        }

    }

    private void kill_Enemy(){
        if(this.enemy != null && this.enemy.cld.ret != null) {
            Platform.runLater(() -> {
                plr.root.getChildren().remove(enemy.vBox);
                enemy.vBox = null;
            });
            Platform.runLater(() -> {
                plr.root.getChildren().remove(enemy.cld.ret);
                enemy.cld.ret = null;
            });
           Platform.runLater(() -> {
                plr.root.getChildren().remove(enemy.imgView);
                enemy.imgView = null;
            });
           System.gc(); //richiama il garbage collector
        }

    }

    private void player_Died(){
        if(this.plr != null && this.plr.cld.ret != null) {
            Platform.runLater(() -> {
                plr.root.getChildren().remove(plr.vBox);
                plr.vBox = null;
            });
            Platform.runLater(() -> {
                plr.root.getChildren().remove(plr.cld.ret);
                plr.cld.ret = null;
            });
            Platform.runLater(() -> {
                plr.root.getChildren().remove(plr.imgView);
                plr.imgView = null;
            });
            System.gc(); //richiama il garbage collector
        }
    }


    private void gameMethodMovementHandler(double deltaTime, GameScene gameScene, Set<KeyCode> keysPressed) {

            if(enemy != null && plr != null && plr.cld != null && enemy.cld != null)   plr.cld.collision_Detected(enemy.cld.ret, true);
            //gestisco l'evento, la penultima condizione degli if è per non far andare fuori mappa, l'ultima condizione è per la collisione
            if ( (keysPressed.contains(plr.forward) || keysPressed.contains(plr.forwardArrow)) && plr.y >0
                    ) {
                plr.dir_forward = true;

                plr.changeImage("Images/Back_Pg.png");
                if(plr.cld.fr)   plr.moveUp(deltaTime);
            }
            else{
                plr.dir_forward = false;
            }

            if ( (keysPressed.contains(plr.backward) || keysPressed.contains(plr.backwardArrow)) && plr.y < (ScreenSettings.screenHeight-ScreenSettings.sizeTile)
                     ) {
                plr.dir_backward = true;

                plr.changeImage("Images/Front_Pg.png");
                if(plr.cld.br) plr.moveDown(deltaTime);
            }
            else{
                plr.dir_backward = false;
            }

            if ( (keysPressed.contains(plr.leftward) || keysPressed.contains(plr.leftwardArrow)) && plr.x > 0
                    ) {
                plr.dir_leftward = true;


                plr.changeImage("Images/Left_Side_Pg.png");
                if(plr.cld.dx) plr.moveLeft(deltaTime);
            }
            else{
                plr.dir_leftward = false;
            }

            if ( (keysPressed.contains(plr.rightward) || keysPressed.contains(plr.rightwardArrow)) && plr.x < (ScreenSettings.screenWidth-ScreenSettings.sizeTile)
                    ) {
                plr.dir_rightward = true;

                plr.changeImage("Images/Right_Side_Pg.png");
                if(plr.cld.sx)    plr.moveRight(deltaTime);
            }
            else{
                plr.dir_rightward = false;
            }

            // Sprint
            // Sprint attivato quando il tasto è tenuto premuto
            if (keysPressed.contains(plr.sprint)) {
                plr.sprintStatus(deltaTime);  // Attiva o continua lo sprint
                plr.sprint(deltaTime);
            } else {
                plr.walk(deltaTime);
            }

    }
    private void gameMethodAttackHandler(double deltatime){

             if(plr.progressBar.getProgress() > 5.551115123125783E-17) {
                 gameScene.setOnMouseClicked(new EventHandler<MouseEvent>() {
                     @Override
                     public void handle(MouseEvent mouseEvent) {
                         double getSceneX = mouseEvent.getSceneX();
                         double getSceneY = mouseEvent.getSceneY();
                         plr.setDestinationAttack(getSceneX, getSceneY);
                         plr.normal_attack(deltatime);
                     }
                 });
             }

        if(plr.attack_flag && plr.progressBar.getProgress() > 0.1){
            plr.shot(deltatime);
        }

    }

}

Player

Questa classe rappresenta il Player con cui interagisce l'utente. I metodi principali sono quelli del movimento moveUp(),moveDown(), moveLeft() e moveRight() e quelli che riguardano lo sprint del personaggio; un altro principale metodo è shot(), il quale si basa nello sparare dei proiettili, implementato con una lista di Projectile così da poterne sparare più di uno; se il proiettile colpisce il nemico, a quest'ultimo gli diminuisce la vita e gli aumenta la velocità; se colpisce il proiettile del nemico, il proiettile del player si distrugge.

public class Player extends CharacterPlayable{
    //per lo sprint
    protected double timeSprint;
    protected double timeReCharge;
    protected static final double SPRINT_TIME_DURATION = 400.0; // durata dello sprint
    protected static final double RECHARGE_TIME_DURATION = 400.0; // tempo di ricarica
    protected boolean isSprinting;

    //attacco
    private List<Projectile> projectiles;
    Image attackImage;
    boolean attack_flag;
    double xDest, yDest;
    protected Group root;
    private Enemy enemy;

    public Player(){
        x = ScreenSettings.screenWidth/2.0;
        y = ScreenSettings.screenHeight/2.0;


        progressBar = new ProgressBar(1.0);   //1 = 100%, 0.5 = 50%
        vBox = new VBox(progressBar);
        vBox.setSpacing(10);
        vBox.setLayoutX(this.x);
        vBox.setLayoutY(this.y - 20);


        this.projectiles = new ArrayList<>();
        attack_flag = false;

        xDest = 0;
        yDest = 0;

        timeSprint = 0.0;
        timeReCharge = 0.0;
        isSprinting = false;


        dir_forward = false;
        dir_backward = false;
        dir_rightward = false;
        dir_leftward = false;
        dir_forward_oblq_right = false;
        dir_forward_oblq_left = false;
        dir_backward_oblq_right = false;
        dir_backward_oblq_left = false;

        speed = 2.5;
        strength = 2.46793;

        img = new Image(getClass().getResourceAsStream("Images/Front_Pg.png"), ScreenSettings.sizeTile, // requestedWidth
                ScreenSettings.sizeTile, // requestedHeight
                false, false);  //preserveRatio = false e disattivando il smoothing a livello di Image
        //Questo dice a JavaFX: "Scala esattamente a 48x48, non interpolare, non mantenere le proporzioni"
        imgView = new ImageView(img);

        //imposto la grandezza dell'immagine
        imgView.setFitWidth(ScreenSettings.sizeTile);
        imgView.setFitHeight(ScreenSettings.sizeTile);



        imgView.setLayoutX(x);
        imgView.setLayoutY(y);

        attackImage = new Image(getClass().getResourceAsStream("Images/ProvaAttacco.png"), ScreenSettings.sizeTile, // requestedWidth
                ScreenSettings.sizeTile, // requestedHeight
                false, false);


        cld = new Collider(x, y,ScreenSettings.sizeTile,ScreenSettings.sizeTile);
    }

    //implementazione metodi movimento
    @Override
    protected void moveUp(double deltaTime) {
        y -= speed * deltaTime ;
        //playerView.setY(y);
        Platform.runLater(() -> { imgView.setLayoutY(y); cld.ret.setY(y);   vBox.setLayoutY(y-20);});
    }

    @Override
    protected void moveDown(double deltaTime) {
        y += speed * deltaTime ;
       // playerView.setY(y);
        Platform.runLater(() -> {
            imgView.setLayoutY(y); cld.ret.setY(y); vBox.setLayoutY(y-20);});
    }

    @Override
    protected void moveLeft(double deltaTime) {
        x -= speed * deltaTime ;
        //playerView.setX(x);
        Platform.runLater(() -> {
            imgView.setLayoutX(x); cld.ret.setX(x); vBox.setLayoutX(x);});
    }

    @Override
    protected void moveRight(double deltaTime) {
        x += speed * deltaTime;
        //playerView.setX(x);
        Platform.runLater(() -> {
            imgView.setLayoutX(x); cld.ret.setX(x); vBox.setLayoutX(x);});
    }

    @Override
    protected void sprintStatus(double deltatime){
        if (!isSprinting && this.timeReCharge <= 0) {
            // Se non stiamo sprintando e il tempo di ricarica è finito
            isSprinting = true; //si attiva sprint
            this.timeSprint = SPRINT_TIME_DURATION;
            System.out.println("Sprint attivato! Durata: " + SPRINT_TIME_DURATION + " secondi.");
        } else if (isSprinting) {
            System.out.println("Già sprintando!");
        } else if (this.timeReCharge > 0) {
            System.out.println("Non puoi sprintare, il tempo di ricarica non è finito.");
        }

    }

    protected void sprint(double deltatime){
        if (this.isSprinting) {
            this.speed = 4;
            this.timeSprint -= deltatime;  // Diminuisci il tempo dello sprint
            System.out.println(this.timeSprint);
            if (this.timeSprint <= 0) {
                this.walk(deltatime);
                this.isSprinting = false;
                this.timeReCharge = Player.RECHARGE_TIME_DURATION;  // Inizia la ricarica
                System.out.println("Sprint finito! Inizia la ricarica.");
            }
        }
    }


    @Override
    protected void walk(double deltaTime){
        speed = 2.5;
        // Se il tasto di sprint non è premuto, gestisci la ricarica
        if (this.timeReCharge > 0) {
            this.timeReCharge -= deltaTime;
            System.out.println("Sto ricaricando");
            if (this.timeReCharge <= 0) {
                System.out.println("Ricarica completa. Puoi sprintare di nuovo!");
            }
        }
    }

    @Override
    protected void normal_attack(double deltatime) {

        if(this.progressBar.getProgress() > 5.551115123125783E-17) {

            Projectile p = new Projectile(attackImage, imgView.getLayoutX(), imgView.getLayoutY(), xDest, yDest);

            this.attack_flag = true;

            projectiles.add(p);
            Platform.runLater(() -> {
                root.getChildren().addAll(p.cld.ret, p.imgView);
            });
            System.out.println("Attacco");
        }
    }

    protected void setDestinationAttack(double xDest, double yDest){
        this.xDest = xDest;
        this.yDest = yDest;
    }

    protected void setRoot(Group root){
        this.root = root;
    }

    protected void setEnemy(Enemy enemy){this.enemy = enemy;}

    protected void shot(double deltaTime){
        //teorema di pitagora
//        double dx = xDest - xAttack;
//        double dy = yDest - yAttack;
//        double distance = Math.sqrt(dx * dx + dy * dy); //ipotenusa, vettore direzione
//        //calcolo le componenti
//        double directionX = dx / distance;  //coseno dell'angolo tra x e l'ipotenusa
//        double directionY = dy / distance;  //seno dell'angolo tra y e l'ipotenusa

        Iterator<Projectile> iterator = projectiles.iterator();
        while(iterator.hasNext()){
            Projectile p = iterator.next();
            p.journey(deltaTime, p.speed);


            if(p.isArrived(xDest, yDest)){
                Platform.runLater(() -> {
                    root.getChildren().removeAll(p.cld.ret, p.imgView);
                });
                iterator.remove();
            }else if ((enemy != null) && (enemy.cld.ret != null) ) {
                if ( p.cld.ret.intersects(enemy.cld.ret.getBoundsInLocal())) {  //se colpisce il nemico
                    if (enemy.health > 1) {  //perchè non so il perchè non va negativo e si ferma a circa 1e-13
                        enemy.speed += 0.2;
                        enemy.health -= (enemy.initial_Health * p.normal_damage);
                        System.out.println(enemy.health);
                        Platform.runLater(() -> {
                            enemy.progressBar.setProgress(enemy.progressBar.getProgress() - p.normal_damage);
                        });
                    }

                    Platform.runLater(() -> {
                        root.getChildren().removeAll(p.cld.ret, p.imgView);
                    });
                    iterator.remove();
                } else if(p.cld.ret.intersects(enemy.p.cld.ret.getBoundsInLocal())){    // se colpisce il proiettile del nemico
                    Platform.runLater(() -> {
                        root.getChildren().removeAll(p.cld.ret, p.imgView);
                    });
                    iterator.remove();
                }
            }
        }

        if(projectiles.isEmpty())   attack_flag = false;    //così ne posso sparare di più


    }


}

Enemy

Rappresenta il nemico da abbattere; il metodo movement() fa muovere il nemico in un percorso fisso; il metodo shot() rappresenta l'attacco del nemico che quando si distrugge o arriva a destinazione o colpisce il player, ne spara subito un altro; se colpisce il player, gli fa fare un piccolo rimbalzo.

public class Enemy extends Character{


    Image attackImage;
    boolean attack_flag;
    Projectile p;
    final double REBOUND = 2.56784;
    private boolean goingDown;



    public Enemy(){
        goingDown = true;

        this.x = (ScreenSettings.screenWidth/2.0) + 100.0;
        this.y = (ScreenSettings.screenHeight/2.0) - 100.0;

        progressBar = new ProgressBar(1.0);   //1 = 100%, 0.5 = 50%
        vBox = new VBox(progressBar);
        vBox.setSpacing(10);
        vBox.setLayoutX(this.x);
        vBox.setLayoutY(this.y - 20);


        dir_forward = false;
        dir_backward = false;
        dir_rightward = false;
        dir_leftward = false;
        dir_forward_oblq_right = false;
        dir_forward_oblq_left = false;
        dir_backward_oblq_right = false;
        dir_backward_oblq_left = false;

        this.health = this.initial_Health;
        speed = 1.5;
        strength = 4;

        img = new Image(getClass().getResourceAsStream("Images/Front_Enemy_c.png"), ScreenSettings.sizeTile, // requestedWidth
                ScreenSettings.sizeTile, // requestedHeight
                false, false);  //preserveRatio = false e disattivando il smoothing a livello di Image
        //Questo dice a JavaFX: "Scala esattamente a 48x48, non interpolare, non mantenere le proporzioni"
        imgView = new ImageView(img);

        //imposto la grandezza dell'immagine
        imgView.setFitWidth(ScreenSettings.sizeTile);
        imgView.setFitHeight(ScreenSettings.sizeTile);

        imgView.setLayoutX(x);
        imgView.setLayoutY(y);

        cld = new Collider(x, y,ScreenSettings.sizeTile,ScreenSettings.sizeTile);

        attackImage = new Image(getClass().getResourceAsStream("Images/ProvaAttaccoEnemy.png"), ScreenSettings.sizeTile, // requestedWidth
                ScreenSettings.sizeTile, // requestedHeight
                false, false);

        attack_flag = true;

    }


    protected void attack(double deltatime, Player plr){
        if(attack_flag && plr.progressBar.getProgress() > 0.1 && this.progressBar.getProgress() > 0.1){
            attack_flag = false;
            Projectile p = new Projectile(attackImage, this.x, this.y, plr.x, plr.y);
            Platform.runLater(() -> { plr.root.getChildren().addAll(p.cld.ret,p.imgView); });
            this.p = p;
            shot(deltatime, plr, this.p);
        }
    }




    protected void shot(double deltaTime, Player plr, Projectile p){

        if(this.progressBar.getProgress() > 0.1 )    movement(deltaTime);

        if(this.progressBar.getProgress() > 0.1 && !attack_flag && plr.progressBar.getProgress() > 0.1) {  //finchè è in vita
            p.journey(deltaTime, p.speed);
            plr.cld.collision_Detected(p.cld.ret, false);

            if (p.isArrived(plr.x, plr.y)) {
                Platform.runLater(() -> { plr.root.getChildren().removeAll(p.cld.ret, p.imgView); } );
                attack_flag = true;
            }
            if(p.cld.ret.intersects(plr.cld.ret.getBoundsInLocal())){

                if(plr.cld.dx && plr.x > 0){
                    Platform.runLater(() -> {
                        plr.imgView.setX(plr.imgView.getX() - (plr.speed * this.REBOUND));
                        plr.cld.ret.setLayoutX(plr.cld.ret.getLayoutX() - (plr.speed * this.REBOUND));
                        plr.progressBar.setTranslateX(plr.progressBar.getTranslateX() - (plr.speed * this.REBOUND * 0.4));
                        plr.vBox.setTranslateX(plr.vBox.getTranslateX() - (plr.speed * this.REBOUND * 0.4));
                    });
                }

                if(plr.cld.sx && plr.x < (ScreenSettings.screenWidth-ScreenSettings.sizeTile)){
                    Platform.runLater(() -> {
                        plr.imgView.setX(plr.imgView.getX() + (plr.speed * this.REBOUND));
                        plr.cld.ret.setLayoutX(plr.cld.ret.getLayoutX() + (plr.speed * this.REBOUND));
                        plr.progressBar.setTranslateX(plr.progressBar.getTranslateX() + (plr.speed * this.REBOUND * 0.4));
                        plr.vBox.setTranslateX(plr.vBox.getTranslateX() + (plr.speed * this.REBOUND * 0.4));
                    });
                }

                if(plr.cld.br && plr.y < (ScreenSettings.screenHeight-ScreenSettings.sizeTile)){


                    Platform.runLater(() -> {
                        plr.imgView.setY(plr.imgView.getY() + (plr.speed * this.REBOUND));
                        plr.cld.ret.setLayoutY(plr.cld.ret.getLayoutY() + (plr.speed * this.REBOUND));
                        plr.progressBar.setTranslateY(plr.progressBar.getTranslateY() + (plr.speed * this.REBOUND* 0.4));
                        plr.vBox.setTranslateY(plr.vBox.getTranslateY() + (plr.speed * this.REBOUND* 0.4));
                    });
                }
                if(plr.cld.fr && plr.y >0){
                    Platform.runLater(() -> {
                        plr.imgView.setY(plr.imgView.getY() - (plr.speed * this.REBOUND));
                        plr.cld.ret.setLayoutY(plr.cld.ret.getLayoutY() - (plr.speed * this.REBOUND));
                        plr.progressBar.setTranslateY(plr.progressBar.getTranslateY() - (plr.speed * this.REBOUND* 0.4));
                        plr.vBox.setTranslateY(plr.vBox.getTranslateY() - (plr.speed * this.REBOUND* 0.4));
                    });
                }

                Platform.runLater(() -> { plr.root.getChildren().removeAll(p.cld.ret, p.imgView); } );
                Platform.runLater(() -> {  plr.progressBar.setProgress(plr.progressBar.getProgress() - 0.2); });
                attack_flag = true;
            }

        }


        if(this.progressBar.getProgress() < 0.1 && !p.isArrived(plr.x, plr.y)){
            Platform.runLater(() -> { plr.root.getChildren().removeAll(p.cld.ret, p.imgView); } );
        }



    }

    public void movement(double deltaTime){
        double maxDestY = ScreenSettings.screenHeight - ScreenSettings.sizeTile;
        double minDestY = 0; // oppure un valore di partenza

        if (goingDown) {
            Platform.runLater(() -> {
                this.changeImage("Images/Front_Enemy_c.png");
            });
            this.y += this.speed * deltaTime;
            if (this.y >= maxDestY) {
                this.y = maxDestY;
                goingDown = false;
            }
        } else {
            Platform.runLater(() -> {
                this.changeImage("Images/Back_Enemy_c.png");
            });
            this.y -= this.speed * deltaTime;
            if (this.y <= minDestY) {
                this.y = minDestY;
                goingDown = true;
            }
        }

        double finalY = this.y;
        Platform.runLater(() -> {
            this.imgView.setLayoutY(finalY);
            this.cld.ret.setY(finalY);
            this.vBox.setLayoutY(finalY - 20);
        });
    }


}

Projectile

Rappresenta il proiettile usato dal nemico e dal player; il metodo journey() rappresenta il movimento del proiettile e isArrived() se è arrivato o no a destinazione.

public class Projectile extends Entity{

    double directionX, directionY;
    double xDest, yDest;
    protected static final double margine = 2.0;
    protected double normal_damage = 0.2;   //in percentuale
    protected final double speed = 2.5;

    public Projectile(Image img, double x, double y, double xDest, double yDest) {

            this.imgView = new ImageView(img);
            this.imgView.setFitWidth(ScreenSettings.sizeTile);
            this.imgView.setFitHeight(ScreenSettings.sizeTile);

            this.x = x;
            this.y = y;
            this.imgView.setLayoutX(this.x);
            this.imgView.setLayoutY(this.y);




        this.xDest = xDest;
        this.yDest = yDest;

        double dx = this.xDest - x;
        double dy = this.yDest - y;
        double distance = Math.sqrt(dx * dx + dy * dy);
        directionX = dx / distance;
        directionY = dy / distance;

        cld = new Collider(this.x, this.y, ScreenSettings.sizeTile, ScreenSettings.sizeTile);
    }

    protected void journey(double deltaTime, double speed){
        x += deltaTime * speed * directionX;
        y +=  deltaTime * speed * directionY;

        Platform.runLater(() -> {
            imgView.setLayoutX(x);
            imgView.setLayoutY(y);
            cld.ret.setX(x);
            cld.ret.setY(y);

        });
    }

    public boolean isArrived(double xDest, double yDest){
        double dx = this.xDest - x;
        double dy = this.yDest - y;
        return Math.sqrt(dx * dx + dy * dy) <= margine;
    }

}

Collider

Rappresenta il Collider, ovvero un oggetto invisibile messo intorno agli oggetti per gestire le collisioni; se block è true allora abilita il collider ad essere "rigido" ovvero di non andare all'interno di un altro collider, mentre se è false serve solo per capire se due oggetti si toccano.

public class Collider {
    Rectangle ret ;
    protected double x, y;
    boolean dx, sx, fr, br;


    public Collider(double x, double y, double width, double height){
        dx = sx = fr = br = true;
        this.x = x;
        this.y = y;
        ret = new Rectangle( this.x, this.y, width, height);    //posizione e grandezza
        ret.setArcHeight(10d);
        ret.setArcWidth(10d);
        //ret.setStroke(Color.RED);

    }
    protected void collision_Detected( Rectangle ret2, boolean block){
        if(  this.ret != null && ret2 != null) {

            if (this.ret.intersects(ret2.getBoundsInParent())) {
                //uso un gap per evitare che il pg si blocchi e quindi avvenga una sovrapposizione delle condizioni di collisione
                //restituisce la coordinata X dell'angolo superiore sinistro del rettangolo rispetto al parent.
                double deltaX = this.ret.getX() - ret2.getX();
                double deltaY = this.ret.getY() - ret2.getY();
                //esempi quando mi trovo a sinistra del nemico:
                //es. 436 - 484 = -48 che è la larghezza delle immagini
//            System.out.println(e1.cld.ret.getX()+"  "+ret2.cld.ret.getX());
//            System.out.println(e1.cld.ret.getY()+"  "+ret2.cld.ret.getY());
                //es. 214.049 - 188 = 26,049
                //quindi dato che il val ass di deltax è > di deltay mi si attiva la collisione da sinistra
                if (Math.abs(deltaX) > Math.abs(deltaY)) {
                    if (deltaX < 0) {
                        // Collisione da sinistra: correggi posizione
                        this.sx = false;
                        //mi imposta la posizione x del colider del player alla distanza del collider del nemico - la larghezza che è 48
                        if(block)
                            Platform.runLater(() -> {
                                this.ret.setX(ret2.getX() - this.ret.getWidth());
                            });
                        System.out.println("Collisione da sinistra!");
                    } else {
                        // Collisione da destra: correggi posizione
                        this.dx = false;
                        if(block) Platform.runLater(() -> {
                            this.ret.setX(ret2.getX() + ret2.getWidth());
                        });
                        System.out.println("Collisione da destra!");
                    }
                } else {
                    if (deltaY < 0) {
                        // Collisione dall'alto: correggi posizione
                        this.br = false;
                        if(block) Platform.runLater(() -> {
                           this.ret.setY(ret2.getY() - this.ret.getHeight());
                        });
                        System.out.println("Collisione dall'alto!");
                    } else {
                        // Collisione dal basso: correggi posizione
                        this.fr = false;
                        if(block) Platform.runLater(() -> {
                            this.ret.setY(ret2.getY() + ret2.getHeight());
                        });
                        System.out.println("Collisione dal basso!");
                    }
                }
            } else this.dx = this.sx =this.fr = this.br = true;
        }
    }

}

Character

Rappresenta un personaggio generico.

public abstract class Character extends Entity{
    //caratteristiche
    protected ProgressBar progressBar;
    protected VBox vBox;
    protected final double initial_Health = 2450.431;
    protected double health;
    protected double strength;
    protected double speed;

    //direzioni: 8 totali
    protected boolean dir_forward;
    protected boolean dir_backward;
    protected boolean dir_rightward;
    protected boolean dir_leftward;
    protected boolean dir_forward_oblq_right;
    protected boolean dir_forward_oblq_left;
    protected boolean dir_backward_oblq_right;
    protected boolean dir_backward_oblq_left;

    protected final void changeImage(String pathImage){
        Platform.runLater(() -> { imgView.setImage(new Image(getClass().getResourceAsStream(pathImage), ScreenSettings.sizeTile, // requestedWidth
                ScreenSettings.sizeTile, // requestedHeight
                false, false));});
    }


}

CharacterPlayable

Rappresenta un personaggio giocabile.

public abstract class CharacterPlayable extends Character{
    //comandi
    protected  final KeyCode forward = KeyCode.W;
    protected  final KeyCode backward = KeyCode.S;
    protected  final KeyCode leftward = KeyCode.A;
    protected  final KeyCode rightward = KeyCode.D;
    protected  final KeyCode forwardArrow = KeyCode.UP;
    protected  final KeyCode backwardArrow = KeyCode.DOWN;
    protected  final KeyCode leftwardArrow = KeyCode.LEFT;
    protected  final KeyCode rightwardArrow = KeyCode.RIGHT;
    protected  final KeyCode sprint = KeyCode.SHIFT;

    //movimento
    protected abstract void moveUp(double deltaTime);

    protected abstract void moveDown(double deltaTime);

    protected abstract void moveLeft(double deltaTime);

    protected abstract void moveRight(double deltaTime);

    protected abstract void sprintStatus(double deltatime);
    protected abstract void walk(double deltaTime);

    protected abstract void normal_attack(double deltatime);

}

Entity

Rappresenta la classe più generica di ogni oggetto all'interno del gioco.

public abstract class Entity {

    //immagine
    protected Image img;
    protected ImageView imgView;

    //posizione
    protected double x;
    protected double y;

    //Collider
    protected Collider cld;
}

About

Gioco fatto con la libreria grafica javafx

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages