3

I have a game that runs on a similar system to games like terraria or minecraft, at least in the aspect of being blocky.

I have constructed it in a way where each block is an Object, and there is a specific class (extends a BlockObject archetype) for each type of block.

I have the game save the blocks in a file like following

I get the name of the instance of the Object i am saving, and store it in a string I start writing the information of the given Object in a string that has the Name of the Class(signifieing what type of block it is Ex. a block that is an object of BlockGrass.java would be stored as BlockGrass). Normally when reading information from a save file I am reading the save file, when it gets to the info of the blocks it first saves the Block type in a local string (BlockGrass in this case), also saves the positions (x cordinate, and y cordinate). Then it would run through a series of if statements like the following

if(blockType.equals("BlockGrass"))
{
blocksArray.add(new BlockGrass(...));
}
else if(blockType.equals("BlockStone"))
{
blocksArray.add(new BlockStone(...));
}
etc

now I want to make my game vary dynamic, and want it so that if someone decides to make a new Block class (Modding the game) they do not have to modifiey the MapReader class. so instead of running through a series of if statements as shown above (where everytime a new block class is created, a new if statement must be placed for that block), i want it so that it make a new object of a class that has the same name as the BlockType. to give you a better idea look at the following

BlocksArray.add(new blockType(...));

the reason what is shown above does not work is because blockType is a string that holds the name of the class i want to use. not a Class Name

How could i do something like that?, without using if-statements.

4
  • 4
    Use Class.forName(String).newInstance(); Commented Apr 9, 2015 at 1:30
  • 1
    Seems like you're re-inventing serialization? Commented Apr 9, 2015 at 1:31
  • @redge although that does give me the instance of the class, i cannot do .add(new Class.forName(String).newInstance()); Commented Apr 9, 2015 at 1:34
  • Create a generic factory which receives a blocktype that should extends a super class then you just pass the blockType reference and returns the right instance of your blockType... Commented Apr 9, 2015 at 1:41

2 Answers 2

1

What you are trying to do is to take advantage of polymorphic behaviours from your BlockObject hierarchy. Therefore using class.forName is the good approach. Once you have invoked newInstance()on the Class variable you will need to cast it to the base class (the archetype as you called it) of your hierarchy of BlockObject class. We have guarantee that since the real class is extending BlockObject, it is a BlockObject according to the definition of inheritance.

Here is an example

public class GameLoader {

    private List<BlockObject> blocksArray = new ArrayList<BlockObject>();

    public Object getNewBlock(String blockClassName) throws     ClassNotFoundException, InstantiationException, IllegalAccessException {

        Class blockClass = Class.forName(blockClassName);
        return blockClass.newInstance();

    }

    public void addNewBlockType(String typeName) throws     ClassNotFoundException, InstantiationException, IllegalAccessException {

        BlockObject castedType = (BlockObject)getNewBlock(typeName); 
        blocksArray.add(castedType);
    }
}

Any method of the base class invoked on such object will display polymorphic behaviours.

Sign up to request clarification or add additional context in comments.

4 Comments

Now i have a question, what about the constructor, I am assuming it is not called in this case?
@yoseph1998, yes it is called Class.newInstance() Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list.(see: docs.oracle.com/javase/7/docs/api/java/lang/… ). Therefore if you customize the constructor, be sure to provide a similar constructor to the default constructor
If you need to call a construction that has arguments you will need to dip into the reflection API and call blockClass.getConstructor (....).newInstance(...) docs.oracle.com/javase/7/docs/api/java/lang/…
Now I have a question? concatonating it to the parent class removes some functionality, like if there are more methods in block with the unknown type, but not the BlockObject class. also what if the constructors on the unknown block are not the same as the BlockObject.
0

This is not compiled and checked but it is just to indicate what must be done.

// first get the class
Class<?> rawclass = Class.forName(String);
// then check an object will fit where you want it.
if (BlockObject.class.isAssignableFrom(rawclass)){
      // create the object, cast it to the correct type and add it
      BlockObject object = (BlockObject) rawclass.newInstance();
      blockArray.add(object);
}

There will be some exceptions to catch out of the forName and newInstance methods.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.