[TUTORIAL] Making non-cuboid Collision Boxes (1.14/1.15/1.16) (Forge/Fabric)

Started by NOYB on

Topic category: User side tutorials

Last seen on 06:40, 15. Feb 2021
Joined May 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
[TUTORIAL] Making non-cuboid Collision Boxes (1.14/1.15/1.16) (Forge/Fabric)
Thu, 08/27/2020 - 07:36 (edited)

Making a non-cuboid Shaped Block

You need some Java knowledge for this tutorial.

Before starting this tutorial keep in mind that this tutorial will require you to lock your block element and you can't change any of your block properties without coding after locking the element. So make sure before adding a custom shape to your block, your block is complete.

Also give your block a cubiod shape other than a full cube to save some work and all of the things here must be done under CustomBlock class so find the line below and do the things here under it.

public static class CustomBlock extends Block {...

Block can be something else if your block is horizontal.

If you are using Fabric Generator, it must look something like below:

public class [YourBlock]Block extends block {...

Classes could be implementing things so this might change.


For Forge 1.15.x/1.16.x (and probably 1.14.x):

First lets see how a cuboid shape is done in Forge.

Block.makeCuboidShape(x1, y1, z1, x2, y2, z2)

This is how you make a cuboid collision box. xyz1 are the start coords of your box and xyz2 are the end coords. Game will automatically create a cube from xyz1 to xyz2.

Now lets create a weird shape using multiple collision boxes:

private static final VoxelShape SHAPE = VoxelShapes.or(Block.makeCuboidShape(6, 0, 6, 10, 13, 10), Block.makeCuboidShape(0, 13, 0, 16, 16, 16)).simplify();

This shape looks like a table with a centered leg. You can also do this like below for better understanding:

private static final VoxelShape SHAPE = VoxelShapes.or(
    Block.makeCuboidShape(6, 0, 6, 10, 13, 10),
    Block.makeCuboidShape(0, 13, 0, 16, 16, 16)
    ).simplify();

This is a VoxelShape/collision box named SHAPE. You can name your shape anything you want but SHAPE is what most people use.
Now we need to bind this shape to our block. This part is very simple just find the override below:

@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
     return [Your Current Shape];
}

And replace your current shape with your shapes name. In our case it must be like below:

@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
    return SHAPE;
}

 And thats it, if you copy pasted the code you'll also need add the imports below:

import net.minecraft.util.math.shapes.VoxelShapes;

What if my block is Horizontal?

If your shape is symetrical, you dont need to do anything, if your shape is not symetrical, then read below.

First make voxelshapes for every direction like below:

private static final VoxelShape SHAPE_NORTH = VoxelShapes.or(Your blocks shape from north);
private static final VoxelShape SHAPE_SOUTH = VoxelShapes.or(Your blocks shape from south);
private static final VoxelShape SHAPE_WEST = VoxelShapes.or(Your blocks shape from west);
private static final VoxelShape SHAPE_EAST = VoxelShapes.or(Your blocks shape from east);

Then again find the override but this time it must look something like below:

@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) {
    switch ((Direction) state.get(FACING)) {
        case UP :
        case DOWN :
        case SOUTH :
        default :
            return [Your Current South Shape];
        case NORTH :
            return [Your Current North Shape];
        case WEST :
            return [Your Current West Shape];
        case EAST :
            return [Your Current East Shape];
    }
}

And replace the shapes accordingly like below:

@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) {
    switch ((Direction) state.get(FACING)) {
        case UP :
        case DOWN :
        case SOUTH :
        default :
            return SHAPE_SOUTH;
        case NORTH :
            return SHAPE_NORTH;
        case WEST :
            return SHAPE_WEST;
        case EAST :
            return SHAPE_EAST;
    }
}

And thats it!


For Fabric 1.16.x:

First lets see how a cuboid shape is done in Fabric.

Block.createCuboidShape(x1, y1, z1, x2, y2, z2)

As you can see its very similar with forge.
Now lets recreate the table shape we created above using Fabric.

private static final VoxelShape SHAPE = VoxelShapes.union(Block.createCuboidShape(6, 0, 6, 10, 13, 10), Block.createCuboidShape(0, 13, 0, 16, 16, 16));

Again you can do this like below for simplicity:

private static final VoxelShape SHAPE = VoxelShapes.union(
    Block.createCuboidShape(6, 0, 6, 10, 13, 10),
    Block.createCuboidShape(0, 13, 0, 16, 16, 16)
    );

Now again find the override, which must look something like below:

@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
    return [Your Current Shape];
}

And again replace your curent shape with your shape. It must look something like below:

@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
    return SHAPE;
}

You dont need to import extra classes in Fabric.

What if my block is Horizontal?

If your shape is symetrical, you dont need to do anything, if your shape is not symetrical, then read below.

Again make multiple voxelshapes for your block, one for every direction like below:

private static final VoxelShape SHAPE_NORTH = VoxelShapes.union(Your blocks shape from north);
private static final VoxelShape SHAPE_SOUTH = VoxelShapes.union(Your blocks shape from south);
private static final VoxelShape SHAPE_WEST = VoxelShapes.union(Your blocks shape from west);
private static final VoxelShape SHAPE_EAST = VoxelShapes.union(Your blocks shape from east);

