0

I have a (probably an easy) problem with my java program. I'm trying to create a circle that will move from one place to another. The map is a part of an easy dialogue game that says "go here" and the map should react to it. It has to be using an Observer design pattern.

So far I have the map in the game implemented but I just can't fathom how to make the circle function as it should, while using Observer, too. Thanks for any help

package GUI;

import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import logika.Game;
import logika.IGame;
import main.Main;
import utils.Observer;


public class Mapa extends AnchorPane implements Observer{

    private IGame game;
    private Circle dot;
    //private double posTop = 0.0;
    //private double posLeft = 0.0;

    public Mapa(IGame game){
            this.game = game;
            game.getGamePlan().registerObserver(this);
            init();
    }

    private void init(){

        ImageView obrazekImageView = new ImageView(new Image(Main.class.getResourceAsStream("/zdroje/mapa.gif"),255,255,false,true));

        tecka = new Circle(10, Paint.valueOf("red"));

       //this.setTopAnchor(tecka, 15.0);
       //this.setLeftAnchor(tecka, 20.0);

        this.getChildren().addAll(obrazekImageView, dot);
        update();
    }

    public void newGame(IGame newGame){
        game.getGamePlan().removeObserver(this);
        game= newGame;
        game.getGamePlan().registerObserver(this);
        update();

    }

    @Override
    public void update(){
        this.setTopAnchor(this, game.getGamePlan().getCurrentPlace().getPosTop());
        this.setLeftAnchor(this, game.getGamePlan().getCurrentPlace().getPosLeft());
    }
}
Mark OD
  • 3
  • 3
  • The idea behind the pattern is that all **observer** (or also *listener*) register for an **event**. If the event occurs it will **notify** all *observer* (call a method on them). By that the *observer* can react to the event. (compare to [UML diagram](https://i.imgur.com/rsaw7nP.jpg) from Wikipedia) – Zabuzard Nov 25 '17 at 13:36
  • Can you be more specific about the overall goal you try to achieve? I don't get how you want to use the pattern since I don't get what you are trying to achieve. – Zabuzard Nov 25 '17 at 13:37
  • Sure. I need the dot (simple circle) to start here https://i.imgur.com/lrlJqK4.jpg , and then I need it to go left/right/(anywhere that is possible to go from there) that I command in the dialogue game. I need it to react after the command so it knows where to go. I hope i'm being clear, english is not my first language :-) – Mark OD Nov 25 '17 at 13:45
  • You may **edit** your answer and include what you just have said. I think you should create a concrete `Observer` for every image. For the event you may choose "*command was entered*" and then, as observer, reject if it's not *your picture* and move the circle if it is *your picture*. So the event will be of kind `public void commandEntered(String command, Circle circle)`. – Zabuzard Nov 25 '17 at 13:50
  • And would it be possible to have something like a combo box window next to the map, where you can choose where you want to go, and the dot will move with whatever you choose? So you would code the circle's position to xy based on what you chose in the combo box. Although it just seems hard to code then – Mark OD Nov 25 '17 at 14:16
  • The pattern itself doesn't care from where the commands come. In my example (see the answer) there are multiple commands like `bottomLeft` which are hardcoded to positions by the observer itself. The user then inputs `bottomLeft`. He may do so by entering it in a console or by choosing values in a combo box, doesn't matter. Just make sure there's an observer listening to that exact command. Of course you can change the command names to `nice island` or `snowy house` and so on. Sorry but I can't be more specific since you didn't provide any more specific information. – Zabuzard Nov 25 '17 at 14:20
  • Ok, hopefully this will be enough, thank you for your help :) – Mark OD Nov 25 '17 at 15:10

1 Answers1

0

You should implement the pattern like seen in this UML diagram from Wikipedia:

enter image description here

That is you will have an interface like CommandObserver with a method like notify that is called on each observer every time the event occurs. The event contains the exact command and all stuff that is neccessary to move the circle around. I'll assume you can move it by only having the reference to the circle. All in all it may look like

public interface CommandObserver {
    void notify(String command, Circle circle);
}

Next the invoker (let's call it CommandReceiver) of the event must have some register method where all observers can be registered. And it must have some kind of notifyObservers that it calls if the event occurs:

public class CommandReceiver {
    // The reference to the circle
    private Circle circle = ...

    private Set<CommandObserver> observers = new HashSet<>();

    public void registerObserver(CommandObserver observer) {
        observers.add(observer);
    }

    public void unregisterObserver(CommandObserver observer) {
        observers.remove(observer);
    }

    private void notifyObserver(String command, Circle circle) {
        for (CommandObserver observer : observers) {
            observer.notify(command, circle);
        }
    }

    // If a command was entered
    public void commandEntered(String command) {
        notifyObserver(command, circle);
    }
}

And last you will implement observers for all possible commands like:

public PositionMoveObserver implements CommandObserver {
    private int x;
    private int y;
    private String command;

    public PositionMoveObserver(int x, int y, String command) {
        this.x = x;
        this.y = y;
        this.command = command;
    }

    @Override
    public void notify(String command, Circle circle) {
        // Not interested in, reject
        if (!this.command.equals(command)) {
            return;
        }

        // Move the circle to our destination
        circle.moveTo(x, y);
    }
}

And then create and register it for every location:

private void createObservers(CommandReceiver invoker) {
    invoker.registerObserver(new PositionMoveObserver(0, 5, "bottomLeft"));
    invoker.registerObserver(new PositionMoveObserver(100, 5, "bottomRight"));
    invoker.registerObserver(new PositionMoveObserver(0, 50, "middleLeft"));
    ...
}

Note that for a specific command only one observer should listen to it, otherwise multiple instances will move the circle around and the result will depend on the iteration order of invokers HashSet.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82