Minecraft模组开发:创建类似末地传送门框架的纹理切换方块
实现右键切换纹理的Minecraft方块(类似末地传送门框架)
嘿,我之前开发模组时刚好做过几乎一样的功能,完全不用碰3D模型,纯2D纹理切换就能搞定,给你一步步拆解怎么实现:
核心思路
给你的方块加一个状态属性(比如标记是否"激活"),右键交互时切换这个状态,然后让游戏根据不同状态加载对应的纹理——这和末地传送门框架的逻辑本质是一样的,只是它用的是是否插入末影之眼的状态。
第一步:给方块添加状态属性
首先要定义一个用来区分纹理状态的属性,比如用布尔值表示"激活/未激活"。以Forge为例,在你的方块类里:
import net.minecraft.world.level.block.state.properties.BooleanProperty; // 定义全局状态属性 public static final BooleanProperty ACTIVATED = BooleanProperty.create("activated"); public YourCustomBlock() { // 方块基础属性(硬度、声音这些) super(Properties.of().sound(SoundType.STONE).strength(2.0F)); // 设置默认状态为未激活 this.registerDefaultState(this.stateDefinition.any().setValue(ACTIVATED, false)); } // 注册状态属性 @Override protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { builder.add(ACTIVATED); }
第二步:处理右键切换逻辑
在方块的use方法里,实现右键切换状态的逻辑。如果需要限制只有特定物品才能触发(比如类似末影之眼),还可以加物品判断:
@Override public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { // 只在服务端处理状态变更,避免客户端不同步 if (!level.isClientSide) { boolean currentState = state.getValue(ACTIVATED); // 切换激活状态 level.setBlock(pos, state.setValue(ACTIVATED, !currentState), Block.UPDATE_ALL); // 如果需要限制特定物品右键,比如只有手持末影之眼才切换: // ItemStack heldItem = player.getItemInHand(hand); // if (heldItem.is(Items.ENDER_EYE)) { // level.setBlock(pos, state.setValue(ACTIVATED, !currentState), Block.UPDATE_ALL); // // 可选:消耗物品 // if (!player.isCreative()) heldItem.shrink(1); // } return InteractionResult.SUCCESS; } return InteractionResult.CONSUME; }
第三步:绑定不同状态的纹理
这一步是让游戏知道不同状态对应哪个纹理,有两种方式:
方式1:用Data Generators(推荐,自动生成配置文件)
在你的BlockStateProvider类里,给每个状态绑定对应的模型/纹理:
@Override protected void registerStatesAndModels() { // 未激活状态,对应纹理 your_block_inactive.png this.getVariantBuilder(YourCustomBlock.BLOCK) .partialState().with(YourCustomBlock.ACTIVATED, false) .modelForState().modelFile(models().cubeAll("your_block_inactive")).addModel(); // 激活状态,对应纹理 your_block_active.png this.getVariantBuilder(YourCustomBlock.BLOCK) .partialState().with(YourCustomBlock.ACTIVATED, true) .modelForState().modelFile(models().cubeAll("your_block_active")).addModel(); }
方式2:手动写blockstates配置文件
如果不用Data Generators,直接在resources/assets/yourmod/blockstates/目录下创建your_custom_block.json:
{ "variants": { "activated=false": { "model": "yourmod:block/your_block_inactive" }, "activated=true": { "model": "yourmod:block/your_block_active" } } }
然后在resources/assets/yourmod/models/block/目录下创建两个模型文件:
your_block_inactive.json(指向未激活纹理)
{ "parent": "block/cube_all", "textures": { "all": "yourmod:block/your_block_inactive" } }
your_block_active.json(指向激活纹理)
{ "parent": "block/cube_all", "textures": { "all": "yourmod:block/your_block_active" } }
最后把你的两张纹理图片放在resources/assets/yourmod/textures/block/目录下,命名和上面的配置一致就行。
额外注意事项
Block.UPDATE_ALL已经包含了客户端同步,所以状态变更后客户端会自动刷新纹理,不用额外写同步代码。- 如果需要更复杂的状态(比如多个切换阶段),可以把
BooleanProperty换成EnumProperty,定义多个枚举值对应不同纹理。
内容的提问来源于stack exchange,提问作者MushMello




