添加一个骰子 (Add A Dice) - Terasology/TutorialAssetSystem GitHub Wiki
静态的方块的确挺酷的, 但是如何添加一个可以交互的方块呢?
让我们按照如下步骤, 添加一个骰子方块:
- 六个面都是不同的 (有没有被吓到, 这是一个骰子 ;) )
- 方块应该是可交互的(默认按'e'键)
- 如果激活了, 骰子应该随机的旋转, 并在一个不同的状态下停下
- 投掷的时候, 骰子应该播放一点点声音.
- 当然, 我们希望骰子有着不同的颜色
我们会从一个简单的骰子开始, 先制作一个不能交互的:
-
添加
dice1.png
至dice6.png
材质到assets/blockTiles
文件夹中去:
-
创造一个方块定义为
blocks/dice.block
:{ "displayName": "Dice 6", "categories" : ["dice"], "hardness": 1, "tiles" : { "top" : "dice1", "bottom" : "dice6", "front" : "dice2", "back" : "dice5", "left" : "dice3", "right" : "dice4" } }
简单的开启游戏看看是否正确的加载了筛子, 然后我们继续:
-
现在到了棘手的部分:
如果我们把这个骰子的所有旋转结果,都定义为一个独立的方块,那会是非常糟糕的 ;) 而且正是这部分我们需要引入方块家族
这里还剩下一个问题, 在当前教程里, 只有horizontal
和attachedToSurface
家族是预定义的.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"
}
}
-
如前所述, 我们需要为骰子擦黄金一个预制体. 定义
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如果它或者里面其他链接的教程是需要被修复的,请带着链接更新这个小节 ;)
译者自己并没有搞清楚这句话是什么意思, 大概的意思就是,如果你觉得需要这个教程,我们会写一篇
-
现在所有东西都已到位. 我们将会让骰子知道它自己是可以被旋转的. 最后一步, 是定义一个 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.