This site requires JavaScript, please enable it in your browser!
Greenfoot back
RcCookie
RcCookie wrote ...

2020/6/2

How to create an object of which only the super class is known

RcCookie RcCookie

2020/6/2

#
I am trying to code a factory style game in which recources travel on belts and factory buildings craft them into other recources. I've got the belts and the most of the general building functionality running, but I can't think of a way to export(--> put on belt) a recource of which I don't know the exact class of. I only know that every Recources superior class is the recoruce class, which is enough to sort the input, however, I have to create the specific type of recource that the crafting recepie produces. In the worst case I had to put all the information about the different recoruces into the recource class and not use subclasses, but I had to rewrite a lot of the code for the input and storage buffer. Here's the building class code, which all actual buildings are going to extend from:
import greenfoot.*;
import java.util.HashMap;
public abstract class Building extends Connectible{
    private HashMap<Class<? extends Recource>, Integer> inputBuffer;
    private HashMap<Class<? extends Recource>, Integer> outputBuffer;
    protected final Recepie recepie;
    
    private int counter;
    
    public Building(Recepie recepie){
        super(ConveyorBelt.CONVEYOR_SPEED);
        this.recepie = recepie;
        inputBuffer = new HashMap<Class<? extends Recource>, Integer>();
        outputBuffer = new HashMap<Class<? extends Recource>, Integer>();
        for(Class<? extends Recource> r : recepie.input.keySet()){
            inputBuffer.put(r, 0);
        }
        for(Class<? extends Recource> r : recepie.output.keySet()){
            outputBuffer.put(r, 0);
        }
        GreenfootImage image = new GreenfootImage(20, 20);
        image.setColor(Color.RED);
        image.fill();
        setImage(image);
    }
    public void act(){
        //try crafting a new object
        craft();
        //manage crafting time
        if(--counter==0){
            for(Class<? extends Recource> r : recepie.output.keySet()){
                produce(r, recepie.output.get(r));
            }
        }
        else if(counter<0)counter = 0;
        //try to export onto belt or similar
        if(getNext()!=null&&
           outputBuffer.keySet().size()>0&&
           getNext().canInput()&&
           export((Class<? extends Recource>)(outputBuffer.keySet().toArray()[0]))){
            
            //This is where I want to add the recource that is being produced
            //by this recepie. However, I can't think of a way to do so. For
            //simplicity, I just want to export the first recource in the output.
            
            getWorld().addObject(new Recource(getNext()){}, 0, 0);
        }
    }
    private Class<? extends Recource> getFirst(){
        return null;
    }
    
    public String toString(){
        return getClass() + ":" + recepie + ",{" + inputBuffer + "," + outputBuffer + "}";
    }
    
    public void craft(){
        if(counter!=0){
            System.out.println("Crafting is running");
            return;
        }
        for(Class<? extends Recource> r : recepie.input.keySet()){
            if(inputBuffer.get(r) < recepie.input.get(r)){
                System.out.println("Too little input");
                return;
            }
        }
        for(Class<? extends Recource> r : recepie.output.keySet()){
            if(outputBuffer.get(r) + recepie.output.get(r) > Recource.STACKSIZE){
                System.out.println("Too little output space");
                return;
            }
        }
        for(Class<? extends Recource> r : recepie.input.keySet()){
            use(r, recepie.input.get(r));
        }
        counter = recepie.craftTime;
        System.out.println("Crafting...");
    }
    
    public boolean input(Class<? extends Recource> r){
        if(inputBuffer.containsKey(r)&&inputBuffer.get(r) < Recource.STACKSIZE){//r.STACKSIZE){
            inputBuffer.put(r, inputBuffer.get(r) + 1);
            return true;
        }
        return false;
    }
    protected boolean use(Class<? extends Recource> r, int count){
        if(inputBuffer.containsKey(r)&&inputBuffer.get(r) >= count){
            inputBuffer.put(r, inputBuffer.get(r) - count);
            return true;
        }
        return false;
    }
    protected void produce(Class<? extends Recource> r, int count){
        outputBuffer.put(r, outputBuffer.get(r) + count);
    }
    public boolean export(Class<? extends Recource> r){
        if(outputBuffer.containsKey(r)&&outputBuffer.get(r) > 0){
            outputBuffer.put(r, outputBuffer.get(r) - 1);
            return true;
        }
        return false;
    }
    
    @Override
    public int X(){
        return getX();
    }
    @Override
    public int Y(){
        return getY();
    }
}
Tip: The important part is in the act method;-) If you need the other classes too, I can put the source code here, too, but I think this should be enough. Here's the hirarchy: Actor ->Connectible(abstract) --->Building(abstract) ----->Smelter --->ConveyorBelt ->Recource(abstract) --->IronOre --->IronIngot Recepie I hope you can help me!
danpost danpost

2020/6/2

#
Maybe you can have the Recepie class create the new Recource object (of specific type) and then have the Building class fetch the created object. It would seem like the creation of the new object from the given resources would be the behavior of the Recepie class, anyway.
RcCookie RcCookie

2020/6/3

#
That’s a great idea. I’ll try that out soon
RcCookie RcCookie

2020/6/4

#
I finally got to implement it, and it works, so thanks!
You need to login to post a reply.