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<BlockPos> 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<Block, BlockState> 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_);
        }
    }
}

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

ModBlocks.java

    public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, Utils.MOD_ID);

    //添加这个
    public static RegistryObject<Block> BFS_BLOCK = BLOCKS.register("bfs_block",()->
            new BlockBFS(AbstractBlock.Properties.copy(Blocks.IRON_BLOCK).harvestTool(ToolType.PICKAXE).harvestLevel(1).requiresCorrectToolForDrops()));

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
    }
  }
}
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"
  }
}
充能时模型

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"
  }
}
models\item中新建玩家手持探测器的模型文件:

bfs_block.json

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

cr2.jpg

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

zh_cn.json中添加中文名称:

"block.fanfu.bfs_block":"探测器",
进入数据包,在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"
				}
			]
		}
	]
}

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

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

tan.jpg

可以看到,8格高的探测器成功探测到了草方块并且显示出充能状态!
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay_fearless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值