Unity的学习(三):古迹探险

一、新建项目

新建项目,并在Assets下右键Import Package ->Custom Package导入资源。如下图所示。
Unity的学习(三):古迹探险_第1张图片
Unity的学习(三):古迹探险_第2张图片

二、地形设计

地形工具的使用可以参考Unity官方文档

2.1创建地形

在Hierarchy中右键创建Terrain(地形),同时在Assets中会出现New Terrain(保存的是地形相关数据),将其重命名为Terrain Data并将其放入创建的Terrain文件夹中。

2.2 调整地形的长度和宽度

在Hierarchy视图中选中Terrain,可以在Inspector视图中看到Terrain游戏物体的组件Terrain,这时点击齿轮(Terrain Settings),在其中可以设置许多地形相关属性。找到Terrain Width 和Terrain Length以及Terrain Height(地形的最大高度),将他们的值设为50,每一个在修改后,按下回车将会生效。如下图所示。

2.3 Raise or Lower Terrain(升高或降低地形)

其中
Brush size:用来调整刷子尺寸的
Opacity:地形强度,当Opacity越大时,地形升高的越快。

按住shift键并且用刷子刷地形可以降低地形。

详细的可以参考Unity官方文档

2.4 Smooth Height

此工具可以将地形设计的更加平滑。

2.5 Paint Texture

使用 Paint Texture 工具可将纹理(如草、雪或沙)添加到地形。如下图所示。

详情请参考Unity官方文档的Paint Texture和地形图层

2.6 Paint Trees

通过点击Paint Trees图标可以在地形上摆放一些树,如下图所示。

详细请参考Unity官方文档

2.7 Paint Details

通过点击Paint Details图标,可以对草和其他一些细节进行处理,如下图所示。

详细的请参考Unity官方文档

三、古迹探险地形设计

此处自由发挥,就不描述了。
由于太亮,所以需要**调节光的强度。**如下图所示。

最终效果类似于如下图。

四、相机和当前视野保持一致

让相机和当前视野保持一致。选择Main Camera -> GameObject -> Align With View。如下图所示。

五、刚体

在场景中创建球体,运行游戏发现球体在半空中并没有掉落,这时就需要给球体游戏对象添加Rigidbody(刚体)组件来实现物理效果。

Unity的学习(三):古迹探险_第3张图片
Mass:对象的质量(默认为千克)
Drag:阻力
Angular Drag:旋转时的阻力
Use Gravity:是否受重力影响
Freeze Position:锁定刚体沿世界 X、Y 和 Z 轴的移动。
Freeze Rotation:锁定刚体围绕局部 X、Y 和 Z 轴旋转。

有关刚体的更多信息,请参考Unity官方文档

六、碰撞器

碰撞器组件定义对象的形状以便用于物理碰撞。如下图所示,当禁用球体的碰撞器(Sphere Collider)后,球体会直接穿过地面,而没禁用碰撞器时,则会与地面发送物理碰撞效果,也就不会穿过地面。

注意:碰撞发生的条件,两个物体必须都有碰撞体(Collider),并且其中一个需要有刚体(Rigidbody)。

关于碰撞器的详细信息可以查看Unity官方文档

6.1 碰撞检测的方法

在Assets下创建Scripts文件夹,在Scripts中创建命名为Sphere的C#脚本,并将脚本挂载到Sphere游戏物体上。如下图所示。

可以使用以下方法(详情可以参考Unity官方文档)来进行碰撞检测,这些方法都是由Unity调用的:

    //当该碰撞体/刚体已开始接触另一个刚体/碰撞体时,调用 OnCollisionEnter。(碰撞发生时调用)
    private void OnCollisionEnter(Collision collision) {
        
    }

    //当该碰撞体/刚体已停止接触另一个刚体/碰撞体时,调用 OnCollisionExit。(碰撞结束时调用)
    private void OnCollisionExit(Collision collision) {
        
    }

    //对应正在接触刚体/碰撞体的每一个碰撞体/刚体,每帧调用一次 :ref::OnCollisionStay。(碰撞过程中调用)
    private void OnCollisionStay(Collision collision) {
        
    }

6.2 碰撞信息的获取

//当该碰撞体/刚体已开始接触另一个刚体/碰撞体时,调用 OnCollisionEnter。(碰撞发生时调用)
    private void OnCollisionEnter(Collision collision) {
        //获取我们和哪一个碰撞器发生了碰撞
        print(collision.collider); 
        //获取我们碰撞的游戏物体的名字
        print(collision.collider.name);
        //获取我们碰撞的游戏物体的标签
        print(collision.collider.tag);
    }

