2

I made a crude copy of SpaceInvaders to get a feeling for JavaFX and was wondering how I could replace the rectangles I've used as Sprites with graphics.

It works fine with the player sprite and the stage background, but I cant figure out how to replace the red enemy squares with graphics.

I have tried putting the Image Object in the nextLevel() method and filling it into the sprites there, but this gives me only a FileNotFoundException error.

nextLevel() method:

private void nextLevel() {
// Image img2 = Image(newFileInputStream("C:\\Users\\user\\Pictures\\y.jpg")); 

            for (int i = 0; i < 5; i++) {
                Sprite enemy = new Sprite (90 + i*100, 150, 30, 30, "enemy", Color.RED);
//      enemy.setFill(new ImagePattern(img2));

                root.getChildren().add(enemy);
            }
        }

I can only initialize the Image in the start method, but then I don't know how to assign it to the enemy square since they have not been initialized yet. The enemy cannot be resolved yet, even when I put it after the createContent() method, which calls the nextLevel() method and also the Stage.

start method:

@Override
        public void start(Stage stage) throws Exception {

            Image img2 = new Image(new FileInputStream("C:\\Users\\user\\Pictures\\x.jpg"));
            Image img = new Image(new FileInputStream("C:\\Users\\user\\Pictures\\y.png"));

            player.setFill(new ImagePattern(img));
    // enemy.setFill(new ImagePattern(img2));

            stage.setTitle("Box");
            stage.setResizable(false);

            Scene scene = new Scene(createContent());
            scene.setFill(new ImagePattern(img2));
            scene.setOnKeyPressed(e ->{
                switch (e.getCode()) {
                case A:
                    player.moveLeft();
                    break;
                case D:
                    player.moveRight();
                    break;
                case SPACE:
                    shoot(player);
                    break;
                }
            });

            stage.setScene(scene);
            stage.show();
        }

createContent() method:

    private Parent createContent() {

        root.setPrefSize(600,800);
        root.getChildren().add(player);

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                update();
            }
        };

        timer.start();

        nextLevel();

        return root;
    }

If anyone needs it, here is the full code:

