添加一个骰子 (Add A Dice) - Terasology/TutorialAssetSystem GitHub Wiki

静态的方块的确挺酷的, 但是如何添加一个可以交互的方块呢?

让我们按照如下步骤, 添加一个骰子方块:

  • 六个面都是不同的 (有没有被吓到, 这是一个骰子 ;) )
  • 方块应该是可交互的(默认按'e'键)
  • 如果激活了, 骰子应该随机的旋转, 并在一个不同的状态下停下
  • 投掷的时候, 骰子应该播放一点点声音.
  • 当然, 我们希望骰子有着不同的颜色

我们会从一个简单的骰子开始, 先制作一个不能交互的:

  1. 添加dice1.pngdice6.png材质到assets/blockTiles文件夹中去:

  2. 创造一个方块定义为 blocks/dice.block:

    {
        "displayName": "Dice 6",
        "categories" : ["dice"],
        "hardness": 1,
        "tiles" : {
            "top" : "dice1",
            "bottom" : "dice6",
            "front" : "dice2",
            "back" : "dice5",
            "left" : "dice3",
            "right" : "dice4"
        }
    }
    

    简单的开启游戏看看是否正确的加载了筛子, 然后我们继续:

  3. 现在到了棘手的部分:

    如果我们把这个骰子的所有旋转结果,都定义为一个独立的方块,那会是非常糟糕的 ;) 而且正是这部分我们需要引入方块家族
    这里还剩下一个问题, 在当前教程里, 只有 horizontalattachedToSurface 家族是预定义的.

    horizontal意为水平的, attachedToSurface意为贴在地上的

    第一个会旋转方块, 但是顶部和底部并不会跟着旋转, 这对于箱子和熔炉来说是极好的, 但是并不是制作一个骰子所需要的.
    第二个允许我们定义3个方块实例通过方块形状(block shape), 分别是针对放置在地板, 墙壁(旋转得和其他墙壁面对面), 天花板的三种情况; 这些对于一些类似火把的方块来说是很不错的, 但是这并不符合我们的骰子

    比如Minecraft中的火把和告示牌, 并不能放置在天花板上, 但是拥有放置在地板和墙上两种状态

    因为这些原因, 这个教程带来了 DiceBlockFamily 能够通过在 .block 文件中编写 "family" : "dice", 来定义, 如果你对方块家族是怎么工作的感兴趣, 你可以继续阅读.
    如果你想要一些关于如何实施你自己的方块家族, 你可以阅读这篇完整文档DiceBlockFamily.

    最后, 我们需要加一个组件在我们的方块里, 这会为我们提供一个标记, 告诉我们这个方块是可以像骰子一样旋转的. 我们添加了一个预制体(会在下一步里定义它)到方块定义中,使用entity小节, 最终版本的 dice.block 应该看起来像这样

{
    "displayName": "Dice 6",
    "categories" : ["dice"],
    "hardness": 1,
    "tiles" : {
        "top" : "dice1",
        "bottom" : "dice6",
        "front" : "dice2",
        "back" : "dice5",
        "left" : "dice3",
        "right" : "dice4"
    },
    "family" : "dice",
    "entity" : {
        "prefab" : "dice"
    }
}
  1. 如前所述, 我们需要为骰子擦黄金一个预制体. 定义 assets/prefabs/dice.prefab 像这样:

    {
        "RotateBlockOnActivate" : {},
        "PlaySoundAction": {
            "sounds": "rollDice"
        }
    }
    

    PlaySoundActionComponent组件,是由引擎定义的,并且会在激活的时候播放声音. 请把rollDice.ogg放置在assets/sounds/rollDice.ogg就可以.
    RotateBlockOnActivateComponent暂时还不存在, 我们可以这样定义他:

    package org.terasology.tutorial.assetsystem.components;
    
    import org.terasology.entitySystem.Component;
    
    /**
     * Marker component for a block which will be rotated if activated
     */
    public class RotateBlockOnActivateComponent implements Component {
    
    }

    注意, ECS的概念超出了这篇教程的范围. 你可以检查议题#2153如果它或者里面其他链接的教程是需要被修复的,请带着链接更新这个小节 ;)

    译者自己并没有搞清楚这句话是什么意思, 大概的意思就是,如果你觉得需要这个教程,我们会写一篇

  2. 现在所有东西都已到位. 我们将会让骰子知道它自己是可以被旋转的. 最后一步, 是定义一个 ComponentSystem 来旋转我们的方块, 请在这个位置定义它 src/main/java/org/terasology/tutorial/assetsystem/systems/RotateBlockOnActivationSystem.java 按照如下内容:

    package org.terasology.tutorial.assetsystem.systems;
    
    import java.util.List;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.terasology.entitySystem.entity.EntityRef;
    import org.terasology.entitySystem.event.ReceiveEvent;
    import org.terasology.entitySystem.systems.BaseComponentSystem;
    import org.terasology.entitySystem.systems.RegisterMode;
    import org.terasology.entitySystem.systems.RegisterSystem;
    import org.terasology.logic.common.ActivateEvent;
    import org.terasology.math.Side;
    import org.terasology.registry.In;
    import org.terasology.tutorial.assetsystem.components.RotateBlockOnActivateComponent;
    import org.terasology.utilities.random.FastRandom;
    import org.terasology.utilities.random.Random;
    import org.terasology.world.WorldProvider;
    import org.terasology.world.block.Block;
    import org.terasology.world.block.BlockComponent;
    
    import com.google.common.collect.Lists;
    
    @RegisterSystem(RegisterMode.AUTHORITY)
    public class RotateBlockOnActivationSystem extends BaseComponentSystem {
    
        @In
        private WorldProvider worldProvider;
    
        private Random random = new FastRandom();
    
        private static final Logger LOG = LoggerFactory.getLogger(RotateBlockOnActivationSystem.class);
    
        @ReceiveEvent(components = {RotateBlockOnActivateComponent.class, BlockComponent.class})
        public void onActivate(ActivateEvent event, EntityRef entity) {
            BlockComponent blockComponent = entity.getComponent(BlockComponent.class);
            Block block = blockComponent.getBlock();
            List<Block> blocks = Lists.newArrayList(block.getBlockFamily().getBlocks());
            //-1 because we omit the block with the same rotation as the current one
            int index = random.nextInt(blocks.size() - 1);
            Side currentDirection = block.getDirection();
            for (int i = 0; i < blocks.size(); i++) {
                Block newBlock = blocks.get(i);
                if (newBlock.getDirection() != currentDirection) {
                    index--;
                }
                if (index == 0) {
                    LOG.info(newBlock.getURI().toString());
                    worldProvider.setBlock(blockComponent.getPosition(), newBlock);
                }
            }
        }
    }
    • 我们只接收方块带有我们标记了的组件的事件(就是我们定义的RotateBlockOnActivateComponent组件)
    • 我们在方块家族中随机选择一个示例
    • 当前方块被那个实例进行替换

是时候在游戏内放置骰子,并激活他像这样 ;)


Translated by MeguminLYQ.

⚠️ **GitHub.com Fallback** ⚠️