You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

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

火山引擎 最新活动