mercredi 13 juillet 2022

How to implement relationships between classes in a pacman game? (java)

So, I had this work at college in an object oriented programming subject where I was supposed to implement and improve some functions associated to a Pacman Game. I developed a solution, but I got so confused with the associations between the classes and some just didn't seem right. So, I would like to know what would be a better approach for this case.

The first thing to say is that there is a class called Element, which basically corresponds to all elements that the game contains. So, the walls, the pacdots, the power pellets, the pacman and the ghots are all Element. But I also created two interfaces: the MovableElement, which has the move() method, and EatableElement, which has the eaten() method.

Because of that, there are three others classes that extend the Element class and implements these interfaces: the AbstractEatableElement, which corresponds to the pacdots and power pellets for example, the AbstractMovableElement, which corresponds to the Pacman for example, and the AbstractMovableEatableElement, which corresponds to Ghosts, because they can be eaten in some circumstances (when a power pellet is eaten by the pacman) and they are movable objects.

I decided to use polymorphism by this method eaten() so the behavior that is supposed to happen when an eatable element is eaten is implemented in the concrete class. It's kind a Strategy Pattern, since we don't need to make a lot of conditionals to verify which type of class is so we can implement the behavior, this way we just implement the behavior inside each class, for example, the PacDot class will have its eaten() method and the PowerPellet and Ghost as well. But here is where things get kinda weird for me.

When a PacDot, a PowerPellet or a Ghost is eaten, the game is supposed to increase the points gotten by the Pacman, an integer attribute called "score" inside the Pacman class. But how exactly would the relationships would work here between the classes? Does that mean that I have to pass a reference of pacman every time I call the eaten() method, like pacdot.eaten(pacman)? This way just dont seem right, because the eaten() method could be able to interfere in others objects in the game, like the power pellet, which turns the ghosts into blue.

So, this was the first solution that I thought, but just seemed weird for me. So, I thought in another approach: each class of PacDot, PowerPellet and Ghost should have a reference to the pacman in their instance variable, and for the case of the PowerPellet (which turns the ghosts into blue when it's eaten), it should have a List of references of Ghosts of the game, so it can turn each one into the blue when the eaten() method of PowerPellet is called. But this solution also kinda sounded weird for me, because it kinda sounds like I'm making a composition between PacDot and Pacman, or between PowerPellet and Ghosts, which doesn't correspond to the real relationship between them.

Said that, I would like to know your opinions about that case. What would be the best way to implement a behavior when an Element is eaten by the Pacman? Is polymorphism in this case useful or is it just making things more messy?

public abstract class Element {
   protected Position pos;
   protected boolean isTransposable;
   /* constructor and others methods here */
}

public interface EatableElement {
   public void eaten();
}

public interface MovableElement {
   public void move();
}

public abstract class AbstractEatableElement extends Element implements EatableElement{
   //...
}

public class PacDots extends AbstractEatableElement{
        
   public PacDots() {
      // constructor
   }
   public void eaten() {
      pacman.increaseScore(this.numberPoints); // but how get pacman reference??
   }  
}

public class Pacman extends AbstractMovableElement {
    /* ... */
    public void eat(EatableElement e){
       e.eaten()
    }
}

Aucun commentaire:

Enregistrer un commentaire