本章中使用基础形状和材质创建一个室内场景。还会展示如何在场景中导航。接上一章,我们会利用所学技术修改对象(如移动、缩放、旋转)。读者还会学习如何配置光照和材质。
学完本章后,读者可以:
- 可熟悉操作和转换对象。
- 掌握如何将纹理叠加到对象上。
- 配置光照强度。
- 掌握如何设置环境光。
在刚开始创建游戏时,虽然有很多的资产供使用,但我们在能够(或雇佣其他人)完成更精致游戏之前可能只想快速创建一个原型来测试功能。虽然具备3D建模背景,但很多初学者无法利用该技能使用基础形状快速创建一个关卡。本章会协助读者完成这类任务:使用相对简单的形状创建一个可用的关卡。第一关我们会创建具备如下功能的场景:
- 带光照、纹理墙面、地面和屋顶的室内迷宫。
- 光照区。
- 会暴露或困住玩家的黑暗区。
创建这一环境,我们要经历如下流程:
- 使用模板(图片)创建迷宫。
- 使用地图在场景中添加对象。
- 删除地图。
- 在场景中向所有对象添加纹理和颜色。
不借助预定义地图,很难知道在哪里添加组成场景的各个对象。当然读者可以根据预定义的坐标来放置对象。但是地图在视觉上可以帮助我们更容易地将对象放到对的位置上。本例中,我们会在地面上铺上地图,然后根据迷宫的轮廓在地面上添加对象,最后在添加完所有对象后使用地砖替换掉这个轮廓。
本关的布局如下图所示。基本上是由一系统过道组成。
可以看到,这一个使用Photoshop创作的非常简单的黑白图。由表示空白空间的白色背景和表示墙壁的不同大小黑色矩形组成。也可以使用其它软件如Paint或Gimp在轻松创作想要的地图。使用地图是为了简化在Godot中大概确定迷宫中各部分的位置。这样我们可以按照初始布局绘制,而不用去猜在哪里添加对象。本章中所用的这张图是使用Photoshop创建的。大小为100x100像素,如果你使用Photoshop的话,还可以启动每5像素的网格线,获取每隔一个像素的分区。
开始设计环境之前是,我们会创建一个新场景,以及一个存储所有资产的文件夹。我们还会导入本关所需的纹理。
首先创建一个场景:
- 假设上一章创建的项目牌打开状态(否则请使用Project | Quit to Project List打开),新建场景(Scene | NewScene)。完成以上操作后就会有一个空白场景以及不包含节点的场景树。
- 在场景栏中点击3D Scene按钮。
- 这会新建一个根节点名为Spatial的3D场景。
- 可以保存该场景,将其命名为maze或是选择其它名称进行保存。
我们可以为该场景创建一个文件夹。虽然不是必须,但这有助于管理项目以及将所有该场景使用的相关资产保存在一个独立文件夹内。
读者应该已经下载到本书的配套资源。本章需要导入的图片有bricks.jpg、ceiling.jpg和gameMap.png:
- 点击在Godot目录中所创建的maze文件夹。
- 定位至所下载并解压好的配套资源文件夹。
- 将bricks.jpg、ceiling.jpg和gameMap.png拖拽到maze文件夹中。
- 此时这些文件应该就会出现在maze文件夹下了,如下图所示。
上一章中我们使用内置的箱体来创建台阶;但其中不包含导航,因此也就不需要测试玩家和环境之间的碰撞。但在本章中我们要使用控制器来在环境中导航,并与墙壁和地面产生碰撞,所以需要创建包含碰撞检测的对象。也就是说,我们需要确保玩家走到墙面时会停止。
为此,我们构建场景的方式略有不同,不能直接使用原始图形进行创建,而是要将其结合CollisionShape及StaticBody节点进行使用。
CollisionShape节点用于定义决定节点是否处于碰撞中的形状(包含胶囊、箱体或球体等类型的形状)。StaticBody节点受制于物理规律,包含碰撞,但是为静态。这正是本例中墙体的情况,因为墙体不是运动的对象,设计StaticBody是为了让这类对象的碰撞检测不像遵守物理定律的移动节点那样消耗较多资源。
现在就可以开始创建迷宫了。首先,我们会创建一个用作地面的立方体,这个立方体会关联一个StaticBody节点及一个CollisionShape节点。
- 新建一个StaticBody节点:在场景中已有的Spatial节点上右击,选择AddChildNode,然后在搜索框中输入StaticBody并选择StaticBody,点击Create。
- 这会新建一个名为StaticBody的节点。
- 选中该节点,问你那一个CollisionShape类型的子节点(在StaticBody上右击,在上下文菜单中点击AddChildNode)。
- 现在在场景中应该可以看到如下图的三个节点。
读者可能注意到了CollisionShape节点上有一个警告标记:这是由于我们需要为该节点指定一个形状类型。也就是说要为该节点指定碰撞器的形状。
- 单击CollisionShape节点。
- 在检查器中,点击CollisionShape | Shape版块empty字段右侧的向下箭头,如下图所示。
- 在弹出的菜单中选择New BoxShape。
- 最后,选中CollisionShape节点新增一个CSGBox子节点(右击CollisionShape节点,然后选择Add ChildNode,在搜索框中输入CSGBox,选择CSGBox并点击Create按钮)。
这时我们就有了可进行碰撞的箱体:
- StaticBody节点保障其可进行碰撞。
- CollisionShape节点决定了应用碰撞检测的边界。
- CSGBox节点赋予这个箱体具体的外观(如颜色和形状)。
注意由于CollisionShape和CSGBox节点是StaticBody节点的子节点,应用于父节点(StaticBody)的转换都会作用于子节点。
至此创建迷宫地面所需的组件已就绪,下面们来改变其形状和外观。
- 将对象StaticBody重命名为ground。
- 使用检查器,确保对象的位置为 (0, 0, 0) 。
- 使用检查器,将该对象的缩放属性改为 (100, 1, 100) ,让其延x轴和z轴进行放大。
下面对地面进行纹理,CSGBox子节点负责地面的外观,先聚焦于这个节点上:
- 为更方便看到变化,我们可通过y轴查看场景。实现方式前面已经讲过,使用视窗右上角的坐标轴工具,点击其中的y轴。
- 点击场景树中的CSGBox对象。
- 使用检查器导航至CSGBox版块。
- 点击Material属性右侧的箭头,在弹出菜单中选择New SpatialMaterial。
- 点击该版块中的白球。
- 会列出Material组件的多个属性。
- 选择Albedo选项。
- 此时可指定地面的纹理。
- 可使用文件系统栏导航至刚刚导入包含纹理的文件夹(即res:// | maze)。定位到文件夹中用于轮廓的纹理(即gameMap.png文件),将该纹理从文件系统拖至empty框。这样就会将纹理应用于ground对象,如下图所示。
然后会看到地面(CSGBox)上已应用了纹理 ,如下图所示。
在检查器栏中,点击Uv1属性,会看到缩放属性为 (1, 1, 1) ,也就是说纹理延各坐标轴仅平铺一次,本关中纹理正是需要这样进行展现。
已定义好定义地面并对其应用了模板,下面该使用立方体创建墙面和其它房间了。因为ground节点已包含了StaticBody和CollisionShap节点,我们通过复制并应用转换将其作为墙面的模板。
下面创建第一个房间:
- 复制一份ground,将其命名为room1。
- 这会新建一个包含子节点CollisionShape类型的room1节点,子节点有具有一个CSGBox类型子节点。
- 将该节点(room1)放到ground上面一点,比如位于 (4, 1, 1) 。
- 可以使用坐标轴工具将视图变为顶部视图(如果默认不是顶部视图的话),这样可以通过y轴查看场景。
现在我们对这个立方体执行一系列转换,让其与地面纹理中的一个矩形相吻合:
- 选中节点room1。
- 为更易于与实际地面相区分,我们会修改该房间的纹理。
- 选中room1节点的子节点CSGBox。
- 使用检查器,在CSGBox版块中,点击Material属性右侧的向下箭头,在弹出的菜单中选择New SpatialMaterial,这会将room1变成一个空白的盒子。
现在可以通过缩放(R)和移动(W)工具调整尺寸及移动立方体,让其与轮廓(定义地面的地图)中的矩形相匹配。
经过连续操作,就创建了与地面纹理相吻合的第一个房间,如下图所示。
至此我们就延x轴和z轴调整好了第一个房间。但仍需调整其调试。我们希望屋顶为2.5米高。下面在检查器窗口中进行调整:
- 选中room1对象。
- 在检查器窗口中,修改y的缩放属性为2.5并将位置属性设置为3.5。
- 这是因为地面的高度为1,而墙高为2.5米。
完成㼚操作后就可以对房间应用纹理了:
- 使用检查器,在Material版块中点击白球。
- 在弹出的窗口中,选择Albedo并将res:// | maze文件夹中的bricks纹理拖拽至检查器的empty框中。
注:鉴于在mac 上默认显示过于朦胧,为方便接下来对纹理的查看,我额外添加了一个光照。
- 现在需要通过将检查器中的Uv1属性修改为 (x=3, y=2, z=1) 来调整纹理的平铺方式。读者可根据自己的需要纹理使用其它缩放属性值。为了让铺设的砖块显得更为真实,可能需要放大对象,然后调整平铺属性,这样可以观察确定适合的x、y或z轴缩放值。
将房间的外观调整至满意之后,可以复制该房间,调整大小创建其它房间:
- 在场景树中复制room1,将复制的对象命名为room2。
- 将复制的对象移到邻近的矩形框上,调整大小匹配好相应的区域(此时仅需调整x轴和z轴的位置及缩放属性)。可以使用移动工具移动对象,缩放工具重置大小。
重复这一过程完成整个迷宫。
创建好各个房间之后,迷宫应该像下图中这样。
读者可能会注意到,不同的房间纹理略有不同。这是因为平铺是根据第一个房间长宽来定的。现在可以不必修改。但如果你希望改进部分房间的外观的话,应该为它们定义具体的材料以让平铺相应的变化(因为平铺关联了材料,对平铺设置的修改会改变或创建新的空间材料)。
此时我们的迷宫就快要完成了,还缺少三个元素:四面外墙、屋顶和一些光照。
那我们来创建外墙。先复制任意一个房间,然后通过调整其大小创建外墙。比如可以像下图中那样:
可以看到,这个过程非常简单,可以重复操作创建其它三面墙:
- 复制northWall节点,重命名为southWall。
- 将其转换属性修改为(0, 3.5, 100)。
- 复制northWall节点,重命名为westWall。
- 将其转换属性修改为 (-100, 3.5, 0) ,并将其旋转属性设置为 (0, 90, 0) 。
- 最后,复制westWall节点,重命名为eastWall。
- 将其转换属性设置为 (100, 3.5, 0) 。
至此我们创建了迷宫的地面、一些房间以及外墙,如果能在迷宫中行走就很棒了。为此,我们要在场景中添加人物控制器,这样可以在迷宫中行走查看玩家看到的外观。执行如下步骤:
- 打开AssetLib窗口(位于顶栏工作空间)。
- 在搜索框中输入first person controller。
- 双击结果中的Simple First Person Controller。
- 在弹出的窗口中,点击Download。
- 接着点击Install。
- 几秒之内Godot会弹出消息告诉你已成功下载资源包。
- 查看文件系统栏,应该会看到一个player文件夹(即res://assests/player),该文件夹内有一个名为Player.tscn的资产。
- 可将该文件(Player.tscn)拖到场景栏的Spatial节点上,这样会为Spatial节点创建一个子节点Player。
- 使用移动工具,可以移动该节点不让其走进墙里,同时保障其y轴坐标为1。
在使用该控制器之前,我们仅需重新为移动赋值快捷键:
- 在顶部菜单中选择Project | Project Settings | Input Map。
- 在该窗口顶部输入player_forwards,点击Add按钮(窗口的右侧)。
- 添加完成后,点击其右侧的+按钮,在弹出菜单中选择Key,如下图所示。
- 在键盘上按下向上方向键然后点击OK。
重复以上步骤添加如下设置:
- player_backwards使用向下方向键。
- player_left使用左方向键。
- player_right使用右方向键。
- player_jump使用空格键。
此时可在场景中按下CTRL +R进行测试,应该可以通过方向键和鼠标进行导航并且不会走到墙里面。
至此,本关供浏览的界面差不多了,但地面还没有完成。读者应该知道,现在使用的模块是由用于表示何处摆放房间立方体的黑白区间组成的。既然已经完成了迷宫的布局,就不再需要这一纹理了。我们可以使用更真实的材质来表示地面,比如在上一章中用作地面的瓷砖材质。下面就进行修改:
- 在场景树中,找到ground对象。
- 点击ground的子节点CSGBox,这时可以在检查器窗口中看到其属性。
- 在检查器中,找到CSGBox版块,点击Material标签右侧带纹理的球体。
- 点击该图标,会出现一个窗口,其中包含一个属性列表,点击Albedo标签左侧的箭头展开Albedo属性。
- 我们通过从文件系统里将tile.jpg纹理拖拽至Texture属性处来替换当前纹理。
纹理拖放完成后,就会看地面的颜色发生了改变,使用的是tile.jpg的纹理;便我们还是需要修改纹理在地面上重复的方式(平铺方式),这可通过UV1属性来实现。
进行以上调整后,是时候在场景中玩耍闲逛一下了:
- 点击Play按钮(或CTRL +R)。
- 使用方向键和鼠标在场景中行走。
- 应该会类似下图中这样。
看到环境和预期一致之后就可以先退出调试了。现在本关已可用,但是如前所述,最好有一个屋顶。可通过复制地面、上移再修改相关联的纹理轻松实现。我们会使用和之前相关的技术(使用移动工具及在检查器中更改纹理):
- 在场景树窗口中,搜索ground对象。
- 定位到该对象后执行复制(CTRL + D或右击选择Duplicate)。
- 将其重命名为ceiling。
- 使用检查器将位置修改为 (0, 7, 0) 。
完成以上操作后,只需再对天花板设置纹理即可:
- 首先要从下载的文件夹中导入ceiling纹理 ,并将其保存至Godot的一个目录中(如maze | textures)。
- 在场景树中定位至ceiling,点击其子节点CSGBox。
- 在检查器中,定位至CSGBox版块,点击Material属性右侧的向下箭头。
- 在新出现的上下文菜单中选择New SpatialMaterial选项。
- 点击Material标签右侧的白球。
- 这会打开一新窗口,供我们修改该节点关联的纹理。
- 在新窗口中,(通过点击相应的箭头)展开Albedo版块,然后从文件系统中将名为ceiling的纹理拖到Texture标签右侧的empty框中。
- 应该会看到ceiling节点的纹理发生了改变。
最后,我们通过展开UV1属性修改这个新材料的平铺属性,将其缩放值设置为 (20, 20, 20) 。
再看一下场景视图,会发现天花板的纹理发生了改变,如下图所示。
可以运行场景查看纹理,可能会发现天花板很暗,在下一部分中通过添加光照环境相关节点可以解决。
在迷宫中行进时,可能会发现有些区域会比较亮,改处光照从迷宫外部照入,这表示天花板没有完全盖住迷宫。我们可以稍后调整屋顶的位置解决这一问题。
读者可能会奇怪在环境封闭的情况下是如何看到墙面的。我们稍后会深入探讨,但总的来说场景具有默认属性,其中一些与场景的环境光有关。默认,即使没有为场景添加光照,也会有一些环境光。当然我们可以调整,在下一节中讲解。
调整好迷宫后, 我们会开始为其添加光照,创建一些黑暗区和明亮区。在游戏中,这会用于隐藏区域或照亮玩家经过的房间或过道。
在添加光照前,我们还设置场景环境的一些属性,对于默认光照,可以使用一个叫做WorldEnvironment的节点实现。
- 在场景树中选中Spatial。
- 为该节点添加WorldEnvironment类型的子节点,方法前面已经讲过(即选择节点,右击再选择Add ChildNode)。
- 这会创建名为WorldEnvironment的节点。
- 选中该节点,使用检查器窗口定位到WorldEnvironment版块。
- 点击Environment标签右侧的箭头,在弹出的菜单中选择New Environment,如下图所示。
现在看到的场景应该是全黑色,这是正常的。
添加好WorldEnvironment节点,如们可以修改属性来添加环境光。
可以运行场景(CTRL + R)查看场景的变化。
场景这样没有问题,但将场景设置为倒置,隐藏一些区域,再为一些地方添加光照会更棒。
首先,我们将环境光设为全黑:
-
选中WorldEnvironment节点。
-
展开Ambient Light版块。
\
接下来我们会添加一些光照。Godot中有很多类型的光照,现在我们只会使用点光来模拟灯泡或火把的光,从具体某一点照亮四周。
因为天花板是场景中y轴上最高的对象,我们可以临时禁用它来更方便地在迷宫内移动对象。操作如下:
完成以上操作后,我们可以开始为场景添加光照了:
- 选择Spatial节点。
- 右击该节点,新增类型为Omni Light的子节点。
- 将其y轴坐标修改为5.5。
- 可以将源移向环境查看其对场景产生的影响。
- 在检查器中,定位至Omni版块,将范围修改为20。
- 类似地,定位至Light版块,将能量修改为7.5。
- 应该会在场景中看到一个标签为OmniLight的新对象,同时在视窗中看到新的光照。
- 可再次开启天花板。
- 运行场景现在应该如下图所示。
在查看场景后,我们可以重复上一步来添加更多光源,通过复制、移动所创建的OmniLight或为Spatial添加更多的OmniLight子节点如下:
- 临时禁用ceiling:这样移动光源更方便。
- 多次复制之前创建的OmniLight节点并移到你希望放的地方,确保大部分走道都能照亮。
- 将复制好的对象移至迷宫中不同的位置。
- 修改每个光源的设置,调整Range、Energy或Color来创建所需的特殊效果(比如每个的颜色和强度都不同)。
- 重新打开ceiling,运行场景查看效果。
本章中,我们熟悉了室内环境的创建,并学习了如何通过内置对象如箱体、点光源或相机创建迷宫。我们还使用了此前学习的转换对象的知识来创建一个完整的作品。
更多内容:Godot从入门到精通系列文章