dimanche 26 mars 2023

Apply Observer pattern to a Asteroid game

I want to apply the designer pattern to my Asteroid game. The use is for it to observe when I colide with an asteroid press or any input like the arrow keys and spacebar.

The Current code that takes care of that is:

 Map<KeyCode, Boolean> pressedKeys = new HashMap<>();

    scene.setOnKeyPressed(event -> {
        pressedKeys.put(event.getCode(), Boolean.TRUE);
    });

    scene.setOnKeyReleased(event -> {
        pressedKeys.put(event.getCode(), Boolean.FALSE);
    });

new AnimationTimer() {

    @Override
    public void handle(long now) {
        if (pressedKeys.getOrDefault(KeyCode.LEFT, false)) {
            ship.turnLeft();
        }

        if (pressedKeys.getOrDefault(KeyCode.RIGHT, false)) {
            ship.turnRight();
        }

        if (pressedKeys.getOrDefault(KeyCode.UP, false)) {
            ship.accelerate();
        }
        if (pressedKeys.getOrDefault(KeyCode.SPACE, false) && projectiles.size() < 3) {
            // we shoot
            Projectile projectile = charFactory.createProjectileFactory(new Polygon(2, -2, 2, 2, -2, 2, -2, -2), (int)ship.getCharacter().getTranslateX(), (int)ship.getCharacter().getTranslateY()).createProjectile();
            projectile.getCharacter().setRotate(ship.getCharacter().getRotate());
            projectiles.add(projectile);
        
            projectile.accelerate();
            projectile.setMovement(projectile.getMovement().normalize().multiply(3));
        
            pane.getChildren().add(projectile.getCharacter());
        }

        ship.move();
        asteroids.forEach(asteroid -> asteroid.move());
        projectiles.forEach(projectile -> projectile.move());

        asteroids.forEach(asteroid -> {
            if (ship.collide(asteroid)) {
                stop();
            }
        });

I've tried to apply the pattern but i end up with it either not working or it being super laggy, delayed or can't take in more than one command. What I did was create an interface with the method update, then a class that takes in the handling and the demo code uses the handling class. But even then the code looked messier, so I could've done it wrong.

I don't want a complete code block as an answer but would like if someone could help with the logical thinking or push me in the right direction.

Here is the full demo code:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.project.ConcreteClasses.Asteroid;
import com.project.ConcreteClasses.Projectile;
import com.project.ConcreteClasses.Ship;
import com.project.Factory.AbstractCharacterFactory;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class Demo extends Application {
public static int WIDTH = 500;
public static int HEIGHT = 400;

List<Projectile> projectiles = new ArrayList<>();

AbstractCharacterFactory charFactory = new AbstractCharacterFactory();

@Override
public void start(Stage stage) throws Exception {
    
    Pane pane = new Pane();
    pane.setPrefSize(WIDTH, HEIGHT);

    Ship ship = charFactory.createShipFactory(new Polygon(-5, -5, 10, 0, -5, 5), WIDTH / 2, HEIGHT / 2).createShip();
    List<Asteroid> asteroids = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
         Asteroid asteroid = charFactory.createAsteroidFactory().createAsteroid();
         asteroids.add(asteroid);
     }
    
    pane.getChildren().add(ship.getCharacter());
    asteroids.forEach(asteroid -> pane.getChildren().add(asteroid.getCharacter()));

    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
    
    Map<KeyCode, Boolean> pressedKeys = new HashMap<>();

    scene.setOnKeyPressed(event -> {
        pressedKeys.put(event.getCode(), Boolean.TRUE);
    });

    scene.setOnKeyReleased(event -> {
        pressedKeys.put(event.getCode(), Boolean.FALSE);
    });

new AnimationTimer() {

    @Override
    public void handle(long now) {
        if (pressedKeys.getOrDefault(KeyCode.LEFT, false)) {
            ship.turnLeft();
        }

        if (pressedKeys.getOrDefault(KeyCode.RIGHT, false)) {
            ship.turnRight();
        }

        if (pressedKeys.getOrDefault(KeyCode.UP, false)) {
            ship.accelerate();
        }
        if (pressedKeys.getOrDefault(KeyCode.SPACE, false) && projectiles.size() < 3) {
            // we shoot
            Projectile projectile = charFactory.createProjectileFactory(new Polygon(2, -2, 2, 2, -2, 2, -2, -2), (int)ship.getCharacter().getTranslateX(), (int)ship.getCharacter().getTranslateY()).createProjectile();
            projectile.getCharacter().setRotate(ship.getCharacter().getRotate());
            projectiles.add(projectile);
        
            projectile.accelerate();
            projectile.setMovement(projectile.getMovement().normalize().multiply(3));
        
            pane.getChildren().add(projectile.getCharacter());
        }

        ship.move();
        asteroids.forEach(asteroid -> asteroid.move());
        projectiles.forEach(projectile -> projectile.move());

        asteroids.forEach(asteroid -> {
            if (ship.collide(asteroid)) {
                stop();
            }
        });

        List<Projectile> projectilesToRemove = projectiles.stream().filter(projectile -> {
            List<Asteroid> collisions = asteroids.stream()
                                                        .filter(asteroid -> asteroid.collide(projectile))
                                                        .collect(Collectors.toList());
        
            if(collisions.isEmpty()) {
                return false;
            }
        
            collisions.stream().forEach(collided -> {
                asteroids.remove(collided);
                pane.getChildren().remove(collided.getCharacter());
            });
        
            return true;
        }).collect(Collectors.toList());
        
        
        projectilesToRemove.forEach(projectile -> {
            pane.getChildren().remove(projectile.getCharacter());
            projectiles.remove(projectile);
        });

        if(Math.random() < 0.005) {
            Asteroid asteroid = charFactory.createAsteroidFactory().createAsteroid();
            if(!asteroid.collide(ship)) {
                asteroids.add(asteroid);
                pane.getChildren().add(asteroid.getCharacter());
            }
        }

    }
}.start();
}

public static void main(String[] args) {
    launch();
}
}

Aucun commentaire:

Enregistrer un commentaire