Best Way to Register Blocks/Entities

Wow, it’s been a while since I posted a question.

I finally re wrote my rendering system for my puzzle game that I restarted a while ago and I need a good way to register blocks. Here is what the game looks like so you can get a feel for what I have:

So there are blocks, but I need a way to register the different types. Eg, trampoline block, or normal wall block and so forth. Right now I am just creating a new instance of the class of that block which then registers a Box to jME. I then join all the meshes together at the end of building the current level. So performance isn’t a problem.
What’s the best way to approach it so that I can, in the level creation code, call:


        makeBlock(new Vector3f(3, 40, 40), Block_Wall.class);

Therefore, creating the block of whichever block.class I put in there?
The constructor for the makeBlock is:


    public void makeBlock(Vector3f pos, Class<? extends BlockSuper> block){
        blocks[(int) pos.x][(int) pos.y][(int) pos.z] = new BlockSuper(main, new Vector3f(pos.x, pos.y, pos.z), level);
        blocks[(int) pos.x][(int) pos.y][(int) pos.z].setUpPhysics();
    }

So as you can see I just create a BlockSuper there, which is the superclass for all blocks. I need to take the .class of whatever block I want there and create an instance of it from that. I know about reflection:


        try {
            Class<?> clazz = Class.forName("Engine.Blocks.BlockSuper");
            Constructor<?> constructor = clazz.getConstructor(Main.class, Vector3f.class, Node.class);
            Object instance = constructor.newInstance(main, pos, level);
        } catch(Exception e){
            e.printStackTrace();
        }

However I really don’t know if this is what I should be using, as it is a rather new concept to me.
Thanks for any help.

Why do you think that it is unfeasible to just “register” already build block instances?

Could you elaborate?

why not


public void makeBlock(BlockSuper block) {...}

makeBlock(new BlockWall(main, new Vector3f(3, 40, 40)));

Oh you’re right… I was half asleep or something. Sometimes I get retarded like that. My bad.

However, I do need to create walls and stuff. This is the wall creation code:


    public void makeWall(Vector3f startPos, Vector3f endPos, Class<? extends BlockSuper> block) {
        for (int x = (int) startPos.x; x <= endPos.x; x++) {
            for (int y = (int) startPos.y; y <= endPos.y; y++) {
                for (int z = (int) startPos.z; z <= endPos.z; z++) {
                    makeBlock(x, y, z, block);
                }
            }
        }
    }

So just creating a new instance for that won’t work.

In this case you could use factories


interface BlockFactory<T extends BlockSuper>
{
  public T create(Vector3f pos);
}

public static final BlockFactory<WallBlock> wallBlockFactory = new BlockFactory<> { 
  public WallBlock create(Vector3f pos){
    return new WallBlock(main, pos);
  } 
}

makeWall(start, end, wallBlockFactory);

Thanks :slight_smile:

It would seem that factories are basically just things to create new objects of a class that extends another one, but you don’t know which subclass it will be. Why not just use reflection? Please correct me if I’m wrong, I know next to nothing about factories.

Actually, I did some research and didn’t find much on the subject. Would you mind giving a very brief explanation of them?

A factory is a class or group of functions that creates a “new” instance of an object in java. It is useful for tile maps because each tile is different and needs a different object. If you didn’t have a factory you run the risk of overwriting tile data in more than one tile.

In short, factories just make sure that each tile can store its own data.

Wikipedia does a good job of explaining it, and even includes some examples in Java:


Okay, that makes sense.
So this bit of code here:


interface BlockFactory<T extends BlockSuper>
{
  public T create(Vector3f pos);
}

Is obviously just an interface I would have to implement in my Level class, correct?

And then this bit:


public static final BlockFactory<WallBlock> wallBlockFactory = new BlockFactory<> { 
  public WallBlock create(Vector3f pos){
    return new WallBlock(main, pos);
  } 
}

Is the piece that creates the new object. The only thing I don’t get about this is that you wrote it as creating WallBlocks instead of the superclass, BlockSuper. Does this mean I have to create one of these methods (or are these their own weird classes… Unfamiliar syntax for me) for every single block I make, or did you mean to put the superclass and accidentally wrote WallBlock? If it’s not the latter it doesn’t seem very dynamic, no?

Then this code:


makeWall(start, end, wallBlockFactory);

Is the bit that actually makes the blocks. This is the bit that leads me to believe that I have to create one of those strange

