官方教程地址如下(仅有英文版):https://learn.unity.com/project/ruby-s-2d-rpg?language=en
近期学习了untiy提供的Ruby的冒险,决定总结一下中文教程(主要为简化流程,希望完全没有接触过unity的朋友还是看官方教程,比较详细)和记录学习心得
虽然目的为简化,但仍然会保证关键的内容,以及画一下自己认为的重点,总体不会跟原版教程差太多,可以一起看,我会加一点点教程没有提到或者容易误解的地方
整个教程制作建议时间14-24小时,请准备至少为期2天的时间来学习本教程~
建议: unity版本 2018.3 以上
由Bigbao实现完整项目代码以及资源(我使用的unity版本为2019.2.0b):https://github.com/Bigbao123/Ruby
如何使用和自定义编辑器
如何在整个开发过程中管理项目资源和场景
如何创建角色和控制器
使用tilemaps的世界布局和设计
如何使静态精灵适应动画精灵
搜索 2D Beginner:Tutorial Resources
在2D Beginner:Tutorial Resources页面上,单击Download 等待下载完成
点击粉红色的按钮Import
点击导入资源->创建新场景->保存
选择你从github上下载的.unity文件 导入
首先尝试让你的ruby动起来
public class RubyController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector2 position = transform.position;//声明position变量,在其中存储了Ruby的当前位置
position.x = position.x + 0.1f;
transform.position = position;
}
}
Ctrl+s保存脚本并切换到unity中查看你的更改, 发现ruby动了起来,但这看起来有点傻夫夫的
(教程里基础写的有点多(虽然基础讲的很细但是对于已经对unity有一些了解的同学不免有一丢丢啰嗦,但是建议有时间可以细看看教程,查漏补缺基础知识),所以我在这边简化一下,如果是任何基础都没有的朋友,建议还是看教程)
现在我们来让ruby上下左右移动
public class RubyController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector2 position = transform.position;
position.x = position.x + 3.0f * horizontal * Time.deltaTime;//deltaTime 包含在Time中,是一个变量,Unity填充帧渲染所需的时间
position.y = position.y + 3.0f * vertical * Time.deltaTime;
transform.position = position;
}
}
这里要注意一下:需要表示Ruby移动的数量不是以每帧为单位,而是以每秒为单位。所以需要通过将其与Unity渲染帧所花费的时间(Time.deltaTime)相乘来更改移动速度。如果游戏以每秒10帧的速度运行,则每帧需要0.1秒。如果它以每秒60帧的速度运行,则每帧将花费0.017秒。如果将移动乘以该值,则移动将以秒为单位表示。
Tilemaps是个啥东西呢? 我们来看看这个图:
Tilemap网格,(unity中的解释)可以在每个网格单元格中设置不同的Sprite。通过使用可以在视觉上连接在一起的Sprite,您可以创建一个更容易在编辑器内直接更改的更大图像
听起来好像也还是没有很懂,那我们先做做了解看
让我们从创建Tilemap开始:
1. 在“层次结构”窗口中,右键单击空白区域。
2. 从上下文菜单中选择2D Object> Tilemap
这将在您的Hierarchy窗口中创建两个GameObject:
网格:正如其名称所暗示的,这是一个场景中的网格,可用于将GameObjects均匀地放置在其单元格中。
Tilemap:Tilemap由Tiles组成 - 为了本教程的目的,将它们视为特殊的Sprites。Tilemap是网格的子GameObject。
在“项目”窗口中,选择“ FirstTile” 。
在Inspector中,可以看到Tile Asset的属性。这些包括Sprite的插槽,Tile将绘制:
找到Tile.png文件,就像使用Ruby.png一样,将此Tile保存在Sprites文件夹中
在Inspector中,单击Sprite 属性右侧的圆圈选择按钮。这将打开一个对话框窗口,其中显示项目的所有Sprite。
为新Palette命名,如GamePalette,然后单击Create 。
将新Palette保存在Tile文件夹中。
将Tile(FirstTile )从Project窗口拖到新Palette的中心
Tile现在显示在调色板的网格中。单击平铺以选择它。
从“平铺调色板”顶部的工具栏中,选择“ 画笔工具” 。
在Hierarchy窗口中,选择Grid GameObject。在Inspector中,找到“单元格大小”属性。你会看到x 和y 都设置为1 :
这意味着每个单元格的宽度为1个单位,高度为1个单位。
2. 在“项目”窗口中,选择FirstTile Sprite。Inspector将显示其导入设置。将看到“ 每单位像素数” 属性设置为100 。
在Inspector的底部,查看Sprite的大小。你会发现它的宽度和高度只有64像素
将每单位像素值更改为64. 这告诉Unity在场景中的1个单位内拟合该Sprite的64个像素。由于你的Sprite是64像素,它将完美地填充1个单位。
更改每单位像素数(PPU)后,单击“检查器”底部的“ apply” 。你所有的精灵现在会完全填满网格!
按住Ctrl键配合鼠标在Palette面板里可以选更多的区域!!!
你现在知道了:
什么是瓷砖
它与Sprites和Tilemaps的关系
如何使用Tile Palette绘制Tilemap
为了更容易创建Tiles和技术优化,用于Tiles的Sprite通常作为单个图像文件称为Tileset 。
例如,下面的图像在3x3网格上包含九个Tiles,然后Unity可以在导入设置中拆分为9个不同的Sprite:
在“Project”窗口中,搜索名称以“Floor”开头的所有文件都是Tilesets。
在Inspector中,使用下拉菜单将Sprite Mode 从Single 更改为Multiple 。
将ppu值更改为64 (因为这些Tiles宽64像素,就像前面的示例一样)。
单击“ apply” 按钮以应用更改。
调整Tileset的Sprite设置:
将图像分割成九个精灵:
1. 在“检查器”中,单击“ Sprite Editor” 按钮。这将打开一个窗口,您可以在其中调整图像的哪个部分作为Sprite导入。
2. 在窗口顶部的菜单栏中,单击“ Slice” 。将出现一个窗口,您可以在其中指定切片图像的方式。
3. 使用下拉菜单将“ Type ” 字段设置为“ Grid by Cell Count ” 。
4. 将Column&Row值(C 和R )设置为3 。
单击“ Slice” 。网格将出现在您的图像上; 该网格的每个单元格都是一个单独的Sprite。
在窗口菜单栏的右上角,单击“ apply” 。
窗口并单击小箭头以查看从该图像创建的精灵,将会有九个!
要将精灵分配给Tiles:
1. 将整个图像从“Project ”窗口拖放到“Palette ”窗口中。
2. 当您松开鼠标按钮时,将出现一个对话框,要求您选择保存Tiles的文件夹。选择Tile 文件夹。
Tiles现在已经创建,是Palette的一部分!您将能够选择它们并对它们进行绘制
对于所有Tileset Assets,重复前三个步骤中的过程,文件名以“Floor”开头(均为3x3 Sprites的Tilesets)。
键盘和鼠标快捷键
还有一些有用的快捷方式可以帮助绘制Tilemap:
Alt +左键拖动 - 平移
轮按钮拖动 - 平移
旋转滚轮按钮 - 放大或缩小
好了!接下来是创作时间 你可以画你自己设计的游戏啦!
完成绘制Tilemap后:
1. 将更改保存到场景中。 2. 单击“ 播放” 进入“播放”模式,欣赏您的角色在您绘制的世界中移动。
因为Tilemap和角色具有相同的深度(它们的位置的z坐标),为了避免Tilemap擦除Ruby,您可以更改z位置。但对于纯粹的2D游戏,最好避免触及深度。为了使Ruby出现,你需要告诉Unity它需要绘制的东西。Unity需要首先绘制Tilemap,以便Ruby出现在背景之上。
要更改Unity绘制Tilemap和角色的顺序:
1. 在Hierarchy中,选择Tilemap GameObject 。 2. 在Inspector中,找到Tilemap Renderer 组件。
3. 设置Order in Layer为-10 。
4.Sorting Layer: default
在Assets > Art > Sprites > Environment里选择你想要的各种装饰精灵
创作完毕后:
让我们看看Ruby的Sprite渲染器:
1. 在Hierarchy中,选择Ruby GameObject。
2. 在Inspector中,找到其Sprite Renderer 组件。
3. 找到Sprite Sort Point 字段。这当前设置为Center ,这意味着它使用Sprite的中心点来决定它是应该在另一个GameObject的前面还是后面。
4. 将Sprite Sort Point更改为Pivot 。
一个pivot是一种特殊的点,你可以手动定义,它充当“锚”的雪碧。如果旋转Sprite,它将围绕该点旋转。它也是用于放置Sprite的点。这意味着如果GameObject位于(0,0)并且Pivot设置为角色的头部,则头部将被绘制在(0,0)处。如果枢轴在脚上,则P脚将被绘制在(0,0)处。 您需要更改Ruby和MetalCube Sprites的Pivots,以便将它们放置在您想要的位置。 要更改单个Sprite Pivot:
1。 在Project窗口中,转到Assets> Art> Sprites> Environment 。选择MetalCube Sprite。
2. 在Inspector中,找到Pivot领域。使用下拉菜单将其设置为Bottom 。
单击检查器底部的“apply” 按钮。
更改Pivot的另一种方法是使用Sprite Editor: 1。 在Project窗口中,转到Assets> Art> Sprites 。选择Ruby Sprite。
2. 在“检查器”中,单击“ Sprite编辑器” 按钮。这将打开您在上一个教程中使用的Sprite Editor。 3. 单击图像,显示Sprite边框。在中心,你应该看到一个小蓝圈。这是Pivot的当前位置。
精灵编辑器允许您在Sprite中将该蓝色圆圈拖放到任何位置。
或者,在灰色的Sprite窗口中,您可以:
坐落在Pivot 下降到中心。
将Pivot 设置为Custom 并手动设置Custom Pivot 。
4. 将自定义轴旋转设为0.5英寸x和0英寸。由于Pivot Unit Mode 设置为Normalized,因此0最小(因此左侧为x,底部为y),1为最大值(右侧为x,顶部为y),0.5为中间值。
5. 单击“ apply” 以保存更改。
1. 在“项目”窗口中,转到顶级文件夹(资产)。 2. 创建一个新文件夹并将其命名为“ Prefabs ”。 3. 将MetalBox GameObject从层次结构拖动到新的Prefab 文件夹。
如果要模拟运动和碰撞,则需要使用所有数学方程来计算对象上的接触和力。但是这写了很多复杂的代码。因为物理定律是相同的,所以可以抽象出这些代码并在所有游戏中分享:这就是物理系统的作用。Unity有一个内置的物理系统,可以为您计算物体移动和碰撞。
为了避免对游戏中的每个对象进行昂贵的数学运算,Unity仅为附加了Rigidbody 2D 组件的GameObjects 进行那些计算。
让我们首先在Ruby中添加一个Rigidbody 2D 组件:
1. 在Hierarchy中,选择Ruby GameObject。 2. 将Ruby GameObject从Hierarchy拖动到Project窗口中的Prefab文件夹中。 3. 双击Ruby Prefab以打开预制模式。 4. 在“检查器”中,单击“ 添加组件” 按钮。 5. 搜索“ Rigidbody 2D ”并选择组件。 注意:确保选择2D组件 - 还有一个名为Rigidbody的组件用于3D游戏。
使用“ 保存” 按钮保存预制件,然后返回场景
如果这时候点击运行 你会发现你的Ruby掉下来了,因为Rigidbody将重力应用于GameObject(默认情况下在y轴上设置),所以GameObject下降了
1. 在Hierarchy中,选择Ruby GameObject。
2. 在Inspector中,找到Rigidbody 2D组件。 3. 找到“ 重力比例” 属性并将其设置为0 。
点击Ruby提交改变Apply All到预制体上
什么是Collider?
现在你的GameObject已经被物理系统所知(因为Rigidbody),你需要告诉物理系统GameObject的哪个部分是“可靠的”。这是通过碰撞者(Colliders)完成的。
碰撞器是简单的形状,如方形或圆形,物理系统将其作为GameObject的近似形状,进行碰撞计算。
让我们从Ruby GameObject开始:
1. 在Prefab模式下打开Ruby Prefab。
2. 在“检查器”中,单击“ Add Component.” 。
3. 搜索“ Box Collider 2D ”,并添加此组件。 注意:再次,请记住使用此组件的2D版本!
4. 现在,您将在“场景”视图中看到Ruby周围的绿色轮廓:
这就是对撞机的形状 - 它现在是物理系统的Ruby形状。
保存预制件。
6. 现在对MetalBox Prefab做同样的事情:
双击预制件将其打开。
添加Box Collider 2D组件。
保存预制件。
退出预制模式。
注意:您尚未在框中添加Rigidbody组件 - 这是正确的。这是因为它不需要通过物理移动,它只需要一个Collider,所以有一个Rigidbody的GameObjects将与它进行交互。
现在按Play,尝试将Ruby移动到盒子周围。
角色抖动并旋转!有点鬼畜......
旋转问题:你需要告诉物理系统不要旋转GameObject。它可能是“真正的”物理学会做的,但在这个2D游戏中它不起作用。 Rigidbody 2D组件有一个设置:
1。检查Ruby是否在Prefab模式下打开。
2. 在Inspector中,找到Rigidbody 2D组件。
3. 单击“ Constraints” 旁边的小箭头以展开该部分。
4. 启用Freeze Rotation 复选框,以确保Rigidbody不向Ruby添加任何旋转
提示:如果您在场景中而不是在Prefab上对Ruby实例进行了更改,请使用下拉Override菜单将更改应用于预制件。
现在准备修复Ruby的抖动问题:
为什么Ruby抖动?(思考.... 字太多我直接机翻过来了...)
抖动的发生是因为物理系统使用仅包含碰撞器的场景的简化副本。 这个物理场景使物理系统的计算更简单,但物理系统需要:
只要带有刚体的GameObject在场景中移动,就可以在物理场景中移动GameObject的副本。
施加力并计算碰撞。
将场景中的GameObject移动到物理场景中计算的新位置。
在这种情况下,这会导致以下事件:
您在帧更新期间移动角色。
物理系统将其副本移动到新位置。
物理系统发现角色Collider现在位于另一个Collider(这里是盒子)里面并将其移回,因此它不再在盒子里面。
物理系统将Ruby GameObject与新位置同步。
你不断地将Ruby移到盒子里,而物理系统正在将她移回去。你告诉你的代码要做什么和物理系统做什么之间的斗争导致抖动。
要修复Ruby的抖动,你需要移动Rigidbody本身而不是GameObject Transform,并让物理系统将GameObject位置同步到Rigidbody位置。这样,物理系统可以在进入盒子之前停止移动,而不必在已经进入盒子后移动Ruby 。
为此,您需要修改Ruby Controller代码:
public class RubyController : MonoBehaviour
{
Rigidbody2D rigidbody2d;
// Start is called before the first frame update
void Start()
{
rigidbody2d = GetComponent();
}
// Update is called once per frame
void Update()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector2 position = rigidbody2d.position;
position.x = position.x + 3.0f* horizontal * Time.deltaTime;
position.y = position.y + 3.0f * vertical * Time.deltaTime;
rigidbody2d.MovePosition(position);
}
}
让我们看看每行代码:
Rigidbody2D刚体2d; 这将创建一个名为rigidbody2d的新变量来存储刚体并从脚本内的任何位置访问它。
rigidbody2d = GetComponent
在Update函数中,您替换了Vector2 position = transform.position; 使用Vector2 position = rigidbody2d.position ; 这意味着您不再使用Transform位置,而是使用Rigidbody。
以同样的方式,而不是用transform.position = position 设置新位置; 你现在正在使用rigidbody2d.MovePosition(position); 这会将Rigidbody移动到你想要的位置,但是如果它在那个运动中与另一个Collider发生碰撞,它将在中途停止。
现在,当您单击“ 播放”时,您将看到您的角色已停止抖动!
但Ruby仍然太早停止,而且看起来并不好看。那是因为碰撞器的大小不适合图像。
如果你查看场景视图,你会看到盒子的碰撞器和Ruby(它们周围的绿色矩形)远远超出你认为GameObject的“实体”部分。 例如,盒子的阴影位于Collider内部,因此它被物理系统认为是固体
要调整对撞机的大小:
1。 双击MetalBox预制件(或单击层次结构中MetalBox右侧的箭头)以进入预制模式。
2. 在Inspector中,找到Box Collider组件。
3. 单击“ 编辑碰撞” 按钮
单击“ 编辑碰撞”时,“碰撞”将在“场景”视图中更改,以在侧面显示四个小方块。您可以单击并拖动它们以调整Collider的大小。如果您错过了单击并且小点消失,只需返回检查器并重新单击“ 编辑碰撞器” 按钮。 调整Collider的大小,使其看起来像这样
你为什么不把它做成盒子的大小?嗯,那是因为你的角色需要能够“躲在”盒子后面才能让它看起来更好(否则盒子在地面看起来会很平坦)。
5. 保存更改。
6. 为Ruby GameObject完成相同的过程,调整其Collider的大小,使其看起来像这样:
Collider只能覆盖Ruby的腿,因为角色需要能够在碰撞前稍微移动到GameObject之上 - 这有助于使游戏更加可信。
7. 保存更改。
8. 单击“ 播放” ,然后尝试在框中移动Ruby。现在它应该看起来很好并且表现得像你期望的那样。(完成后请记得再次按“播放”,退出“播放模式”。)
现在你的角色与我们所有有碰撞器的游戏对象发生碰撞。但她仍然可以在水上行走 - 你需要让她与水瓦片碰撞,所以她不能走在他们身上。但你怎么能这样做?
您可以将一个Collider添加到空GameObject并调整其大小以覆盖水。但这很容易出错,如果您想要将水重新绘制为更大,更小或不同的形状,则必须手动更换对撞机。请记住,Tilemaps可以让您轻松快速地改变世界。
值得庆幸的是,Tilemaps还可以拥有碰撞器。每个Tile都可以存储它是否应该碰撞,Tilemap Collider将为所有设置为碰撞的Tiles创建一个Collider。
要设置Tilemap Collider: 1。在Hierarchy中,选择Tilemap GameObject。
2. 在“检查器 Inspector”中,单击“ 添加组件 Add Component ” 按钮。
3. 搜索“ Tilemap Collider 2D ”并选择此组件。您将看到这会在场景视图中为所有切片添加绿色对撞方格:
这是因为现在所有的Tiles都设置为碰撞。
4. 在“项目”窗口中,转到“Tile”文件夹。选择所有非水的瓷砖。您可以单击一个,然后按住Shift 并单击要包括的最后一个平铺以全部选中它们
5. 在Inspector中,找到Collider Type 属性并将其从Sprite (现在)更改为None。
现在,您选择的Tiles不再被视为碰撞者。如果在层次结构中选择Tilemap,您将在“场景”视图中看到只有水砖具有绿色方块。
6. 保存更改。 7. 单击“ 播放” 进入“播放模式”并尝试让Ruby在水上行走 - 她现在应该与边界碰撞。
设置Tilemap Collider还有最后一小步。目前,每个磁贴都是一个单独的碰撞器,您可以在“场景”视图中看到。 这很好,但它会产生两个问题:
它在物理系统的计算上更重; 如果你有一个大世界,它可以开始放慢你的游戏速度。
它可以在瓷砖之间的边界上产生小问题。由于它们是两个并排的碰撞器,并且它们之间存在微小的间隙,因此计算中的微小不精确可能导致罕见的碰撞仍然发生。
为解决这些问题,Unity提供了一个名为Composite Collider 2D 的组件。这会将所有碰撞器放在物体上(或物体的子物体上)并从中制造一个大碰撞器。 让我们添加和配置这个组件:
1。 在Hierarchy中,选择Tilemap GameObject。 2. 在“检查器”中,单击“ 添加组件” 按钮。 3. 搜索“ Composite Collider 2D ”并选择此组件。
您将看到这会自动添加Rigidbody 2D,因为复合Collider需要Rigidbody 2D才能正常工作。
4. 在Tilemap Collider 2D组件中,启用Used By Composite 复选框。 5. 在Rigidbody 2D组件中,将Rigidbody Body Type 属性设置为Static 。 将此设置为静态将阻止您的世界移动。它还有助于物理系统优化计算,因为它现在知道Rigidbody无法移动。
现在,水砖周围的碰撞器是一个大的矩形
如果您绘制新的水砖,Unity会自动更新Tilemap的Composite Collider以包含这些新的Colliders。
在本教程中,您有:
探讨了Unity中物理系统的基础知识
添加了一个Rigidbody组件,使物理系统处理对象
添加了碰撞器以使对象碰撞在一起
在下一个教程中,您将扩展您对物理系统的使用,以检测与游戏对象(例如,可收集的健康包)的角色碰撞。