持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情。你可以简单浏览一下目录,有需要的阅读,写文章不易,阅读之前请给我点个赞吧~
本文主要内容
- 创建一个预制(prefab)
- 实例化多个立方体(cubes)
- C# 代码的一些精简
- 用立方体展现一个数学函数,通过计算绘制一个你喜欢的图案吧,这里绘制了一个笑脸,祝我的女朋友天天开心,也祝每一个看到这篇博客的人天天都有好心情~
下的主要内容
- 创建一个表面着色器(surface shader)和着色器图(shader graph)
- 让曲线动起来
一、创建一个立方体的笑脸(任意路径)
根据上节提到的内容,创建一个新的 Unity 工程。
1.1 Prefabs
-
向场景中添加一个 cube 把它命名为 Point。
-
移除它的
BoxCollider组件, 因为我们不使用物理(physics)。 -
我们将使用一个自定义组件来创建这个 cube 的许多实例,并正确地放置它们。
-
为了做到这一点,我们将把立方体变成一个游戏对象模板。
-
将 cube 从层次结构窗口拖到项目窗口中。
-
这将创建一个新的资产(asset),称为预制件(prefab)。
-
选中 Point
-
选中工程目录中的 Assets 中的 Point ,你将看到
-
点击 Open Prefab
-
然后你将看到这个预制件(prefab)场景的背景是深蓝色的(天空盒在预制场景中是默认禁用的)
-
如果你改变预制资产,它在任何场景中的所有实例都会以同样的方式改变;
-
改变预制的缩放比例也会改变场景中立方体的比例。但是,每个实例都使用自己的位置和旋转。此外,游戏对象实例可以被修改,这将覆盖预制件的值。
-
使用脚本创建预制实例,意味着我们不再需要当前场景中的预制实例
-
通过 Edit --> Delete 删除场景中的实例 point
1.2 Graph 组件
- 创建 C# 脚本,命名为 Graph
- 给它一个可序列化的字段来保存对实例化点的预制的引用,命名为 pointPrefab。
using UnityEngine; public class Graph : MonoBehaviour { [SerializeField] Transform pointPrefab; } - 上述定义的可序列化的字段,我们需要访问 Transform 组件来定位这些点,因此要将其作为字段的类型。
- 在场景中添加一个空的游戏对象并命名为 Graph
- 将我们的 Graph 组件添加到这个对象中,然后将我们的预制件资产 point 拖到图的 pointPrefab 字段上,并设置如下参数
1.3 实例化 Prefabs
-
实例化一个游戏对象是通过
Object.Instantiate方法完成的 -
Instantiate 方法克隆任何作为参数传递给它的 Unity 对象
-
让我们在 Graph 组件唤醒时执行此操作,代码如下
public class Graph : MonoBehaviour { [SerializeField] Transform pointPrefab; void Awake () { Instantiate(pointPrefab); } } -
扩展关系:
MonoBehaviour是Behaviour的扩展,Behaviour是Component的扩展,Component是Object的扩展,所以上述使用 Instantiate,只需要继承 MonoBehaviour 即可。 -
如果我们现在进入游戏模式,Point 预制(prefab)的一个实例将在世界坐标原点处生成。它的名字和预制(prefab)的是相同的,是用克隆添加的。
-
为了将点放置在其他地方,我们需要调整实例的位置。
-
Instantiate 方法为我们提供了它所创建的任何东西的引用。
-
因为我们给了它一个 Transform 组件的引用,这就是我们得到的返回值。
-
我们用一个变量来记录它。
void Awake () { Transform point = Instantiate(pointPrefab); <img src="}" alt="" width="100%" /> -
在之前的教程中,我们通过将一个四元数分配给枢轴(pivot)的变换(
Transform)的localRotation 属性来旋转时钟臂。 -
改变位置的工作原理与此相同,只是我们必须将3D向量赋值给 localPosition 属性。
-
在 Unity 中用 Vector3 创建了一个 3D 向量,使用 Vector3.right 表示向量(1,0,0)
Transform point = Instantiate(pointPrefab); point.localPosition = Vector3.right; -
游戏模式下,你将看到立方体右移了一个单位。
-
让我们实例化第二个,并将其置于更右侧的地方。
void Awake () { Transform point = Instantiate(pointPrefab); point.localPosition = Vector3.right; point = Instantiate(pointPrefab); point.localPosition = Vector3.right * 3f; } -
游戏模式下,你将看到下图的样子
1.4 代码循环
int i = 0;
while (i < 10) {
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
i = i + 1;
}
沿着X轴排成一排的10个立方体
1.5 简洁的语法
int i = 0;
while (i++ < 10) {
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
}
for (int i = 0; i < 10; i++) {
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
}
1.6 改变作用域
目前,我们的点的 X 坐标在 0 到 9 之间。在处理函数时,这不是一个方便的范围。通常,x 的取值范围为[0,1]。当处理以0为中心的函数时,取值范围为[−1,1]。让我们相应地重新定位这些点。
上面的效果可以看到,沿着两个单位长的线段放置十个立方体会导致它们重叠,所以我们把每个点的缩放比例改成 。
for (int i = 0; i < 10; i++) {
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
point.localScale = Vector3.one / 5f;
}
游戏模式下,你将看到下图的样子
把这些点对称的放到 [-1,1] 里面,C# 中不会取整,保留实际运算结果
point.localPosition = Vector3.right * ((i + 0.5f) / 5f - 1f);
游戏模式下,Points 就填充了[-1,1]
简化代码
using UnityEngine;
public class Graph : MonoBehaviour
{
[SerializeField]
Transform pointPrefab;
void Awake()
{
var position = Vector3.zero;
var scale = Vector3.one / 5f;
for (int i = 0; i < 10; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) / 5f - 1f;
point.localPosition = position;
point.localScale = scale;
}
}
}
1.7 用X定义Y
-
实现 的直线效果
for (int i = 0; i < 10; i++) { Transform point = Instantiate(pointPrefab); position.x = (i + 0.5f) / 5f - 1f; position.y = position.x; point.localPosition = position; point.localScale = scale; } -
实现 的直线效果
for (int i = 0; i < 10; i++) { Transform point = Instantiate(pointPrefab); position.x = (i + 0.5f) / 5f - 1f; position.y = position.x * position.x; point.localPosition = position; point.localScale = scale; } -
计算一个笑脸玩玩~
附上代码,大家自行尝试吧~using UnityEngine; public class Graph : MonoBehaviour { [SerializeField] Transform pointPrefab; void Awake() { var position = Vector3.zero; var position2 = Vector3.zero; var position3 = Vector3.zero; var scale = Vector3.one / 5f; for (int i = 0; i < 10; i++) { Transform point = Instantiate(pointPrefab); position.x = (i + 0.5f) / 5f - 1f; position.y = position.x * position.x; point.localPosition = position; point.localScale = scale; Transform point2 = Instantiate(pointPrefab); position2.x = (i + 0.5f) / 5f - 2f; position2.y = -1 * position2.x * position2.x - 2 * position2.x + 1; point2.localPosition = position2; point2.localScale = scale; Transform point3 = Instantiate(pointPrefab); position3.x = (i + 0.5f) / 5f; position3.y = -1 * position3.x * position3.x + 2 * position3.x + 1; point3.localPosition = position3; point3.localScale = scale; } } } ```