public static final BlockFactory<WallBlock> wallBlockFactory = new BlockFactory<> { ... }

things for each individual block.

Yes, you would have to create a factory for each block type you have. In my previous code I created an anonymous class and stored it in a “singleton”, I did it that way so that you don’t need to create a new instance of the factory on each “makeBlock” call.

The benefits of not using reflection for this task is type safety and better performance.

So this is not very dynamic is it? Let’s say we have a game with many, many blocks, like the game Minecraft. Does that game use factories? It seems for a game like that this way would not be very good at all.

Excuse me if I’m being a bit irritating, I am trying to get as in depth as possible in order to fully understand it. Feel free to tell me to back off :slight_smile:

You perhaps have to rethink your solution. Why not have only one data class for Blocks with a type component:


public class Block
{
  public enum Type { Wood, Concrete, Metal; } 
  
  public final Type type;
}


How would that let one do specific things with a single type? Let’s say I want to do something when the player ball rolls onto a block, like fill his hearts back up. Wouldn’t I need a specific subclass like, RegenBlock or something that overrides onPlayerCollide(PlayerBall player)?

Doing it like Minecraft? Here is how:
‘Fake’-Singletons, and flat binary data.

More detailed description:

You have one super class called ‘Block’.
This class could look like this:


abstract class Block
{
  String genericName;

  public Block(String genericName)
  {
    this.genericName = genericName;
  }

  public void onPlayerCollide(Player p, int thisBlockX, int thisBlockY, int thisBlockZ){/**Empty**/}
  public void onPlayerClick(Player p, int thisBlockX, int thisBlockY, int thisBlockZ){/**Empty**/}
}

Then you have classes like this:


class RegenBlock extends Block
{
  RegenBlock()
  {
    super("regenBlock");
  }

  public void onPlayerCollide(Player p, int thisBlockX, int thisBlockY, int thisBlockZ)
  {
    p.health++;
  }
}

+////////////////////////////////////////

class ButtonBlock extends Block
{
  ButtonBlock()
  {
    super("buttonBlock");
  }
  
  public void onPlayerClick(Player p, int thisBlockX, int thisBlockY, int thisBlockZ)
  {
    // Do what a button does.
  }
}

Then you have a special class, which stores the existing block-types (not the blocks themself!):


class BlockList
{
  Block[] blockList;

  public BlockList()
  {
     blockList = new Block[256];
     blockList[0] = new BlockAir();
     blockList[1] = new RegenBlock();
     blockList[2] = new ButtonBlock();
  }
}

Then you have a chunk-class, like this.
It only stores integers which are nothing more than indexes into the BlockList’s “blocks” array.


class Chunk
{
    <any-structure-that-can-store-integers> blocks;
    
    public Chunk()
    {
        // set block
        blocks(blabla-integer-setter x/y/z) = 0; // 0 is 'BlockAir' in the BlockList's 'blocks' array.
        blocks(blabla-integer-setter x/y/z) = 1; // 1 is 'RegenBlock' in the BlockList's 'blocks' array.
    }
}

Now then we have this:


// In the method section which does collision and stuff.
int blockColllidedWithX = ...;
int blockColllidedWithY = ...;
int blockColllidedWithZ = ...;
int blockData = ... This is the integer we get from a Chunk's block data-structure.

BlockList[blockData].onPlayerCollide(player, blockColllidedWithZ, blockColllidedWithY, blockColllidedWithZ);

Note that:

  • This is quite a long piece of code, written in a haste, so I probably forgot something.
  • Read this post multiple times, until you understand it.
  • This can also be optimized a LOT, and can be made much more dynamic.
  • If you don’t understand something, ask me or anyone that understands this.

Have a nice day!

  • Longor1996

That’s a very nice approach actually, it makes it so that I only need to create one instance of each block. There are only a few downers I can see that can come from using this approach! I’ll go and code it all in and report back if I have any problems. Thanks a bunch!

Edit:

Okay I decided to go with Factories as I decided that I really don’t need a large amount of blocks. Because of my collision system sometimes I was getting null when colliding with something because of some positioning readjustments I had to do. So I ended up making one instance of a new class, Block_Air, and setting everything that wasn’t occupied to that one instance. Obviously there are some drawbacks to that, but hey, it works.

Thanks a lot for the help guys. By the way, I re did some of the rendering stuff, check out how it looks now: