Navigation

    CreatiCode Scratch Forum

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • CreatiCode

    三维 - Bloxorz 滚动方块游戏(难度:6)

    小教程
    1
    1
    384
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • info-creaticode
      CreatiCode last edited by admin

      介绍

      在本教程中,你将重现一款名为“滚动方块”(Bloxorz)的经典益智游戏。在这个游戏中,玩家在平台上旋转一个盒子从一个目标洞中穿过:

      fall.gif

       
      你将练习使用父子关系使物体围绕任意点旋转,使用表格进行关卡设计,还会用到一点的三维物理引擎。

       
       

      第 1 步 - 星空场景

      首先,请在创益编程平台创建一个新项目,移除带小狗的角色,并将空白的角色重命名为“主程序”。

      在主程序角色中,添加以下积木。他们将创建一个空的三维场景,显示三维坐标系,并添加一个漂亮的太空星图作为背景。

      b92bc4d9-99bc-4702-a3a0-8f48eae1127e-image.png

       
      这是你应该得到的:

      sky.gif

       
       

      第 2 步 - 添加新的摄像头

      默认情况下,当你添加天空盒子时,它也会把摄像头拉到很远的地方。然而,在这个游戏中,我们将使用非常小的物体。因此,请使用以下积木添加一个新的摄像头,它将替换现有的摄像头:

      81ec2efe-9022-4f22-88f9-4a238c047cdc-image.png

       

      这个摄像头与世界中心的距离为 10。此外,我们还禁用了键盘和鼠标指针的输入。这样,玩家就无法改变摄像机的视角,所有的按键操作都将用于旋转盒子。

      你应该得到如下的视图。你能发现这里有什么问题吗?

      908441da-e634-45be-ab8e-4faf2ad07fe7-image.png

       
       

      第 3 步 - 配置摄像头

      你可能已经注意到了一个问题:我们现在看不到背景中美丽的星空了。那是因为背景距离摄像头太远了。要解决这个问题,我们需要更改摄像头的设置,使其能够查看距离为 1000000 以内的所有物体:

      4284a659-6fc6-4ff7-a1d9-0696b5d5990d-image.png

       
      现在我们就可以同时看到离我们很近的三维坐标系和遥远的星空:

      ae40d7ab-30be-40fa-814f-ab0145d938c0-image.png

       
       

      第 4 步 - 添加玩家盒子

      现在让我们添加玩家控制的盒子。它应该是 1 x 1 x 2,并命名为“p”。你可以选择任何你喜欢的纹理。我们需要将它移动到 x = 1、y = 1 和 z = 1 的位置。由于它的高度为 2,z 位置为 1,因此它的底部将恰好位于 z = 0 的位置。

      b250e673-e7cc-4d1d-adad-f0cefd80cf05-image.png

       

      它应该是这样的:

      4b751523-3895-4183-b713-d3d8a0b26743-image.png

       
       

      第 5 步 - 添加“平台”角色

      现在请添加一个名为“平台”的空角色,它将用于管理组成平台的盒子。

      为了把它初始化,请从 主程序角色 发送一条“添加平台”的消息,

      4a02b21a-51ab-4741-bbd2-d605ea07fe9e-image.png

       
      然后在 平台角色 中接收这个消息:

      2fce2d3a-8b0d-4e6a-8ce4-e6d8a6484c72-image.png

       
       

      第 6 步 - 为平台添加第一个盒子

      游戏的平台将由许多盒子组成。为了提高效率,我们将使用一种常见的创建方式:我们将添加一个盒子,然后把它复制为很多副本。

      这是添加第一个盒子的积木。为了方便设计盒子的位置,我们将使每个盒子在 x 和 y 维度上为 1 个单位。它应该相当薄,厚度为 0.1。给它起一个像“g”这样的名字,然后随意为它挑选任何纹理。

      4d2e2b20-8746-4090-ba5e-a5d5d03d660e-image.png
       
      当我们拉近摄像头时,这个盒子看起来像这样:

      7e2bf8ca-4d00-4fc2-9764-bcc5fc9d77bf-image.png

       
       

      第 7 步 - 将第一个盒子移开

      现在我们把这个盒子移动到一个很大的Z位置上,这样我们的摄像头就看不到它了。此后我们就可以根据我们的关卡设计图随意的放置所有复制出来的盒子。

      1404ec9f-043a-4a1b-825b-0e78d22985d5-image.png

       
       

      第 8 步 - 使用表格代表盒子的位置

      为了组建平台,我们需要添加很多的盒子,并将它们放置在不同的位置。理想情况下,我们希望能够直观地查看它们的位置,以便轻松的创建或更改这个地图。因此,我们将使用 表格 来代表这个地图。

      例如,下面是一个表格,其中有 3 个列,名称分别为“1”、“2”和“3”,分别代表 x 位置1/2/3。它也有 3 行,分别代表 y 位置 1/2/3。这样,表格中的每一项都可以用来表示该位置是否应该有一个盒子。例如,对于第 1 列和第 1 行,如果我们将字母“b”放在那里表示“盒子”(你可以选择使用任何字母),那就表示我们想在 x = 1 和 y = 1 的位置放置一个盒子。表中带有“b”的 7 个项目就代表我们要在这7个位置添加盒子,组成一个字母“H”的阵型。

      352f52c9-166a-4ce2-9345-bf36df9d56d4-image.png

       
      现在请创建一个名为“地图”的新表格。

       
       

      第 9 步 - 向表中添加 20 个空列

      虽然我们可以手动向表中添加新列,但使用积木要快得多。首先,创建一个新变量“x”,然后添加以下计数循环来插入 20 列。它将在第 1 列插入名为“1”的列,然后在第 2 列插入名为“2”的列,依此类推。

      6a54134f-d391-46da-8362-381da4b15e54-image.png

       

      这个表将有 20 列,但还没有任何内容:

      sky.gif

       
      请注意,如果出现任何问题,你可以使用以下积木删除表格中的所有行和所有列以重新开始,但 请注意不要意外运行这个积木。

      257af3ff-b324-446a-98d7-81b4e33ffe18-image.png

       
       

      第 10 步 - 向表中添加 20 个空行

      我们还可以使用积木快速向表中添加一些空行。创建一个新变量“y”,然后使用这样的一个计数循环添加 20 行:

      7cc2fe62-d32e-4e8e-97a9-38c205f3240a-image.png

       
      现在表中有 20 个空行:

      sky.gif

       
       

      步骤 11 - 向表中添加一些数据

      现在让我们在表格中添加一些字母来表示 3 行盒子,每行 5 个。你可以单击表格里面的任何单元格对其进行编辑,也可以按键盘上的 TAB 键从一个单元格跳到右侧的下一个单元格。

      ttt.gif

       
       

      第 12 步 - 定义“添加盒子”积木

      现在让我们定义一个新的积木,用于在指定的 x/y 位置添加一个新盒子。它接受 x 和 y 的 2 个输入。在它的定义中,我们将首先选择之前添加的第一个名为“g”的盒子,然后复制它。注意,我们需要在原始的盒子和复制的盒子之间共享数据。当我们复制很多盒子时,这将节省大量时间和计算机内存。

      我们将使用 x 和 y 位置来命名每个复制的盒子。例如,如果 x 为 5,y 为 6,则盒子的名称将为“5_6”。稍后我们可以使用这个盒子的名字来对它进行操作(比如移动或删除它)。

      最后,我们将把这个盒子放在指定的 x/y 位置。它的 z 位置应该是 -0.05,因为它的高度是 0.1,而且我们希望盒子的顶面在 z 位置 0。

      1537a2f0-c6d2-459b-b323-9449741c925d-image.png

       
       

      第 13 步 - 根据地图表格添加盒子

      现在我们终于可以添加盒子了。我们将读取表中每个项目的内容,并使用一个新变量“类型”来存储此信息。每当我们发现一个项目的类型是“b”时,我们就在那个对应的位置添加一个盒子。请注意,这里我们巧妙的利用了这个事实:“x”的值既是列名又是 x 位置,“y”的值既是行号又是 y 位置。

      c52fd965-1c09-4d42-9cf5-830668ec7da2-image.png

       
      运行程序后将有 15 个盒子被添加出来:

      8369317f-5455-4a72-b585-d0de3ffa93eb-image.png

       
       

      第 14 步 - 重置摄像头的位置

      为了更清楚地查看平台,让我们 回到主程序角色,将摄像头的观察距离更改为 9,并将其目标位置更改为 x = 3 和 y = 2:

      027f422c-b23e-48ee-bc56-5722c5216ef4-image.png

       
      现在我们得到这个视图:

      58f9275b-076e-4753-8436-33fc9d95a326-image.png

       
       

      第 15 步 - 在盒子之间添加间隙

      目前,我们很难分辨平台盒子之间的边界。我们可以稍微缩小每个盒子,这样它们之间就会有个一个小间隙。 在平台精灵中,我们可以将第一个盒子的大小从 1 x 1 更改为 0.96 x 0.96:

      cc610557-aa66-46f2-ba60-270dd2b7d87e-image.png

       
      结果,我们可以看到盒子之间有明显的缝隙:

      0c9dc477-2dc0-4017-9e63-8f186fa96d7e-image.png

       
       

      第 16 步 - 添加旋转锚点

      现在我们让玩家的盒子在平台上旋转。这里的挑战是我们不能简单地让盒子围绕它自己的中心点旋转。相反,我们需要它围绕某个边旋转。解决方案是使用一个父节点作为旋转的“锚点”。当父节点旋转时,玩家的盒子将会绕着这个父节点的位置旋转。

      要添加锚点对象,我们可以添加一个名为“a”的转换器:

      9dfafc12-3e41-447c-936d-d67a75f965b2-image.png

       
       

      第 17 步 - 处理按键的循环

      我们将允许玩家通过按键来旋转他的盒子。让我们定义一个名为“处理按键”的新积木,并使用一个永久循环来不断的检测按键事件。我们从处理“d”键开始:

      6bac749f-2e29-48c9-920a-e85ac1068700-image.png

       
      请注意,我们总是首先选择玩家的盒子“p”作为角色物体,因为角色物体可能已经改变。

       
       

      第 18 步 - 定义“旋转盒子”积木

      当玩家按下“d”键时,我们需要让玩家的盒子围绕其右下方的边缘旋转。为此,我们首先需要将锚点物体移动到这个点,然后让它围绕 Y 轴旋转,如下所示:

      ttt.gif

       

      为了实现这一步,我们将首先定义一个名为“旋转盒子”的新积木。它将接受 4 个输入,允许我们指定锚点需要移动到的 x 和 y 位置,以及围绕 X 轴和 Y 轴各旋转多少度:

      cc0e57db-5eb3-48e6-a691-3e7cd0da6037-image.png

       
       

      第 19 步 - 向右旋转

      要将玩家的盒子向右旋转,让我们决定如何设置 4 个输入参数。

      假设玩家的盒子的中心在 x坐标 =1 和 y坐标 = 1,那么锚点应该在中心点右边0.5,即 盒子的x坐标+0.5。锚点的 y 坐标与中心点的 y 坐标相同。锚点的z坐标应该是盒子底部的z位置,也就是0。

      我们将围绕 Y 轴旋转盒子 -90 度。因为不需要绕 X 轴旋转它,我们可以将这个输入设置为 0 度。

      因此,这就是我们应该如何使用新的积木:

      639e368d-2bc6-45a7-8e66-ea392cc61853-image.png

       
      请注意,由于此时玩家盒子“p”被选为角色物体,因此运动积木“x 坐标”和“y 坐标”就代表“p”的中心点的位置。

       
       

      第 20 步 - 移动锚点物体

      现在是时候实现“旋转盒子”的定义了。首先,我们需要选择锚点物体,并将其移动到指定的 x 和 y 位置。接下来,我们将选择玩家的盒子,然后将锚点物体设置为它的父节点。

      93110237-551c-4a08-b6ea-c1efca660471-image.png

       
      请注意,2 个“选择”积木非常重要。它们告诉三维引擎下面你想对哪个物体进行操作。

       
       

      第 21 步 - 旋转锚点物体

      接下来,我们将旋转锚点物体。我们可以检查“绕 x 转角”的值,看看我们是绕 X 轴还是绕 Y 轴旋转。如果它不为 0,则表示我们需要绕 X 轴旋转。请注意,我们在旋转它之前先要选择它作为角色物体。

      c2cd974b-04bd-45b1-a667-0f27f65f2131-image.png

       
       

      步骤 22 - 解除父节点关系

      旋转锚点物体后,玩家的盒子将旋转到新的位置。我们需要取消它与锚点物体的父子关系,否则它的位置信息将不准确。

      59c21234-c530-4aa3-bb5b-df9a02603e7e-image.png

       
      现在我们可以试一试了。当我们按下“d”时,玩家的盒子会正确地向右旋转。

      ttt.gif

       
       

      步骤 23 - 再次向右旋转

      当我们尝试再次按“d”将盒子向右旋转时,我们得到了不正确的结果。

      ttt.gif

       
      这是因为当盒子躺平时,它的右边缘距离它的中心点不是 0.5 个单位,而是 1 个单位。

      那么我们怎么知道盒子是否躺着呢?我们可以检查它的 z 坐标。如果盒子是直立的,它的高度是2,所以它中心的 Z 坐标应该是 1;当它躺下时,它的高度是1,所以它中心的 Z 坐标是 0.5。

      d5c7d66c-2f4d-473b-96e3-4afedc343a66-image.png

       
      现在我们可以连续向右旋转盒子了:

      ttt.gif

       
       

      第 24 步 - 按“w”向前旋转

      接下来,让我们在按下“w”键时让盒子向前旋转。我们可以复制处理“d”键的块,并在几个地方修改它:

      • 当我们向前旋转盒子时,锚点将在盒子前面的底边,而不是右底边。这意味着我们需要将锚点物体移动到与盒子相同的 x 位置,但 y 位置更大。
      • 我们需要围绕 X 轴而不是 Y 轴旋转。

      8ebbe1fd-24e5-4a95-8a71-7ac47246f2e5-image.png

       
      现在我们也可以向前旋转了:

      ttt.gif

       
       

      步骤 25 - 重置锚点物体的方向

      当我们将盒子向右旋转 2 次,然后向前旋转时,我们遇到了一个问题:

      ttt.gif

       
      这是一个棘手的问题。我们可以看到锚点物体的位置是正确的,但它是向后旋转盒子,而不是向前旋转。其实,这里的原因是我们将锚点物体向右旋转2次后,它变成了倒立着的。所以当我们告诉它向前旋转时,它会向我们看起来的后面旋转。

      要解决这个问题,我们只需要在每次使用锚点物体之前重置它的方向:

      9742c4ae-eb24-407f-bc20-9c570fa47638-image.png

       
      我们可以确认此问题已得到解决:

      ttt.gif

       
       

      第 26 步 - 侧身旋转

      还有一个我们必须解决的情况。当我们向右旋转一次,然后向前旋转时,盒子最终悬在空中:

      ttt.gif

       
      这一次,问题不在于旋转方向,而在于锚点的位置。当箱子躺下时,它可以向前或向侧面躺下。到目前为止,我们只处理了前一种情况。

      当盒子横着躺下时,要向前滚动它,锚点的 y 位置应该距离盒子的中心点只有 0.5 个单位,而不是 1 个单位。

      但是,我们怎么知道盒子是向前躺着还是侧着躺着呢?我们可以检查它的 y 坐标。如果它是横着的,那么它的 y 坐标就是一个整数,比如1、2等;如果它向前躺着,它的 y 坐标在 2 个格子的中间,就应该是 1.5、2.5 等等。所以,我们可以检查 y 坐标是否四舍五入到它自身: 把 y 四舍五入后是否仍然等于 y。

      13017c82-cb8d-4a42-a6d4-fe9e749a9e10-image.png
       
      现在问题已经解决:

      ttt.gif

       
       

      第 27 步 - 向前旋转然后向侧面旋转

      我们需要应用相同的逻辑来处理“d”键:如果盒子向前翻转,然后向右滚动,我们需要调整锚点的 x 位置。

      192be178-dd8a-46c4-af7a-fc2ea3b64980-image.png

       
      我们可以这样测试它:

      ttt.gif

       
       

      第 28 步 - 处理“a”键

      现在让我们复制“d”键的逻辑来处理“a”键。锚点的 x 位置将位于盒子中心的左侧,而且旋的角度是 90 度而不是 -90 度:

      4e896b5d-6551-4189-9059-e49c4f31e9e1-image.png

       
       

      第 29 步 - 处理“s”键

      最后,让我们复制“w”键的逻辑来处理“s”键。锚点的 y 坐标比盒子的中心小,旋转角度为 -90:

      7a466349-d77c-4f9a-93af-ac9276632a31-image.png

       
      请你彻底的测试所有 4 个方向:

      ttt.gif

       
       

      第 30 步 - 指定目标位置

      现在让我们指定目标在地图上的位置。我们可以用一个不同的字母“g”来表示目标的位置,而且整张地图应该只有一个“g”。例如,我们可以把它放在第 4 列,第 2 行:

      113ade8c-f1e2-48fe-af45-2d7743d09116-image.png

       
       

      第 31 步 - 在目标位置添加一个新盒子

      在平台角色中,当我们为平台创建盒子时,我们将遍历表格里面的每一项。如果我们发现项目的类型是“g”,我们应该创建一个新的盒子来表示目标位置。除了不同的颜色(如紫色)外,它与其他盒子的大小相同。

      0721efd6-2e07-46ce-a047-92dbafdae2c0-image.png

       
      ca2e1fc0-0ed1-4722-a02f-22a23807093d-image.png

       
       

      第 32 步 - 让目标盒子发光

      为了让我们的目标盒子更漂亮,我们可以让它发光。我们需要更新它的发光颜色,然后为它创建一个辉光层:

      83f41e0f-351b-4d8f-8c2f-8049b0ea57fe-image.png

       
      这是发光效果:

      1782fb47-d967-439c-9f18-0d5d9d6b652a-image.png

       
       

      步骤 33 - 检查玩家盒子的位置

      现在我们的游戏已经可以开始玩了。每次玩家旋转盒子后,我们都需要检查盒子的位置,看看它是否应该掉落,或者关卡已经完成。

      让我们首先创建一个名为“检查位置”的新积木,让它在“旋转盒子”积木的末尾运行。

      2d1ea4f3-cad4-458e-ab7e-a107f15378f1-image.png

       
       

      步骤 34 - 当玩家的盒子站起来时的位置类型

      玩家的盒子由 2 个立方体组成。我们需要知道每个立方体下面是否有一个平台盒子,或者目标盒子就在这些立方体下面。我们可以从“地图”表中读取这些信息。

      当玩家的盒子是直立的时候(即它的 z 坐标是 1 时),这是相当简单的。玩家盒子的两个立方体与盒子本身共享相同的 x 和 y 坐标。让我们创建 2 个新变量“类型 1”和“类型 2”来表示每个立方体下面平台块的类型,我们可以这样设置它们的值:

      d62006dd-ec02-4bf3-9453-b79713d48166-image.png

       
      例如,当玩家框的 x 坐标为1,y 坐标为2时,那么我们将“类型 1”设置为表格第2行第1列的值,即“b”。 “类型 2”将是相同的,因为玩家盒子的第二个立方体也位于相同的 x 和 y 位置。

      c15c17f5-2c89-4fb1-b553-ad701219f54b-image.png

       
       

      第 35 步 - 当玩家的盒子从左到右躺平时

      当玩家盒子的 z 位置不为 1 时,表示它处于躺平状态。如果它从左到右躺着,它的 y 坐标将是一个整数。在这种情况下,玩家盒子的 2 个立方体将具有与盒子本身相同的 y 坐标,并且它们的 x 位置将距盒子的中心 0.5 个单位。

      bacd3625-ab09-404e-9b51-1c4f2f6f7d7a-image.png
       
      例如,如果盒子位于 y 为 2 和 x 为 2 到 3 的位置,我们会发现2个立方体的位置类型都是 “b”:

      86d648b3-722d-44e1-b838-5b13de097690-image.png

       
       

      第 36 步 - 当玩家的盒子从前到后躺平时

      在最后一种情况下,玩家的盒子是前后平放的。组成它的 2 个立方体将具有与它相同的 x 坐标,它们的 y 坐标将与盒子的 y 坐标相差 正/负 0.5 个单位。

      4b2ebf60-ad69-47f4-8bfc-5b3c83b8d408-image.png

       
      例如,在这张图片中,2 个立方体的 x 为 4,y 为 2 和 3。因此它们下方的砖块类型分别为“g”和“b”:

      aa07f5f1-4dec-4105-b73e-2b47a8e37f88-image.png

       
       

      第 37 步 - 启用物理引擎

      到目前为止,我们根本没有使用物理引擎。只要玩家的盒子落在平台上正确的位置,我们只需要使用旋转动画。然而,当玩家的箱子需要从平台上掉下来时,我们要使用物理引擎,这样掉落的过程看起来真实。

      要使用物理引擎,让我们做一些改变:

      • 在主程序角色中,为整个场景启用物理引擎:

      • 在平台角色中,将物理身体附加到我们创建的第一个盒子上。这样,它的所有副本都会自动拥有一个一样的物理身体。请注意,“质量”必须为 0,以确保这些砖块不会自己掉落。

       
       

      第 38 步 - 让玩家的盒子掉落

      当播放器盒直立时,它必须站在平台某个砖上面。如果玩家的盒子是躺着的,那么组成它的两个立方体都必须在平台的砖块上。

      因此,当我们检查“类型 1”和“类型 2”时,如果其中至少有一个是空的,那么我们就知道盒子应该掉下来。为了让盒子掉落,我们只需要给它附加一个物理身体。

      a8d2bc8d-2262-4eba-8eb3-b381b529e5fd-image.png

       
      现在我们得到了一个很好的下落效果:

      fall.gif

       
       

      第 39 步 - 检查关卡是否完成

      我们如何知道玩家是否已经完成挑战?盒子应该站在目标块的上方,这意味着**“类型 1”和“类型 2”都应该是“g”。

      当这个条件满足时,我们也应该给盒子附加上物理身体让它下坠。

      5dce00e3-2fc2-4419-922e-9bd3be03f5fb-image.png

       
      现在盒子将从目标区域穿过去:

      fall.gif

       
       

      第 40 步 - 关卡完成

      当盒子落入目标时,我们还应该显示“关卡完成”的消息。我们可以使用标签控件来做到这一点:

      12ea2232-dfb8-4f78-9baa-bf806c5e4deb-image.png

       
      它会像这样弹出:

      fall.gif

       
       

      改编创意

      虽然这款游戏目前非常简单,但你可以通过多种方式对其进行扩展。以下是一些值得尝试的想法:

      • 更改关卡地图:你可以通过更改“地图”表格非常轻松地更改平台的地图。如果需要,你可以给表格添加更多的行和列。

      • 多关卡游戏:当用户完成挑战后,你可以将平台重置为更难的地图。

      • 按钮:你可以在一些积木上添加按钮,当玩家的盒子落在这些按钮上时,它会触发其他一些积木的被添加或移除,例如平台两部分之间的桥梁。要实现这个想法,你需要动态更改“地图”表格的内容。

      • 阻挡砖块:你可以为平台的某些砖块使用不同的颜色,当玩家的盒子落在这些砖块中的任何一个上时,它会被弹回之前的位置。

      • 排行榜:你可以跟踪玩家完成关卡的移动次数,并在排行榜中显示。

      • 屏幕按钮:你可以在屏幕下方添加一些用于旋转盒子的按钮,这样在触摸屏上也可以玩这个游戏。

      下面是一个演示游戏:

      https://play.creaticode.com/projects/77083f9840c1f919563357ff

      1 Reply Last reply Reply Quote 0
      • Pinned by  info-creaticode info-creaticode 
      • First post
        Last post