0

So I was experimenting with javaFX a bit since it is a part of one of my subjects. I have a catapult that shoots a ball in certain direction. I was wondering if you could somehow change the color of a canvas background in a runtime on a certain occasion - when a ball hits the wall for example. I already figured out how to make the ball bounce of the wall, but I cannot figure out how to change the bg color in runtime.

I'm using import javafx.scene.canvas.GraphicsContext; as it is what we kinda "have" to work with.

I thought something like this would work, I found some threads about sleep so I gave it a try.

public void flashCanvas() {

try
{
    gc.setFill(Color.WHITESMOKE);
    Thread.sleep(100);
    gc.setFill(Color.BLACK);
    Thread.sleep(100);
}
catch(InterruptedException ex)
{
    Thread.currentThread().interrupt();
    }

}

I thought that this would just change the color, then wait and over again.

Thanks for help!

t0is
  • 29
  • 7
  • 1
    Hi, I have never used JavaFX, but isn't `setFill()` just changing the previously set color? If so, you would need to draw using the new color. I found this: `GraphicsContext gc = getGraphicsContext2D(); gc.setFill(Color.web("#010a23")); gc.fillRect(x, y, w, h);` So maybe you need to use something like `fillRect()` after having changed the color. May help: https://stackoverflow.com/questions/25468882/change-color-of-background-in-javafx-canvas – Barudar Oct 07 '19 at 03:32
  • Thank you, works well with the advice Ahmed provided! – t0is Oct 07 '19 at 09:12
  • You're welcome ;) – Barudar Oct 08 '19 at 02:21

2 Answers2

0

Short Answer
You can make your desired behaviour using this part of code

   Runnable collide = new Runnable() {
        @Override
        public void run() {
            Platform.runLater(() ->
                damageEffect()
            );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Platform.runLater(() ->
                resetEffect()
            );
        }
    };
    new Thread(collide).start();


Explanation you can't use Thread.Sleep() on the main thread that will cause your UI to freeze so you need to make it on another thread and for more safety when changing anything in the UI/Main thread you should use Platform.runLater()

you can write whatever the effect in these function boomEffect() and resetEffect() if you want to change the canvas fill color you can use the code provided by @Barudar in the comment like this

private void resetEffect() {
    canvas.getGraphicsContext2D().setFill(Color.RED);
    canvas.getGraphicsContext2D().fillRect(0,0,canvas.getWidth(),canvas.getHeight());
}

where fillRect() take startingX , startingY , endX , endY as a parameters

Ahmed Emad
  • 674
  • 6
  • 19
  • thanks for advice I know about the runLater so I mentioned it in the explanation but didn't want to make the code complicated – Ahmed Emad Oct 07 '19 at 09:12
  • Thank you, worked well. I just now need to somehow edit so it would not go like crazy once the ball actually hits the ball. Thanks a lot! – t0is Oct 07 '19 at 09:13
  • So how the thing should be done properly? Should I just wrap the resetEffect methon inside the runLater() ? It asks for a runnable and I'm not really sure how to resolve this the correct way. :) – t0is Oct 07 '19 at 09:19
  • I have edited my answer to use `Platform.runlater()` as it should be – Ahmed Emad Oct 07 '19 at 09:52
  • does it make sense for you now Tomas ? – Ahmed Emad Oct 07 '19 at 10:10
  • Thanks, I made it a bit messy, but achieved a same result, will fix it now with your code. Thanks everyone for your effort, I got it :) – t0is Oct 07 '19 at 16:16
0

You're blocking the JavaFX application thread with Thread.sleep which prevents the change from being rendered. (In your code there actually is no change, since you're simply replacing the color used to draw, assuming the color is not used anywhere else, but this is what would happen, if you did draw something in addition to modifying the fill property.)

I recommend using one of the classes from the javafx.animation package to change this.

In this case a PauseTransition seems the simplest way to go, but if you want to include a update loop, I recommend going with AnimationTimer or Timeline instead and integrating this kind of logic into the update "loop". Using one of the latter possiblities you could simply save the last time the ball hit a wall and decide based on this info which color to use to draw the background.

Example using PauseTransition:

gc.setFill(Color.WHITESMOKE);
gc.fillRect(x, y, w, h);

// schedule update without blocking
PauseTransition pause = new PauseTransition(Duration.millis(100));
pause.setOnFinished(evt -> {
    gc.setFill(Color.BLACK);
    gc.fillRect(x, y, w, h);
});
pause.play();

Note that you'll probably need to redraw more than just the background, since using fillRect replaces all the content currently in the rectangle.

fabian
  • 80,457
  • 12
  • 86
  • 114