• Minecraft 1.16.5模组开发(五十四) 方块探测器(Detector)


    我们本次预计实现一个方块探测器,让其可以探测我们想要找到的方块。

    1.我们希望将方块放下后,可以探测以其坐标为中心的16×16×16的范围内是否具有目标方块:

    cr1.jpg

    新建一个方块类BlockBFS,为了方便枚举区域内的方块状态,我们可以采取一种宽度优先搜索(3维BFS)的算法来对区域内的所有方块进行探测:

    BlockBFS.java

    package com.joy187.fanfu.common.blocks;
    
    import net.minecraft.block.*;
    import net.minecraft.block.material.Material;
    import net.minecraft.particles.RedstoneParticleData;
    import net.minecraft.state.BooleanProperty;
    import net.minecraft.state.StateContainer;
    import net.minecraft.state.properties.BlockStateProperties;
    import net.minecraft.tileentity.TileEntity;
    import net.minecraft.util.Direction;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.util.math.shapes.ISelectionContext;
    import net.minecraft.util.math.shapes.VoxelShape;
    import net.minecraft.util.math.shapes.VoxelShapes;
    import net.minecraft.util.math.vector.Vector3d;
    import net.minecraft.world.Blockreader;
    import net.minecraft.world.IBlockReader;
    import net.minecraft.world.World;
    import net.minecraft.world.server.ServerWorld;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.api.distmarker.OnlyIn;
    import net.minecraftforge.common.ToolType;
    
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.Random;
    
    import static java.lang.Math.abs;
    import static net.minecraft.block.BedBlock.getConnectedDirection;
    
    public class BlockBFS extends RedstoneDiodeBlock {
        //3维偏移量
        int[]dx = {1,-1,0,0,0,0};
        int[]dy = {0,0,1,-1,0,0};
        int[]dz = {0,0,0,0,1,-1};
    
        protected static final VoxelShape SHAPE = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D);
        
        //我们的方块有两个属性,一个是朝向,一个是是否充能
        public BlockBFS(AbstractBlock.Properties properties) {
            super(properties);
            this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(POWERED, Boolean.valueOf(false)));
        }
    
        public VoxelShape getCollisionShape(BlockState p_220071_1_, IBlockReader p_220071_2_, BlockPos p_220071_3_, ISelectionContext p_220071_4_) {
            return SHAPE;
        }
    
        public VoxelShape getBlockSupportShape(BlockState p_230335_1_, IBlockReader p_230335_2_, BlockPos p_230335_3_) {
            return VoxelShapes.block();
        }
    
        public VoxelShape getVisualShape(BlockState p_230322_1_, IBlockReader p_230322_2_, BlockPos p_230322_3_, ISelectionContext p_230322_4_) {
            return VoxelShapes.block();
        }
    
        //BFS函数
        private boolean checkBlock(World level, BlockPos pos, BlockState state) {
            boolean[][][] st = new boolean[16][16][16];
            for(int i=0;i<16;i++)
                for(int j=0;j<16;j++)
                    for(int k=0;k<16;k++)
                        st[i][j][k]=false;
    
    
            boolean flag=false;
            //用一个队列,将方块探测器的坐标加入到队列中并将其坐标进行标记(由于mc坐标可能存在负数,我们要对坐标进行取模运算)
            Queue q = new LinkedList();
            q.offer(pos);
            st[(pos.getX()-pos.getX()+8)%16][(pos.getY()-pos.getY()+8)%16][(pos.getZ()-pos.getZ()+8)%16]=true;
            while(q.size()!=0)
            {
                BlockPos blockP=q.poll();
                BlockState s=level.getBlockState(blockP);
                //如果当前我们找到了该目标方块,就跳出bfs循环
                if(s.getBlock()==Blocks.GRASS_BLOCK){
                    flag=true;
                    break;
                }
                for(int i=0;i<6;i++)
                {
                    for(int j=0;j<6;j++)
                    {
                        for(int z=0;z<6;z++)
                        {
                            int xx=blockP.getX()+dx[i];
                            int yy=blockP.getY()+dy[i];
                            int zz=blockP.getZ()+dz[i];
                            if(zz>0 && zz<256 && st[(xx-pos.getX()+8)%16][(yy-pos.getY()+8)%16][(zz-pos.getZ()+8)%16]==false && abs(pos.getX()-xx)<9 && abs(pos.getY()-yy)<9 && abs(pos.getZ()-zz)<9)
                            {
                                q.offer(new BlockPos(xx,yy,zz));
                                st[(xx-pos.getX()+8)%16][(yy-pos.getY()+8)%16][(zz-pos.getZ()+8)%16]=true;
                            }
                        }
                    }
                }
            }
            //System.out.println();
            return flag;
        }
    
        //探测器是否检测到目标方块
        @OnlyIn(Dist.CLIENT)
        public void animateTick(BlockState p_180655_1_, World p_180655_2_, BlockPos p_180655_3_, Random p_180655_4_) {
            //如果方块没有激活就不断对区域内的方块进行检测
            if(!p_180655_1_.getValue(POWERED))
            {
                boolean flag = this.checkBlock(p_180655_2_, p_180655_3_, p_180655_1_);
                //如果找到了,就将探测器充能发光
                if(flag)
                    p_180655_2_.setBlock(p_180655_3_, p_180655_1_.setValue(POWERED, Boolean.valueOf(true)), 2);
            }
            else{
                boolean flag = this.checkBlock(p_180655_2_, p_180655_3_, p_180655_1_);
                if(!flag)
                    p_180655_2_.setBlock(p_180655_3_, p_180655_1_.setValue(POWERED, Boolean.valueOf(false)), 2);
            }
        }
    
        public void neighborChanged(BlockState p_220069_1_, World p_220069_2_, BlockPos p_220069_3_, Block p_220069_4_, BlockPos p_220069_5_, boolean p_220069_6_) {
    
        }
    
        @Override
        protected int getDelay(BlockState p_196346_1_) {
            return 1;
        }
    
        protected void createBlockStateDefinition(StateContainer.Builder p_206840_1_) {
            p_206840_1_.add(FACING,POWERED);
        }
    
        public int getSignal(BlockState p_180656_1_, IBlockReader p_180656_2_, BlockPos p_180656_3_, Direction p_180656_4_) {
            return p_180656_1_.getValue(POWERED) ? 15 : 0;
        }
    
        public boolean isSignalSource(BlockState p_149744_1_) {
            return true;
        }
        private void updateNeighbours(BlockState p_196378_1_, World p_196378_2_, BlockPos p_196378_3_) {
            p_196378_2_.updateNeighborsAt(p_196378_3_, this);
            p_196378_2_.updateNeighborsAt(p_196378_3_.relative(getConnectedDirection(p_196378_1_).getOpposite()), this);
        }
    
        public void onRemove(BlockState p_196243_1_, World p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_, boolean p_196243_5_) {
            if (!p_196243_5_ && !p_196243_1_.is(p_196243_4_.getBlock())) {
                if (p_196243_1_.getValue(POWERED)) {
                    this.updateNeighbours(p_196243_1_, p_196243_2_, p_196243_3_);
                }
    
                super.onRemove(p_196243_1_, p_196243_2_, p_196243_3_, p_196243_4_, p_196243_5_);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154

    2.在ModBlocks类中注册我们的探测器方块:

    ModBlocks.java

        public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, Utils.MOD_ID);
    
        //添加这个
        public static RegistryObject BFS_BLOCK = BLOCKS.register("bfs_block",()->
                new BlockBFS(AbstractBlock.Properties.copy(Blocks.IRON_BLOCK).harvestTool(ToolType.PICKAXE).harvestLevel(1).requiresCorrectToolForDrops()));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.代码部分结束,来到资源包制作环节

    resources\assets\你的modid\blockstates下新建bfs_block.json文件,枚举方块状态:

    bfs_block.json

    {
      "variants": {
        "facing=east,powered=false": {
          "model": "fanfu:block/bfs_block",
          "y": 90
        },
        "facing=east,powered=true": {
          "model": "fanfu:block/bfs_block_on",
          "y": 90
        },
        "facing=north,powered=false": {
          "model": "fanfu:block/bfs_block"
        },
        "facing=north,powered=true": {
          "model": "fanfu:block/bfs_block_on"
        },
        "facing=south,powered=false": {
          "model": "fanfu:block/bfs_block",
          "y": 180
        },
        "facing=south,powered=true": {
          "model": "fanfu:block/bfs_block_on",
          "y": 180
        },
        "facing=west,powered=false": {
          "model": "fanfu:block/bfs_block",
          "y": 270
        },
        "facing=west,powered=true": {
          "model": "fanfu:block/bfs_block_on",
          "y": 270
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    models\block中新建bfs_block.jsonbfs_block_on.json,分别表示充能和未充能的方块模型:
    未充能时模型

    bfs_block.json

    {
      "parent": "block/orientable",
      "textures": {
        "top": "fanfu:blocks/virus_generator_side",
        "front": "fanfu:blocks/virus_generator",
        "side": "fanfu:blocks/virus_generator_side"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    充能时模型

    bfs_block_on.json

    {
      "parent": "block/orientable",
      "textures": {
        "top": "fanfu:blocks/virus_generator_side",
        "front": "fanfu:blocks/virus_generator_on",
        "side": "fanfu:blocks/virus_generator_side"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    models\item中新建玩家手持探测器的模型文件:

    bfs_block.json

    {
      "parent": "fanfu:block/bfs_block"
    }
    
    • 1
    • 2
    • 3
    textures\blocks中添加探测器的材质:

    cr2.jpg

    在语言包lang\en_us.json中添加方块英文名称:
    "block.fanfu.bfs_block":"Detector",
    
    • 1

    zh_cn.json中添加中文名称:

    "block.fanfu.bfs_block":"探测器",
    
    • 1
    进入数据包,在resources\data\fanfu\loot_tables\blocks路径下新建bfs_block.json,编写方块破坏后的掉落物:

    bfs_block.json

    {
    	"type": "minecraft:block",
    	"pools": [
    		{
    			"rolls": 1,
    			"bonus_rolls": 0,
    			"entries": [
    				{
    					"type": "minecraft:item",
    					"name": "fanfu:bfs_block"
    				}
    			],
    			"conditions": [
    				{
    					"condition": "minecraft:match_tool"
    				}
    			]
    		}
    	]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.保存所有代码 -> 运行游戏测试

    我们在距离草方块8格和9格高的地方放置探测器

    tan.jpg

    可以看到,8格高的探测器成功探测到了草方块并且显示出充能状态!
  • 相关阅读:
    运筹学-单纯形法-代码实现(包含做题的每一步骤)
    【SpringBoot项目】SpringBoot+MyBatis+MySQL电脑商城
    一文读懂 MySQL 索引
    LeetCode 202
    【已解决】‘python‘ 不是内部或外部命令,也不是可运行的程序或批处理文件
    JavaScript:js基础1
    我注册了某音帐号之后。。。(内含推荐算法)
    13-ES5和ES6基础
    Python:Unittest框架快速入门:用例、断言、夹具、套件、HTML报告、ddt数据驱动
    B50 - 基于51单片机的儿童成长管理系统
  • 原文地址:https://blog.csdn.net/Jay_fearless/article/details/126411887