Pacman java Game runs very slow almost freezes when smart ghost is moving (DIjkstra algorithm shortest path)

145 views Asked by At

The problem I'm having is that whenever I enable the timer of the samrt pacaman that tries to find the position of pacman teh game runs very slow. I just can't seem to figure out why.

Vakje means Box. intelligent spook is a smartghost. Buur means Neighbor. spelElement means GameElement. sorry for the dutch coding. Here is the code:

public abstract class Spookje extends Poppetje {
private Queue<Vakje> vakjesToInspect = new LinkedList<Vakje>();
private ArrayList<Vakje> visitedvakjes = new ArrayList<Vakje>();
private ArrayList<Vakje> currentVakjes = new ArrayList<Vakje>();
private ArrayList<Vakje> previousVakjes = new ArrayList<Vakje>();
protected Stack<Vakje> movementStack = new Stack<Vakje>();
protected boolean searching = false;

@Override
public void Bewegen(Direction direction) {

}


  private void reset() {
    vakjesToInspect.clear();
    visitedvakjes.clear();
    movementStack.clear();
    currentVakjes.clear();
    previousVakjes.clear();
}

private void search() {
    while (!vakjesToInspect.isEmpty()) {
        Vakje current = vakjesToInspect.remove();
        visitedvakjes.add(current);
        checkNeighbors(current);
    }
}

private void checkNeighbors(final Vakje vakje) {

    for (Vakje u : vakje.buren.values()) {
        if (u.isPacman()) {
            if (!visitedvakjes.contains(u)) {
                vakjesToInspect.add(u);
                currentVakjes.add(u);
                previousVakjes.add(vakje);
            }
            buildMovementStack(u);
            setSearching(false);
            break;
        } else {
            if (!visitedvakjes.contains(u)) {
                vakjesToInspect.add(u);
                currentVakjes.add(u);
                previousVakjes.add(vakje);
            }
        }
    }

}

private void buildMovementStack(Vakje vakje) {
    Vakje current = vakje;

    while (current != this.vakje && !movementStack.contains(current)) {

        movementStack.push(current);
        int index = currentVakjes.indexOf(current);

        Vakje nextStep = previousVakjes.get(index);
        current = nextStep;
    }
}

public void setSearching(boolean searching) {
    this.searching = searching;
}

private void createInitialState() {
    Vakje vakje = this.vakje;
    vakjesToInspect.add(vakje);
}

public void SearchIt() {
    reset();
    createInitialState();
    search();
}

protected void findPacman() {
    reset();
    createInitialState();
    search();
}

second class:

public class IntelligentSpook extends Spookje {
Pacman pacman;

public IntelligentSpook(Pacman pacman) {
    this.pacman = pacman;
}

@Override
public void draw(Graphics g) {
    try {
        /* Voor scherpere rendering */
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.drawImage(ImageIO.read(new File("smart.png")), vakje.getxPos(), vakje.getyPos(), vakje.getWidth(), vakje.getHeight(), null);
    } catch (IOException ex) {
        Logger.getLogger(Spookje.class.getName()).log(Level.SEVERE, null, ex);
    }

}

public void Move() {

    if (!this.searching) {
        setSearching(true);
        findPacman();
    }
    if (this.movementStack.size() > 0) {
        Vakje vakje = this.movementStack.pop();

        this.getVakje().removeSpelElement(this);
        Vakje x = this.moveToVakje(vakje);
        x.addSpelElement(this);
        this.setVakje(x);
    }
}

}

Here is the code that calls the draw:

public class Speelboard {
public Timer timdronkenspook = new Timer(400, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        if (!FirstRun) {

            for (Vakje vakje : vakken) {
                if (vakje.has(DronkenSpook.class)) {
                    if (vakje.get(DronkenSpook.class) instanceof DronkenSpook) {
                        ((DronkenSpook) vakje.get(DronkenSpook.class)).Move();
                    }

                }
            }

            gamepanel.repaint();
        }
    }
});