Then again find the override which must look something like below:

@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
    switch ((Direction) state.get(FACING)) {
        case UP :
        case DOWN :
        case SOUTH :
        default :
            return [Your Current South Shape];
        case NORTH :
            return [Your Current North Shape];
        case WEST :
            return [Your Current West Shape];
        case EAST :
            return [Your Current East Shape];
    }
}

And again replace the shapes accordingly like below:

@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
    switch ((Direction) state.get(FACING)) {
        case UP :
        case DOWN :
        case SOUTH :
        default :
            return SHAPE_SOUTH;
        case NORTH :
            return SHAPE_NORTH;
        case WEST :
            return SHAPE_WEST;
        case EAST :
            return SHAPE_EAST;
    }
}

And you're done! Enjoy your non-cuboid collision boxed blocks. 😀


If you come across with any issues, you can post them below. Also don't forgot to give your log and code using a website like pastebin, etc..

(Please don't just copy paste the whole log 😢☹️👿)

Edited by NOYB on Thu, 08/27/2020 - 07:36
Last seen on 06:40, 15. Feb 2021
Joined May 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Thanks
Wed, 08/26/2020 - 10:40

Thanks

Amazing tutorial! I think it…
Wed, 08/26/2020 - 21:00

Amazing tutorial! I think it will help a lot of users(like me, when I will continue to make mods). I'm glad to see you also want to make the tutorial for an unofficial plugin! :D

Last seen on 06:40, 15. Feb 2021
Joined May 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Thanks, I'm glad I can help…
Thu, 08/27/2020 - 05:56

Thanks, I'm glad I can help you and other users. I'll add Fabric once I finish it, their isn't much diffrence between them anyway.

Last seen on 06:40, 15. Feb 2021
Joined May 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
(Finally) 🙃 added Fabric 
Thu, 08/27/2020 - 07:38

(Finally) 🙃 added Fabric 

Last seen on 19:32, 20. Sep 2020
Joined Apr 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Marry me!  <3
Thu, 08/27/2020 - 17:21

Marry me!  <3

Last seen on 13:59, 19. May 2023
Joined Jul 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
O_o (replying to chrishiss)
Sat, 09/12/2020 - 05:20

O_o (replying to chrishiss)

Last seen on 04:42, 20. May 2023
Joined Oct 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Hi! I'm trying to make a…
Sun, 12/06/2020 - 06:09

Hi! I'm trying to make a block with a custom collision box using this tutorial. It all mostly makes sense to me, except for this part:

private static final VoxelShape SHAPE_NORTH = VoxelShapes.or(Your blocks shape from north);
private static final VoxelShape SHAPE_SOUTH = VoxelShapes.or(Your blocks shape from south);
private static final VoxelShape SHAPE_WEST = VoxelShapes.or(Your blocks shape from west);
private static final VoxelShape SHAPE_EAST = VoxelShapes.or(Your blocks shape from east);

I'm not entirely sure what I should be putting in the parentheses? I've had experience with coding in the past before, but I can't find any documentation on VoxelShapes and I don't really know what to do here. Please help!

Last seen on 06:40, 15. Feb 2021
Joined May 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Sorry for the late reply,…
Mon, 12/07/2020 - 09:10

Sorry for the late reply, you need to put one or more shapes in parentheses
A shape:

Block.makeCuboidShape(minX, minY, minZ, maxX, maxY, maxZ)

After each line, put a comma (,) to seperate the each shape, except the last one

Example:

VoxelShapes.or(
    Block.makeCuboidShape(minX, minY, minZ, maxX, maxY, maxZ),
    Block.makeCuboidShape(minX, minY, minZ, maxX, maxY, maxZ),
    Block.makeCuboidShape(minX, minY, minZ, maxX, maxY, maxZ)
);

minX, minY, minZ, maxX, maxY, maxZ must be numbers (min 0, max 16)

A proper example:

VoxelShapes.or(
    Block.makeCuboidShape(8, 0, 8, 0, 16, 0),
    Block.makeCuboidShape(13, 4, 13, 5, 8, 5)
);

 

Last seen on 04:42, 20. May 2023
Joined Oct 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Thanks so much! Wouldn't…
Tue, 12/08/2020 - 02:16

Thanks so much! Wouldn't have figured that out on my own, this helps a lot!

Last seen on 23:32, 28. Mar 2022
Joined May 2019
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
How do I do on with this?  …
Mon, 02/22/2021 - 02:26

How do I do on with this?

 

Stream.of(
Block.makeCuboidShape(1, 0, 1, 15, 1, 15),
Block.makeCuboidShape(4, 1, 4, 12, 16, 12),
Block.makeCuboidShape(10, 1, 2, 14, 12, 6),
Block.makeCuboidShape(2, 1, 2, 5, 8, 6),
Block.makeCuboidShape(9, 1, 10, 13, 9, 14),
Block.makeCuboidShape(3, 1, 9, 7, 6, 13)
).reduce((v1, v2) -> {return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);});