Problem with OOP implementation of interface class

Hello everybody.

I am struggling with an OOP architecture problem i have for a game i am coding. Sorry in advance for my poor English.

The aim of the game is to shoot monsters with a canon.

The objects of my game are :

  • A battleship which fires to monsters
  • An island (a simple square on the screen) which contains one or more ground monsters (like crabs)
  • A sea which contains one or more islands and one or more sea Monster (like octopus).

A monster can move through different patterns : it can be still (no move) or move horizontally or move vertically or move randomly in each directions. It cannot cross the island borders.

My first idea was to use an interface OOP class for the move pattern. So i can assign for each monster a specific move pattern.

Here is my implementation in OOP :

class Monster {

// other attributes

PVector pos ; // position

PGraphics aliveForm ;

MoveType movetype ; // move pattern

// lots of stuff

}
class Crab extends Monster {

// lot of stuff

createAliveForm() {

// construct a crab image and put it in aliveform;

}

class Octopus extends Monster{

// lot of stuff

createAliveForm() {

// construct a octopus image and put it in aliveform;

}

Interface MoveType {

void move() ;

}

class StillMove implements MoveType {

  void move(){

// do nothing}

}

Class HozizontalMove implements MoveType{

Void move() {

// i can’t figure how to code here}

}

Class Island {

PVector pos ;// position of left corner of the island

Int w, h ; //width and height of the island

ArrayList<Crab> crabs = new ArrayList<Crab>(); // list of crab monster

}

I can’t figure how to manage the coding of the Monster movement. In interface ModeType, it does not access to position attribute of Crab or Octopus Class. So it cannot modify the position according to the type of move. Do i have to pass object Crab and Island in parameter to the move method of interface ? It seems strange to me…

I feel a little lost and fear to be in the wrong way with this implementation.

I would appreciate some hints of OOP skilled coder.

Thanks

You have a good challenge there. I cannot provide a straight answer as I will need to do a couple of iterations in my head to provide a good proposal. However, using an interface here in your game seems to be a good approach. The interface could contain the x,y position of your “Movable” object. I am not 100% sure, but you can have another interface that describes the dimensions of the object, say interface “Body”. For example, a monster, your ship, the island all has dimensions (width and height if they are represented by squares, for example)

Now, monster, your ship and islands will implement these two interfaces. Movable can define an internal function that accepts an object that implements “Body”. This works well because an object that implements Body means that it has a width and a height, so you can tap in into the object and do the boundary checking. This should work.

Maybe you want to explore this next post where I did a demo of static and dynamic squares. It does not use interfaces but you can see an OOP implementation, although I am sure you can find many other good examples here in the forum: How to use mouseClicked to only effect one object in ArrayList?

Finally, I will suggest to make your Monster an abstract class. The reason is that your game will not implement a monster ever but you will always have either a crab or an octopus. Sorry I cant provide code today but I hope this gives you some push in the right direction.

Give it a try and share your questions if something here is not clear.

Kf

Thank You kfrajer. I will try to adapt the code in the direction you pointed and will come back in a few days with the results.

Well, i managed to make it work.

Monster class is now abstract as her display method. It has an interface MoveType reference.

abstract class Monster{
 PVector pos;
 ConstrainMoveMode moveType;
 
 Monster(int _posX, int _posY)
   {pos=new PVector(_posX,_posY);}

 abstract void display();

 void move(Island i){ 
   moveType.move(this,i); // calling generic interface method move
   }

} // end of Class Monster

Crab class extends Monster class and her display method. Her constructor take a MoveType class implementation as a parameter.

class Crab extends Monster {
  
  Crab(int _posX, int _posY,ConstrainMoveMode mt){
    super(_posX,_posY);
    moveType= mt; // affecting move pattern
  }//end of constructor
  
  void display()
   {
   noStroke();fill(200);
   rect(pos.x,pos.y,10,10);
   }
  
} // end of subclass Crab

The MoveType interface defines a move method taking an Island and a Monster as parameters.
ConstrainHorizontalMove implements MoveType so the move method manage to make the monster going only horizonataly.
ConstrainVerticalMove does the opposite.

interface ConstrainMoveMode{
  void move(Monster m, Island i);
}

class ConstrainHorizontalMove implements ConstrainMoveMode {
  int speed=+5;
  void move(Monster m, Island i){
    if (((m.pos.x+speed)<=(i.pos.x+i.w)) && (m.pos.x+speed)>=(i.pos.x))
      {m.pos.x=m.pos.x+speed;}
    else {speed=-speed;}
   }
}

class ConstrainVerticalMove implements ConstrainMoveMode {
  int speed=+3;
  void move(Monster m, Island i){
    if ((m.pos.y+speed)<=(i.pos.y+i.h)&&(m.pos.y+speed)>=(i.pos.y))
      {m.pos.y=m.pos.y+speed;}
    else {speed=-speed;}
    
   }
}

Here is the Island Class

class Island{
  PVector pos;
  int w,h;
  ArrayList<Crab> crabs = new ArrayList<Crab>();
  
  Island(PVector _pos, int _w, int _h){
    pos=new PVector(_pos.x,_pos.y);
    w=_w;h=_h;
  }//end of constructor
  
  void display(){
    fill(150);
    noStroke();
    rect(pos.x,pos.y, w,h);
  }
  
  void addMonster(Crab newCrab){
    crabs.add(newCrab);
  }

}//end of Island class

And finally the main programm which runs all :


ConstrainHorizontalMove chm = new ConstrainHorizontalMove(); // moving pattern horizontal 
ConstrainVerticalMove cvm = new ConstrainVerticalMove(); // moving pattern vertical
Island i; // the island which will contain the 2 crabs

void setup(){
  size(800,800);
  i= new Island(new PVector(100,100),500,300);
  i.addMonster(new Crab(300,150,chm)); // creating Crab1 with horizontal move pattern
  i.addMonster(new Crab(300,300,cvm)); // creating Crab2 with vertical move pattern
}

void draw(){
  background(250);
  i.display();
  for (int j=0;j<i.crabs.size();j++)
    {
    i.crabs.get(j).display();
    i.crabs.get(j).move(i);
    }
}

It works :wink:

One refinement is probably to extract the Monster position from the Monster Class and to put it in ModeType class Implementation but it the calling method to get monster position will be very weird : example : Crab.MoveType.getX / Crab.MoveType.getY … not very elegant.

Any Suggestion to improve it ?

You could create an abstract base class then extend that to two subclasses, one of those implementing an interface, then extend those subclasses to children that either need the interface or not.

Crab crab;
Octopus octo;

void setup() {
  size(400, 400);

  crab = new Crab();
  octo = new Octopus();

  crab.render();
  octo.display();
}

interface IMonster {
  void move();
}

abstract class Monster {

  Monster() {
  }

  abstract void display();
}

class MonsterDynamic extends Monster implements IMonster {

  MonsterDynamic() {
  }

  void display() {
    println("I am a dynamic monster");
  };
  void move() {
    println("watch me move");
  };
}

class MonsterStatic extends Monster {

  MonsterStatic() {
  }

  void display() {
    println("I am a static monster");
  };
}

// Crab moves
class Crab extends MonsterDynamic {

  Crab() {
  }

  void display() {
    println("Crab");
    super.display();
  }
  void move() {
    super.move();
  }

  void render() {
    display();
    move();
  }
}

class Octopus extends MonsterStatic {

  Octopus() {
  }

  void display() {
    println("Octopus");
    super.display();
  }
}