public Timer timslimspook = new Timer(100, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        if (!FirstRun) {
            for (Vakje vakje : vakken) {
                if (vakje.has(IntelligentSpook.class)) {
                    if (vakje.get(IntelligentSpook.class) instanceof IntelligentSpook) {
                        ((IntelligentSpook) vakje.get(IntelligentSpook.class)).Move();
                    }
                }
            }

            gamepanel.repaint();
        }

    }
});

public Timer timpacman = new Timer(190, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        if (!FirstRun) {
            pacman.Bewegen();

        }

        if (pacman.getgegetenbolletje() > aantalBolletjes / 2 && toonKers) {
            plaatsKers();
            toonKers = false;
        }

        if (pacman.getgegetenbolletje() == aantalBolletjes) {

            aantalBolletjes = 0;
            volgendeLevel();

            gamepanel.addkeyPacman();
        }
        gamepanel.repaint();

    }
});

public ArrayList<Vakje> vakken = new ArrayList<Vakje>();

private ArrayList<Vakje> vakjes;
public ArrayList<SpelElement> spelElements;
public LevelHandler levelhandler = new LevelHandler();
private int[] level;
public Pacman pacman;
public DronkenSpook dronkenspook;
public int aantalBolletjes;
public int timeplayed = 1;
private boolean toonKers = true;

Image gameover = new ImageIcon("gameover.png").getImage();
Image win = new ImageIcon("youwin.png").getImage();

Vakje vak;
public GamePanel gamepanel;

public Speelboard(GamePanel gamepanel) {
    this.setLevel(levelhandler.level_one);
    this.laden();
    this.gamepanel = gamepanel;

}

public void setLevel(int[] level) {
    this.level = level;
}

public int[] getLevel() {
    return level;
}

public Speelboard() {
    this.setLevel(levelhandler.level_one);
    this.laden();

}

public void laden() {
    vakken = new ArrayList<>();
    for (int i = 0; i < level.length; i++) {

        switch (level[i]) {
            case 0:
                aantalBolletjes = aantalBolletjes + 1;
                vakken.add(new Leegvakje(new NormaalBolletje(10)));
                break;
            case 1:
                vakken.add(new Muur(40, 40, 40, 40));
                break;
            case 2:
                vakken.add(new Leegvakje(new IntelligentSpook(pacman)));
                break;
            case 3:
                pacman = new Pacman();
                vakken.add(new Leegvakje(pacman));
                break;
            case 4:
                dronkenspook = new DronkenSpook();

                vakken.add(new Leegvakje(dronkenspook));
                break;
            case 5:
                vakken.add(new Leegvakje(new SuperBolletje(0)));
                break;
        }
    }
    this.vakjesVerdelen();

}

private void vakjesVerdelen() {
    int y = 0;
    int x = 0;
    int i = 0;
    for (Vakje vakje : vakken) {
        vakje.setyPos(y);
        vakje.setxPos(x);
        x = x + vakje.getWidth();

        // Dit checkt of er kolommen naast zijn
        if (i % levelhandler.rowMax == 0) {
            vakje.toevoegenBuurVakje(Direction.EAST, (Vakje) vakken.get(i + 1));
        } else if (i % levelhandler.rowMax == levelhandler.rowMax - 1) {
            vakje.toevoegenBuurVakje(Direction.WEST, (Vakje) vakken.get(i - 1));
        } else {
            vakje.toevoegenBuurVakje(Direction.EAST, (Vakje) vakken.get(i + 1));
            vakje.toevoegenBuurVakje(Direction.WEST, (Vakje) vakken.get(i - 1));
        }

        // Dit checkt of er rijen boven en onder zijn
        if (Math.floor(i / levelhandler.rowMax) == 0) {
            vakje.toevoegenBuurVakje(Direction.SOUTH, (Vakje) vakken.get(i + levelhandler.rowMax));
        } else if (Math.floor(i / levelhandler.rowMax) == this.level.length / levelhandler.rowMax - 1) {
            vakje.toevoegenBuurVakje(Direction.NORTH, (Vakje) vakken.get(i - levelhandler.rowMax));
        } else {
            vakje.toevoegenBuurVakje(Direction.SOUTH, (Vakje) vakken.get(i + levelhandler.rowMax));
            vakje.toevoegenBuurVakje(Direction.NORTH, (Vakje) vakken.get(i - levelhandler.rowMax));
        }

        i++;

        if (i % levelhandler.rowMax == 0) {
            y = y + vakje.getHeight();
            x = 0;
        }
    }
    pacman.setActive(true);
    FirstRun = false;
}