6.3 触发检测

有时候我们需要做一些机关,当角色靠近机关时会触发一些效果,这时我们就可以将碰撞器设置为触发器(勾选 Is Trigger)。如下图所示。可以创建一个Cube,移除掉Mesh Filter和Mesh Renderer组件。

或者直接创建一个空游戏物体(Create Empty),然后给它添加碰撞器(Collider),并将碰撞器的Is Trigger勾选。并可以使用Edit Collider图标对Collider范围进行调节。如下图所示。

6.4 触发检测的方法

可以使用以下方法来进行触发检测,详情参考Unity官方文档

	//当一个游戏物体开始进入到另一个游戏物体触发区域时,调用OnTriggerEnter
    private void OnTriggerEnter(Collider other) {
        
    }

    //当一个游戏物体离开另一个游戏物体触发区域时,调用OnTriggerExit
    private void OnTriggerExit(Collider other) {
        
    }

    //当一个游戏物体正在另一个游戏物体触发区域时,调用OnTriggerStay
    private void OnTriggerStay(Collider other) {
        
    }

6.5 触发信息的获取

//当一个游戏物体开始进入到另一个游戏物体触发区域时,调用OnTriggerEnter
    private void OnTriggerEnter(Collider other) {
        //获取触发器
        print(other);
        //获取触发器所在游戏物体的名字
        print(other.name);
        //获取触发器所在游戏物体的标签
        print(other.tag);
    }

七、Unity中四种灯光

关于光源的详细信息可以参考Unity官方文档

7.1 Directional Light

方向光对于在场景中创建诸如阳光的效果非常有用。方向光在许多方面的表现很像太阳光,可视为存在于无限远处的光源。方向光没有任何可识别的光源位置,因此光源对象可以放置在场景中的任何位置。

7.2 Point Light

点光源位于空间中的一个点,并在所有方向上均匀发光。照射到表面的光线的方向是从接触点返回到光源对象中心的线。强度随着远离光源而衰减,在到达指定距离时变为零。点光源可用于模拟场景中的灯和其他局部光源。还可以用点光源逼真地模拟火花或爆炸照亮周围环境。

7.3 Spot Light

像点光源一样,聚光灯具有指定的位置和光线衰减范围。不同的是聚光灯有一个角度约束,形成锥形的光照区域。锥体的中心指向光源对象的发光 (Z) 方向。聚光灯锥体边缘的光线也会减弱。加宽该角度会增加锥体的宽度,并随之增加这种淡化的大小,称为“半影”。
聚光灯通常用于人造光源,例如手电筒、汽车前照灯和探照灯。

7.4 Area Light

面光源是通过空间中的矩形来定义的。光线在表面区域上均匀地向所有方向上发射,但仅从矩形的所在的面发射。无法手动控制面光源的范围,但是当远离光源时,强度将按照距离的平方呈反比衰减。由于光照计算对处理器性能消耗较大,因此面光源不可实时处理,只能烘焙到光照贴图中。

八、给场景添加火堆

8.1 给场景添加光源

给场景添加光源,并对光的颜色做一些设置。

8.2 添加火堆

给火堆添加光源,并将其设为Prefab(预制体)。

九、Lightmapping

当我们在场景中不使用光照贴图的话,光对场景的影响是需要实时计算的,这样比较耗费性能。如果视野Lightmapping的话,会提前将光照信息计算好,然后烘焙成一个贴图,并将贴图贴到模型上,这样在实际运行中就不需要进行重复计算了。
Unity的学习(三):古迹探险_第4张图片

由于火光会有动画效果,一闪一闪的,如果用Backed的话,效果是不变的。所以火堆这里需要用Mixed。
Unity的学习(三):古迹探险_第5张图片

观察Scene视图,发现其中没有阴影。

十、使用粒子系统创建火焰

选择Bonfire预制体,创建粒子系统。

调整形状。

调整Start LifeTime和Start Speed


比较详细的过程可以去看siki学院的视频

最终效果,如下图所示。

十一、给灯光添加闪烁效果

创建动画

给灯光添加运动动画效果,让火苗左右摇摆。

整个动画效果,如下图所示。

十二、导航系统(寻路系统)

要使用导航系统需要进行导航网格的烘焙,在烘焙之前需要确定Environment的static是勾选上的(确保Navigation Static勾选上就行了)。

12.1 生成导航网格

在Navigation -> Bake ->Bake按钮。可通过Agent Radius来调节代理半径(类似于在障碍物的范围不可进行导航)。