import java.io.FileInputStream;
import java.util.List;
import java.util.stream.Collectors;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class SpaceInvaders extends Application {

    private double t = 0;
    private final Pane root = new Pane();
    private final Sprite player = new Sprite (300,700,80,80, "player",Color.BLUE);

    private Parent createContent() {

        root.setPrefSize(600,800);
        root.getChildren().add(player);

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                update();
            }
        };

        timer.start();
        nextLevel();
        return root;
    }

    private void nextLevel() {

        for (int i = 0; i < 5; i++) {
            Sprite enemy = new Sprite (90 + i*100, 150, 30, 30, "enemy", Color.RED);
            root.getChildren().add(enemy);
        }
    }

    private List<Sprite> sprites(){
        return root.getChildren().stream().map(n -> (Sprite)n).collect(Collectors.toList());
    }
    private void update() {
        t += 0.016;
        sprites().forEach(s -> {
            switch (s.type) {

            case "enemybullet":
                s.moveDown();

                if (s.getBoundsInParent().intersects(player.getBoundsInParent())) {
                    player.dead = true;
                    s.dead = true;
                }
                break;

            case "playerbullet":
                s.moveUp();

                sprites().stream().filter(e -> e.type.equals("enemy")).forEach(enemy ->{
                    if (s.getBoundsInParent().intersects(enemy.getBoundsInParent())) {
                        enemy.dead = true;
                        s.dead = true;
                    }
                });
                break;

            case "enemy":

                if (t > 2) {
                    if (Math.random() < 0.3) {
                        shoot2(s);
                    }
                }

                break;
            }
        });

        root.getChildren().removeIf(n -> {
            Sprite s = (Sprite) n;
            return s.dead;
        });

        if (t > 2) {
            t = 0;
        }
    }

    private void shoot(Sprite who) {
        Sprite s = new Sprite((int) who.getTranslateX() + 40, (int) who.getTranslateY(), 5, 20, who.type + "bullet", Color.BLACK);
        root.getChildren().add(s);
    }

    private void shoot2(Sprite who) {
        Sprite s = new Sprite((int) who.getTranslateX() + 20, (int) who.getTranslateY() + 5, 5, 20, who.type + "bullet", Color.BLACK);
        root.getChildren().add(s);
    }

    @Override
    public void start(Stage stage) throws Exception {

        Image img2 = new Image(new FileInputStream("C:\\Users\\Alexxx\\Pictures\\ibama.jpg"));
        Image img = new Image(new FileInputStream("C:\\Users\\Alexxx\\Pictures\\pinguin.png"));

        player.setFill(new ImagePattern(img));

        stage.setTitle("Nordpol-Defender 2");
        stage.setResizable(false);

        Scene scene = new Scene(createContent());
        scene.setFill(new ImagePattern(img2));
        scene.setOnKeyPressed(e ->{
            switch (e.getCode()) {
            case A:
                player.moveLeft();
                break;
            case D:
                player.moveRight();
                break;
            case SPACE:
                shoot(player);
                break;
            }
        });

        stage.setScene(scene);
        stage.show();
    }

    private static class Sprite extends Rectangle {

        boolean dead = false;
        final String type;

        Sprite(int x, int y, int w, int h, String type, Color colour){
            super(w, h, colour);
            this.type = type;

            setTranslateX(x);
            setTranslateY(y);
        }

        Sprite(int x, int y, int w, int h, String type, Color colour, Image img){
            super(w, h, colour);
            this.type = type;

            setFill(new ImagePattern(img));
            setTranslateX(x);
            setTranslateY(y);
        }

        void moveLeft() {
            setTranslateX(getTranslateX() - 5);
        }

        void moveRight() {
            setTranslateX(getTranslateX() + 5);
        }
        void moveUp() {
            setTranslateY(getTranslateY() - 5);
        }

        void moveDown() {
            setTranslateY(getTranslateY() + 5);
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
G3cko
  • 23
  • 5
  • 1
    Welcome to SO. Please use publicly available resources (web images, for example: https://icons.iconarchive.com/icons/iconshock/tiny-animals/256/penguin-icon.png) so we can execute your code. By posting [mre] you are more likely to get help. – c0der Feb 16 '20 at 07:55
  • Does [How do I add an image inside a rectangle](https://stackoverflow.com/questions/22848829/how-do-i-add-an-image-inside-a-rectangle-or-a-circle-in-javafx) answer your question ? – c0der Feb 16 '20 at 08:08
  • Sadly this doesn't help me out here. – G3cko Feb 16 '20 at 12:27
  • Make `Image img2,img` a class variable (a field) so you can use it anywhere with the class. For more help post mre as advised. – c0der Feb 16 '20 at 14:21

1 Answers1

1

The following Minimal, Reproducible Example (1) demonstrates changing an image in a Rectangle in run time:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ChangeImageInShape extends Application {

    private int imageSelected = 0;
    private Sprite player;

    private static final String[] fishImages = {
            "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/lg/57/tropical-fish_1f420.png",
            "https://www.shareicon.net/data/128x128/2015/03/28/14104_animal_256x256.png",
            "https://cdn1.iconfinder.com/data/icons/DarkGlass_Reworked/128x128/apps/gnome-fish.png",
            "http://www.iconsalot.com/asset/icons/freepik/pet-shop-13/128/010-fish-2-icon.png"
    };
    private final Image[] images = new Image[fishImages.length];

    @Override
    public void start(Stage stage) throws Exception {

        for(int i = 0 ; i < images.length ; i++){
            images[i] = new Image(fishImages[i]); //loading images takes some time 
        }

        player = new Sprite (0,0,80,80, "player",Color.BLUE);
        changeImageInSprite();

        Button btn = new Button("Change Image In Sprite");
        btn.setOnAction(e->changeImageInSprite());

        Pane root = new BorderPane(player, null, null, btn, null);
        root.setPrefSize(300,200);

        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    private void changeImageInSprite() {
        player.setFill(new ImagePattern(images[imageSelected++]));
        imageSelected = imageSelected >= images.length ?  0 : imageSelected;
    }

    private static class Sprite extends Rectangle {

        Sprite(int x, int y, int w, int h, String type, Color colour){
            super(w, h, colour);
        }
    }

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


(1) It uses publicly available resources, it is a short as possible, and does not represent your application but the problem.
Consider adding mre to question and asnswers.
c0der
  • 18,467
  • 6
  • 33
  • 65
  • Thank you, I will consider it the next time I'm posting. Implementing the String Array and Image Array and loading the pictures from there seems to be working fine. However I haven't been able to figure out how to add pictures that are on my pc. As I mentioned, http addresses seem to work fine in the String Array, but something along the lines of " "C:\\Users\\username\\Pictures\\picture.png" doesn't seem to work, maybe just wrong formatting? – G3cko Feb 16 '20 at 19:48
  • Try the following format: `Image image = new Image("file:///C:/Users/username/Pictures/picture.png");` For more information see [this](https://stackoverflow.com/questions/7830951/how-can-i-load-computer-directory-images-in-javafx) question. – c0der Feb 17 '20 at 06:22