public void plaatsKers() {
    ArrayList<Vakje> vakjes = this.zoekLeegVakje();
    Random random = new Random();

    Vakje kersVak = vakjes.get(random.nextInt(vakjes.size()));

    Kers kersje = new Kers(100);
    kersje.setVakje(kersVak);
    kersVak.addSpelElement(kersje);
}

private void endGame(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    if (pacman.getcheckGamestatus() == false) {
        gamepanel.stop();
        pacman.setActive(false);
        g2.setColor(Color.black);
        g2.fillRect(0, 0, 1240, 687);

        g2.setColor(Color.white);
        g2.setFont(new Font("TimesRoman", Font.PLAIN, 24));

        if (timeplayed <= 3) {
            g2.drawImage(gameover, -100, 0, 1100, 500, null);
        } else if (timeplayed == 4) {
            g2.drawImage(win, -180, 0, 1100, 500, null);
        }

        g2.setFont(new Font("TimesRoman", Font.PLAIN, 20));
        g2.drawString("Uw score: " + pacman.score, 360, 500);
        g2.drawString("Druk op R om opnieuw te starten of druk op de restart knop", 200, 50);
    }
}

private ArrayList<Vakje> zoekLeegVakje() {
    ArrayList<Vakje> LeegVakjes = new ArrayList<>();
    for (Vakje vakje : this.vakken) {
        if (vakje.isEmpty()) {
            LeegVakjes.add(vakje);
        }
    }

    return LeegVakjes;
}

public Speelboard(ArrayList<SpelElement> spelElements, ArrayList<Vakje> vakjes) {
    this.spelElements = spelElements;
    this.vakjes = vakjes;
}
public boolean FirstRun = true;

public void draw(Graphics g) {

    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.BLACK);
    g2.fillRect(1, 400, 200, 100);
    g2.setColor(Color.white);
    g2.setFont(new Font("Helvetica Neue", Font.CENTER_BASELINE, 24));
    g2.setRenderingHint(
            RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
    g2.drawString("Score: " + pacman.score, 40, 470);
    g2.drawString("levens: " + pacman.levens, 40, 500);

    g2.setColor(Color.lightGray);

    for (Vakje vakje : vakken) {
        vakje.draw(g);
    }
    endGame(g);

}

public void volgendeLevel() {
    timeplayed++;

    switch (timeplayed) {
        case 2:
            timdronkenspook.setDelay(300);
            this.setLevel(levelhandler.level_two);

            break;
        case 3:
            timdronkenspook.setDelay(230);
            this.setLevel(levelhandler.level_three);
            break;
    }

    if (timeplayed <= 3) {
        this.laden();

    } else {
        pacman.SetcheckGamestatus(false);
    }
}

public ArrayList<Vakje> getVakjes() {
    return vakjes;
}

public ArrayList<SpelElement> getSpelElements() {
    return spelElements;
}

public int getaantalbolletje() {
    return aantalBolletjes;
}

public void setaantalbolletjes(int aantalbolletjes) {
    aantalBolletjes = aantalbolletjes;
}

}

1

There are 1 answers

1
dkatzel On

Your main problem is your code that does complex calculations as part of the Move() method is done inside the Event DispatchThread (which is where the actionPerformed() code is executed). This will freeze all drawing and inputs until the calculations are complete. It's better to instead in another thread and then re-update/repaint the screen when the calculations are done.

Tutorial on The Event Dispatch Thread

Another one here

Also while probably not the main source of your slow down, you call Image.read(new File("smart.png")) EVERY TIME you draw. It's better to do that just once in a static block and save the BufferedImage in memory instead of re-reading it everytime.