对于草之类的,角色应该是可以通过的,我们需要将其Navigation Static勾选取消掉,然后再重新进行烘焙。

对于不能到达的,要选中物体->Navigation->Object->AI->Navigation Area->Not Walkable。

Unity的学习(三):古迹探险_第6张图片

12.2 添加导航组件

想要控制角色在网格上行走,需要给角色添加导航组件Nav Mesh Agent,可通过Radius和Height调整宽度和高度。
Unity的学习(三):古迹探险_第7张图片

12.3 通过导航组件控制角色的移动

通过鼠标点击地面,获取鼠标点击的点,将这个点设置为目的地,然后让角色到达目的地。

在Scripts文件夹下创建Hero脚本,并将其挂载到Hero游戏物体上。
Unity的学习(三):古迹探险_第8张图片

12.3.1 射线检测
void Update() {

        //鼠标左键按下
        if (Input.GetMouseButtonDown(0)) {

            //射线检测
            //ScreenPointToRay:将屏幕坐标转换为射线
            //Input.mousePosition:鼠标位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            //用于从射线投射获取信息的结构。
            RaycastHit hit;
            //Physics.Raycast():向场景中的所有碰撞体投射射线,并返回有关命中对象的详细信息,信息保存在hit中。
            if (Physics.Raycast(ray, out hit)) {
                print(hit.point);
            }


        }

    }

12.3.2 控制角色到达目的地

在Hero脚本中定义属性public NavMeshAgent agent;并将组件Nav Mesh Agent拖入。如下图所示。
Unity的学习(三):古迹探险_第9张图片
在判断代码中用agent调用SetDestination()方法

 if (Physics.Raycast(ray, out hit)) {
       //print(hit.point);
       //设置目的地
       agent.SetDestination(hit.point);
}

效果,如下图所示。

完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Hero : MonoBehaviour {

    public NavMeshAgent agent;

    // Start is called before the first frame update
    void Start() {

    }

    // Update is called once per frame
    void Update() {

        //鼠标左键按下
        if (Input.GetMouseButtonDown(0)) {

            //射线检测
            //ScreenPointToRay:将屏幕坐标转换为射线
            //Input.mousePosition:鼠标位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            //用于从射线投射获取信息的结构。
            RaycastHit hit;
            //Physics.Raycast():向场景中的所有碰撞体投射射线,并返回有关命中对象的详细信息,信息保存在hit中。
            if (Physics.Raycast(ray, out hit)) {
                //print(hit.point);
                //设置目的地
                agent.SetDestination(hit.point);
            }


        }

    }
}

十三、控制摄像机的跟随

调节相机到合适的角度,创建FollowTarget脚本,并将其挂载到Main Camera游戏物体上。
Unity的学习(三):古迹探险_第10张图片

在FollowTarget脚本中定义属性public Transform hero;保存,并在Unity中将Hero赋给hero。如下图所示。
Unity的学习(三):古迹探险_第11张图片
代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowTarget : MonoBehaviour {

    //因为跟随目标,只需要目标的位置
    public Transform hero;

    //位置的偏移
    private Vector3 offset;

    // Start is called before the first frame update
    void Start() {
        //当前游戏物体位置减去角色hero的位置
        offset = transform.position - hero.position;
    }

    // Update is called once per frame
    void Update() {
        //相机跟随
        transform.position = offset + hero.position;
    }
}

效果:

十四、控制角色的动画播放

创建Animator Controller。
Unity的学习(三):古迹探险_第12张图片

编辑状态机。

在脚本中设置参数的值进行动画的切换。
Unity的学习(三):古迹探险_第13张图片
代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Hero : MonoBehaviour {

    public NavMeshAgent agent;

    public Animator anim;

    // Start is called before the first frame update
    void Start() {

    }

    // Update is called once per frame
    void Update() {

        //鼠标左键按下
        if (Input.GetMouseButtonDown(0)) {

            //射线检测
            //ScreenPointToRay:将屏幕坐标转换为射线
            //Input.mousePosition:鼠标位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            //用于从射线投射获取信息的结构。
            RaycastHit hit;
            //Physics.Raycast():向场景中的所有碰撞体投射射线,并返回有关命中对象的详细信息,信息保存在hit中。
            if (Physics.Raycast(ray, out hit)) {
                //print(hit.point);
                //设置目的地
                agent.SetDestination(hit.point);
            }


        }
        //agent.velocity.magnitude:速度的大小
        anim.SetFloat("speed",agent.velocity.magnitude);

    }
}

你可能感兴趣的:(Unity3D,游戏开发,unity,游戏)