Help with object oriented programming

I have an abstract class Building and a class Factory1 that extends Building
and a class Factory2 that also extends Building.
Every instance of a building like a factory has the same radius,
but Factory1 and Factory2 don't have the same radius.

Every factory is saved as Building, so I have to access their radius as Building.

I saved the radius like this:

class Building{
  public int radius;
}

and

class Factory1{
  Factory(){
    radius = 42;  //custom radius
  }
}

But now I've got a problem, because when I build a factory, I first have to check if thre's enough space.
So when I build an instance of Factory1, I need the radius of Factory1
before even an instance ofFactory1 exists.

What is the cleanest way to solve this?

Answers

  • edited March 2015

    Your requests are very confused. But let's give it a try: 3:-O

    Every instance of a building like a factory has the same radius,...

    Perhaps declare it as static then? static int rad = 100;

    ... but Factory1 and Factory2 don't have the same radius.

    Well, so their fields can't be static as Building: int rad;

    I first have to check if there's enough space.

    Does it mean check whether Factory1 and Factory2 don't get a radius > Building's?

      Factory1(int radius) {
        rad = radius < super.rad? radius : super.rad;
      }
    

    Here's an attempt example. Sorry you're gonna need to be more specific than that: :|

    static abstract class Building {
      static int rad = 100;
    }
    
    class Factory1 extends Building {
      int rad;
    
      Factory1(int radius) {
        rad = radius < super.rad? radius : super.rad;
      }
    
      @ Override String toString() {
        return "" + rad;
      }
    }
    
    void setup() {
      println(new Factory1(200));
      println(new Factory1(50));
      exit();
    }
    
  • edited March 2015

    But now I've got a problem, because when I build a factory, I first have to check if there's enough space.

    So you only want to build the factory if you have space and the new command will always return an object.

    In OOP the solution is to use the Factory Design Pattern (this is the name of the pattern and the use of 'factory' is not because of your class names) which effectively means providing a method that creates and returns objects based on the parameters.

    The code below does just that, it first declares two constants to represent the type of building required i.e. Factory1 or Factory2. The Building class has been declared abstract.

    Each of the Factory classes has its own static attribute RAD which represents the Factory radius.

    Since we are using static methods and attributes all the classes must be declared static so they will be treated as top level classes.

    The code is fairly self explanatory, the setup code attempts to create 4 factories 2 which are OK and 2 where there is not enough space.

    static final int FACTORY1 = 1;
    static final int FACTORY2 = 2;
    
    void setup(){
      Building b;
    
      b = Building.makeFactory(FACTORY1, 50); // OK
      println(b);
    
      b = Building.makeFactory(FACTORY1, 30); // Not OK
      println(b);
    
      b = Building.makeFactory(FACTORY2, 70); // OK
      println(b);
    
      b = Building.makeFactory(FACTORY2, 50); // Not OK
      println(b);
    }
    
    static abstract class Building {
      public int radius;
    
      /*
       Create a Factory of the required type if there is 
       sufficent space. If not then return null
       type = factory type
       maxRadius max radius (space) available
       */
      static Building makeFactory(int type, int maxRadius) {
        Building b = null;
        switch(type) {
        case FACTORY1:
          if (Factory1.RAD <= maxRadius)
            b = new Factory1();
          break;
        case FACTORY2:
          if (Factory2.RAD <= maxRadius)
            b = new Factory2();
          break;
        }
        return b;
      }
    
      String toString(){
        return (getClass().getSimpleName() + "  radius = " + radius);
      }
    }
    
    static class Factory1 extends Building {
    
      static final int RAD = 42;
    
      Factory1() {
        radius = RAD;  //custom radius
      }
    }
    
    static class Factory2 extends Building {
    
      static final int RAD = 60;
    
      Factory2() {
        radius = RAD;  //custom radius
      }
    }
    
  • edited March 2015

    The problem is, that it is a multiplayer, so i first have to know,
    if it's possible, and then send the command to create a building on both client- sides.

    And I will create more subclasses of Building, so it could get complicated this way.

    the space question is just a bunch of code that outputs a
    boolean and uses the radius and tests for possible collisions with other buildings:

    boolean isEnoughSpace(int radius);
    
  • edited March 2015

    That's how i create a building at the moment:

    public class BuildAim extends Aim {
        Class building;
    
        PImage previewImg;
    
        public BuildAim(Class building) {
            this.building = building;
            try {
                Method m = building.getMethod("preview");
                previewImg = (PImage) m.invoke(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        void update() {//will update every gametick
            float x, y;
            x = Building.xToGrid(Building.gridToX());
            y = Building.xToGrid(Building.gridToY());
            if (canPlaceAt(x, y)) {
                ref.app.tint(255, 150);//ref.app is the PApplet
            } else {
                ref.app.tint(255, 100, 100, 150);
            }
            ref.app.image(previewImg, x, y / 2, 60, 60);
            ref.app.tint(255);
    
        }
    
        boolean canPlaceAt(float x, float y) {
            return true;//test for space
        }
    
        void execute() {//will update on buildcommand
            float x, y;
            x = Building.xToGrid(Building.gridToX());
            y = Building.xToGrid(Building.gridToY());
            if (canPlaceAt(x, y)) {
                ClientHandler.send("<spawn " + building.getSimpleName() + " 0 " + x
                        + " " + y );
            }
        }
    }
    
  • are there other possibilities to solve this?

  • I assume you are using a client server setup to manage multi player implementation, in which case a request would be sent to the server asking for a new building. The server would decide whether the building can be built.

    If not then it sends a message back to the originating player saying its not possble. If the building is permitted then the server would send a message to ALL players to create the building. The message would include sufficient information to instantiate the object.

  • edited April 2015

    but I want to know if I can build it before sending, because I want
    to color it red if it's not possible. (line 20 - 24)

    at the moment, my server just sends the commands to every player,
    but I will change that, when I figured out how...

  • class Plonk {
      float px, py, r;
      Plonk(float ipx, float ipy, float ir) {
        px=ipx;
        py=ipy;
        r=ir;
      }
      void draw() {
        noStroke();
        fill(255);
        ellipse(px, py, r, r);
      }
    }
    
    ArrayList<Plonk> plonks = new ArrayList();
    float r = 100;
    
    void setup() {
      size(600, 600);
      ellipseMode(CENTER);
    }
    
    void draw(){
      background(0);
      boolean tooClose = false;
      for (int i=0; i<plonks.size(); i++) {
        plonks.get(i).draw();
        if ( dist(plonks.get(i).px, plonks.get(i).py, mouseX, mouseY) <= (plonks.get(i).r + r)/2) {  
          tooClose = true;
        }
      }
      stroke(0,255,0);
      noFill();
      if(tooClose){
        stroke(255,0,0);
        fill(255,0,0,128);
      }
      ellipse(mouseX, mouseY, r, r);
    }
    
    void mousePressed(){
      boolean tooClose = false;
      for (int i=0; i<plonks.size(); i++) {
        if ( dist(plonks.get(i).px, plonks.get(i).py, mouseX, mouseY) <= (plonks.get(i).r + r)/2) {  
          tooClose = true;
        }
      }
      if(!tooClose){
        plonks.add( new Plonk(mouseX,mouseY,r) );
      }
    }
    
    void keyPressed(){
      if(keyCode == UP) r++;
      if(keyCode == DOWN) r--;
    }
    
  • sorry, but the problem is, I want different subclasses of Buildings,
    where every subclass has it's own radius.

    And because there are many subclasses, I'd like a general solution, if possible.

  • Answer ✓

    Use object serialisation to serialise the created object and then send the object.This would require some research to investigate serialisation in general and data streaming.

  • I think this helps. Thank you. :)

    What happens, when the connection is a bit slow?
    Then I would have a delay in optical feedback (line 20-24)?

  • edited April 2015

    hm

  • How bad is this idea?: When I want to build a building, I create an instance of the factory that is not connected to the rest of the game, so it isn't displayed or anything, but I can get the radius and everything I need. And when I click build, it delets the factory and sends a command to the server, that creates the real factory.

    Is this bad programming or should I use this?

  • can someone help?

Sign In or Register to comment.