第二天 Unity基本概念及脚本编程

讲解实例:3D射击游戏

 

注:今天所学的知识是重中之重,是Unity的基础,也是核心,掌握了本章内容,在自行设计一些玩法,在简洁的Unity框架下,理论上编写一个小游戏是很简单的,因为Unity中脚本的编写几乎都要用到今天所学的内容,万变不离其宗。让我们开始今天的学习吧。

一、Unity基本概念

用Unity创建游戏是由一个或多个场景(Scene)组成的,打开Unity会默认创建一个场景。

第二天 Unity基本概念及脚本编程_第1张图片

  

1、游戏物体和组件

第二天 Unity基本概念及脚本编程_第2张图片

(1)空物体

第二天 Unity基本概念及脚本编程_第3张图片 第二天 Unity基本概念及脚本编程_第4张图片

第二天 Unity基本概念及脚本编程_第5张图片 (2) 球体等3D原型物体

第二天 Unity基本概念及脚本编程_第6张图片

第二天 Unity基本概念及脚本编程_第7张图片

第二天 Unity基本概念及脚本编程_第8张图片

Tip:第二天 Unity基本概念及脚本编程_第9张图片

 第二天 Unity基本概念及脚本编程_第10张图片

 

 (3)灯光

第二天 Unity基本概念及脚本编程_第11张图片

 

 (4)摄像机

第二天 Unity基本概念及脚本编程_第12张图片

第二天 Unity基本概念及脚本编程_第13张图片 第二天 Unity基本概念及脚本编程_第14张图片

2、变换组件

 第二天 Unity基本概念及脚本编程_第15张图片

(1)位置

第二天 Unity基本概念及脚本编程_第16张图片

 第二天 Unity基本概念及脚本编程_第17张图片

(2)朝向

第二天 Unity基本概念及脚本编程_第18张图片

(3)缩放比例

第二天 Unity基本概念及脚本编程_第19张图片

(4)父子关系

 第二天 Unity基本概念及脚本编程_第20张图片

3、“父子关系”详解

第二天 Unity基本概念及脚本编程_第21张图片

(1)使用“父子关系”复用零件

第二天 Unity基本概念及脚本编程_第22张图片 第二天 Unity基本概念及脚本编程_第23张图片

(2)父子关系与局部坐标系

第二天 Unity基本概念及脚本编程_第24张图片

 第二天 Unity基本概念及脚本编程_第25张图片

第二天 Unity基本概念及脚本编程_第26张图片

(3)用父子关系表示角色骨骼

第二天 Unity基本概念及脚本编程_第27张图片

第二天 Unity基本概念及脚本编程_第28张图片  Tip:

第二天 Unity基本概念及脚本编程_第29张图片

(4)利用父物体统一管理大量物体

第二天 Unity基本概念及脚本编程_第30张图片

4、物体的标签和层

第二天 Unity基本概念及脚本编程_第31张图片

Tip:

第二天 Unity基本概念及脚本编程_第32张图片 (1)标签(Tag)的简要说明

第二天 Unity基本概念及脚本编程_第33张图片

 (2)层(Layer)的简要说明

 第二天 Unity基本概念及脚本编程_第34张图片

5、常用组件

 第二天 Unity基本概念及脚本编程_第35张图片

第二天 Unity基本概念及脚本编程_第36张图片

第二天 Unity基本概念及脚本编程_第37张图片

二、用脚本获取物体和组件

第二天 Unity基本概念及脚本编程_第38张图片

1、物体、组件和对象

第二天 Unity基本概念及脚本编程_第39张图片

Tip:

一个脚本可以挂载到多个物体,一个物体也可以挂载多个脚本。

 

  Tip:

什么是物体:

简单来讲,就是这些东西。

第二天 Unity基本概念及脚本编程_第40张图片

 什么是组件:

简单来讲,就是这些东西。

第二天 Unity基本概念及脚本编程_第41张图片

什么是对象:

简单来讲,对象是相对而言的,一个组件所挂载的物体就是对象。

一个物体的组件也可以是对象。 

2、获取组件的方法

组件已挂载到物体上: 

第二天 Unity基本概念及脚本编程_第42张图片

 

using UnityEngine;

public class Test : MonoBehaviour
{
    SphereCollider collider;
    
    void Start()
    {
        //获取到组件后,将它的引用保存在cllider字段中,方便下次使用
        collider = gameObject.GetComponent();
    }
}

 第二天 Unity基本概念及脚本编程_第43张图片

using UnityEngine;

public class Test : MonoBehaviour
{
    SphereCollider collider;
    
    void Start()
    {
        //获取到组件后,将它的引用保存在cllider字段中,方便下次使用
        collider = gameObject.GetComponent();
        //一下每一句的写法均等同于上一句
        collider = this.gameObject.GetComponent();//this指脚本对象自身,gameObject是它的属性
        collider = transform.GetComponent();//通过transform组件获取其他组件
        collider = transform.GetComponent().GetComponent();
        collider = transform.GetComponent().GetComponent();
        //多此一举的写法,但结果不错
    }
}

 第二天 Unity基本概念及脚本编程_第44张图片

第二天 Unity基本概念及脚本编程_第45张图片 

using UnityEngine;

public class Test : MonoBehaviour
{
    SphereCollider collider;
    
    void Start()
    {
        //获取到组件后,将它的引用保存在cllider字段中,方便下次使用
        collider = gameObject.GetComponent();
        //一下每一句的写法均等同于上一句
        Test[] tests = GetComponents();
        Debug.Log("共有" + tests.Length + "个Test组件");
    }
}

3、获取物体的方法

(1)通过名称获取物体

using UnityEngine;

public class TestGameObject : MonoBehaviour
{
    GameObject objMainCam;
    GameObject objMainLight;
    
    void Start()
    {
        objMainCam = GameObject.Find("Main Camera");
        objMainLight = GameObject.Find("Directional Light");
        Debug.Log("主摄像机:" + objMainCam);
        Debug.Log("主光源:" + objMainLight);
        //将主摄像机放在这个物体后方一米处
        objMainCam.transform.position = transform.position - transform.forward;
    }
}

第二天 Unity基本概念及脚本编程_第46张图片

第二天 Unity基本概念及脚本编程_第47张图片

第二天 Unity基本概念及脚本编程_第48张图片 第二天 Unity基本概念及脚本编程_第49张图片

Tip:

也可以通过禁用摄像机进行尝试。 

(2)通过标签查找物体

     //查找第一个标签为Player的物体
    GameObject player = GameObject.FindGameObjectWithTag("Player");
    //查找所有标签为Monster的物体,注意返回值是一个数组,结果可以是0个或多个
    GameObject[] monsters = GameObject.FindGameObjectsWithTag("Monster");
    //以上两个方法名称的区别是两者差了一个“s”,也就是说Monster是多个物体的标签

在编译器中修改标签 

第二天 Unity基本概念及脚本编程_第50张图片

 在脚本中修改标签:

//获得某个Player物体
    GameObject p = GameObject.FindGameObjectWithTag("Player");
   //将它的标签设置为Cube
   p.tag = "Cube";
   //判断player的标签是不是Cube
   if(p.CompareTag("Cube"))
   {
       Debug.Log("yes");
   }
   //上面得CompareTag用法等价于player.tag == "Cube",推荐使用CompareTag

第二天 Unity基本概念及脚本编程_第51张图片

4、在物体和组件之间任意遨游

(1)通过“父子关系”获取物体

第二天 Unity基本概念及脚本编程_第52张图片

第二天 Unity基本概念及脚本编程_第53张图片 第二天 Unity基本概念及脚本编程_第54张图片

(2)通过父子路径获取物体

第二天 Unity基本概念及脚本编程_第55张图片

第二天 Unity基本概念及脚本编程_第56张图片

第二天 Unity基本概念及脚本编程_第57张图片

(3)其他查找父子物体的方式

第二天 Unity基本概念及脚本编程_第58张图片

第二天 Unity基本概念及脚本编程_第59张图片

(4)一些有用的技巧

第二天 Unity基本概念及脚本编程_第60张图片

5、利用公开变量引用物体和组件

using UnityEngine;

public class TestGetTransform : MonoBehaviour
{
    public GameObject other;
    void Start()
    {
        if(other!=null)
        {
            Debug.Log("other 物体名称为" + other.name);
        }
        else
        {
            Debug.Log("未指定other物体");
        }
    }
}

第二天 Unity基本概念及脚本编程_第61张图片

 

using UnityEngine;

public class TestGetTransform : MonoBehaviour
{
    public GameObject other;

    public TestGetTransform otherTrans;

    public MeshFilter otherMesh;

    public Rigidbody otherRigid;
    
    void Start()
    {
        //任意使用前面定义的变量
    }
}

 以上代码会改变Inspector中的信息:

第二天 Unity基本概念及脚本编程_第62张图片

第二天 Unity基本概念及脚本编程_第63张图片

第二天 Unity基本概念及脚本编程_第64张图片

第二天 Unity基本概念及脚本编程_第65张图片

第二天 Unity基本概念及脚本编程_第66张图片

三、用脚本创建物体

第二天 Unity基本概念及脚本编程_第67张图片

1、预制体

第二天 Unity基本概念及脚本编程_第68张图片

第二天 Unity基本概念及脚本编程_第69张图片

第二天 Unity基本概念及脚本编程_第70张图片

(1)场景物体与预制体的关联

第二天 Unity基本概念及脚本编程_第71张图片

第二天 Unity基本概念及脚本编程_第72张图片

第二天 Unity基本概念及脚本编程_第73张图片

(2)编辑预制体

第二天 Unity基本概念及脚本编程_第74张图片

2、创建物体

Tip:

第二天 Unity基本概念及脚本编程_第75张图片

 第二天 Unity基本概念及脚本编程_第76张图片

Tip:

第二天 Unity基本概念及脚本编程_第77张图片

using UnityEngine;

public class TestInstantiate : MonoBehaviour
{
    public GameObject prefab;

    void Start()
    {
        //在场景根结点创建物体
        GameObject objA = Instantiate(prefab, null);
        //创建一个物体,作为当前脚本所在物体的子物体
        GameObject objB = Instantiate(prefab, transform);
        //创建一个物体,指定他的位置和朝向
        GameObject objC = Instantiate(prefab, new Vector3(3, 0, 3), Quaternion.identity);
    }
}

 第二天 Unity基本概念及脚本编程_第78张图片 

using UnityEngine;

public class TestInstantiate : MonoBehaviour
{
    public GameObject prefab;

    void Start()
    {
       //创建十个物体围成环
       for(int i = 0; i<10; i++)
        {
            Vector3 pos = new Vector3(Mathf.Cos(i * (2 * Mathf.PI) / 10), 0, Mathf.Sin(i * (2 * Mathf.PI) / 10));
            pos *= 5;
            Instantiate(prefab, pos, Quaternion.identity);
        }
    }
}

第二天 Unity基本概念及脚本编程_第79张图片

第二天 Unity基本概念及脚本编程_第80张图片

3、创建组件

using UnityEngine;

public class TestInstantiate : MonoBehaviour
{
    public GameObject prefab;

    void Start()
    {
        GameObject go = GameObject.Find("Cube");
        go.AddComponent();
    }
}

执行前:

第二天 Unity基本概念及脚本编程_第81张图片

执行后:因为加了物理组件受重力影响,物体已经开始下落了。

第二天 Unity基本概念及脚本编程_第82张图片

4、销毁物体和组件

using UnityEngine;

public class TestDestrory : MonoBehaviour
{
    public GameObject prefab;
    void Start()
    {
        //创建20个物体围城环形
        for(int i = 0; i < 20; i++)
        {
            Vector3 pos = new Vector3(Mathf.Cos(i * (2 * Mathf.PI) / 20), 0, Mathf.Sin(i * (2 * Mathf.PI) / 20));
            pos *= 5;
            Instantiate(prefab, pos, Quaternion.identity);
        }
    }
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.D))
        {
            GameObject cube = GameObject.Find("Cube(Clone)");
            Destroy(cube);
        }
    }
}

 第二天 Unity基本概念及脚本编程_第83张图片

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.D))
        {
            GameObject cube = GameObject.Find("Cube(Clone)");
            Destroy(cube);
            cube.AddComponent();
        }
    }

第二天 Unity基本概念及脚本编程_第84张图片

5、定时创建和销毁物体

第二天 Unity基本概念及脚本编程_第85张图片

using UnityEngine;

public class TestInvoke : MonoBehaviour
{
    public GameObject prefab;
    int counter = 0;
    void Start()
    {
        Invoke("CreatePrefab", 0.5f);
    }
    void CreatePrefab()
    {
        Vector3 pos = new Vector3(Mathf.Cos(counter * (2 * Mathf.PI) / 10), 0, Mathf.Sin(counter * (2 * Mathf.PI) / 10));
        pos *= 5;
        Instantiate(prefab, pos, Quaternion.identity);
        counter++;
        if(counter<10)
        {
            Invoke("CreatePrefab", 0.5f);
        }
    }
}

执行结果: 

第二天 Unity基本概念及脚本编程_第86张图片

第二天 Unity基本概念及脚本编程_第87张图片

using UnityEngine;

public class TestDestroy : MonoBehaviour
{
    public GameObject prefab;

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.D))
        {
            GameObject cube = GameObject.Find("Cube(Clone)");
            //Destroy(cube);
            //将上一句改为延迟0.8秒
            Destroy(cube, 0.8f);
            cube.AddComponent();
        }
    }
}

执行结果:

第二天 Unity基本概念及脚本编程_第88张图片

四、脚本的生命周期

第二天 Unity基本概念及脚本编程_第89张图片

1、理解脚本的生命周期

第二天 Unity基本概念及脚本编程_第90张图片

Tip:

第二天 Unity基本概念及脚本编程_第91张图片

 第二天 Unity基本概念及脚本编程_第92张图片

 第二天 Unity基本概念及脚本编程_第93张图片

第二天 Unity基本概念及脚本编程_第94张图片

2、常见的事件方法

第二天 Unity基本概念及脚本编程_第95张图片 第二天 Unity基本概念及脚本编程_第96张图片

第二天 Unity基本概念及脚本编程_第97张图片

第二天 Unity基本概念及脚本编程_第98张图片

3、实例:跟随主角的摄像机

第二天 Unity基本概念及脚本编程_第99张图片

using UnityEngine;

public class FollowCam : MonoBehaviour
{
    //追踪的目标,在编辑器里指定
    public Transform followTarget;
    Vector3 offset;
    void Start()
    {
        //算出从目标到摄像机的向量,作为摄像机的偏移量
        offset = transform.position - followTarget.position;
    }
    void LateUpdate()
    {
        //每帧更新摄像机的位置
        transform.position = followTarget.position + offset;
    }
}

在这里拖拽指定追踪目标即可。 

第二天 Unity基本概念及脚本编程_第100张图片

Tip:

也可以在Vector3前面加上public这样就可以在inspector里面自由调试了。 

 第二天 Unity基本概念及脚本编程_第101张图片

4、触发器事件

第二天 Unity基本概念及脚本编程_第102张图片

第二天 Unity基本概念及脚本编程_第103张图片

第二天 Unity基本概念及脚本编程_第104张图片

Tip:

第二天 Unity基本概念及脚本编程_第105张图片

第二天 Unity基本概念及脚本编程_第106张图片

第二天 Unity基本概念及脚本编程_第107张图片

五、协程入门

第二天 Unity基本概念及脚本编程_第108张图片

using UnityEngine;

public class TestCoroutine : MonoBehaviour
{
    void Start()
    {
        //开启一个协程,协程函数为Time
        StartCoroutine(Timer());
    }

   //协程函数
    IEnumerator Timer()
    {
        //不断循环执行,但是并不会导致死循环
        while(true)
        {
            //打印4个汉字
            Debug.Log("测试协程");
            //等待一秒
            yield return new WaitForSeconds(1);
            //打印当前游戏经历的时间
            Debug.Log(Time.time);
            //在等待1秒
            yield return new WaitForSeconds(1);
        }
    }
}

第二天 Unity基本概念及脚本编程_第109张图片

第二天 Unity基本概念及脚本编程_第110张图片

第二天 Unity基本概念及脚本编程_第111张图片

六、实例:3D射击游戏

接下来做一个简易的俯视角度的射击游戏。

1、游戏总体设计

第二天 Unity基本概念及脚本编程_第112张图片

2、游戏的实现要点

第二天 Unity基本概念及脚本编程_第113张图片

3、创建主角

先搭建场景,在创建主角。

(1)先创建一个蓝灰色平面(Plane)作为地板命名Ground,位置归零(Reset),再放大4倍。

第二天 Unity基本概念及脚本编程_第114张图片

(2)创建一个3D胶囊体(Capsule),命名为Player,适当调整位置。

第二天 Unity基本概念及脚本编程_第115张图片

 (3)给主角设置正面,添加一个正方体做脸(脸是主角的子物体),调整大小,并附上红色材质。

第二天 Unity基本概念及脚本编程_第116张图片

 (4)创建脚本Player以控制主角移动。

using UnityEngine;

public class Player : MonoBehaviour
{
    //移动速度
    public float speed = 3;
    //最大血量
    public float maxHp = 20;
    //变量,输入方向用
    Vector3 input;
    //是否死亡
    bool dead = false;
    //当前血量
    float hp;

    void Start()
    {
        //初始满血状态
        hp = maxHp;
    }
    void Update()
    {
        //将键盘的横向、纵向输入,保存在input变量中
        input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        //未死亡则执行移动逻辑
        if(!dead)
        {
            Move();
        }
    }
    void Move()
    {
        //先归一化输入向量,让输入更直接,同时避免斜向移动时速度超过最大速度
        input = input.normalized;
        transform.position += input * speed * Time.deltaTime;
        //令角色前方与移动方向一致
        if(input.magnitude>0.1f)
        {
            transform.forward = input;
        }
        //以上移动方式没有考虑阻挡,因此使用下面的代码限制移动范围
        Vector3 temp = transform.position;
        const float BORDER = 20;
        if (temp.z > BORDER) { temp.z = BORDER; }
        if (temp.z < -BORDER) { temp.z = -BORDER; }
        if (temp.x > BORDER) { temp.x = BORDER; }
        if (temp.x < -BORDER) { temp.x = -BORDER; }
        transform.position = temp;
    }
}

执行结果:

 第二天 Unity基本概念及脚本编程_第117张图片

由测试结果可知,角色移动的范围确实是|20|

 (5)可以将GetAxis()改为GetButton()或者修改工程面板,减少延时感。第二天 Unity基本概念及脚本编程_第118张图片

 (1)第二天 Unity基本概念及脚本编程_第119张图片

(2) 

 第二天 Unity基本概念及脚本编程_第120张图片

 

4、调整摄像机

第二天 Unity基本概念及脚本编程_第121张图片

第二天 Unity基本概念及脚本编程_第122张图片 摄像机脚本

using UnityEngine;

public class FollowCam : MonoBehaviour
{
    //追踪的目标,在编辑器里指定
    public Transform followTarget;
    Vector3 offset;
    void Start()
    {
        //算出从目标到摄像机的向量,作为摄像机的偏移量
        offset = transform.position - followTarget.position;
    }
    void LateUpdate()
    {
        //每帧更新摄像机的位置
        transform.position = followTarget.position + offset;
    }
}

 第二天 Unity基本概念及脚本编程_第123张图片

 

5、实现武器系统和子弹

using UnityEngine;

public class Weapon : MonoBehaviour
{
    //子弹的prefab
    public GameObject prefabBullet;
    //几种武器的CD时间长度
    public float pistolFireCD = 0.2f;//手枪
    public float shotgunFireCD = 0.5f;//散弹
    public float rifleCD = 0.1f;//步枪
    //上次开火时间
    float lastFireTime;
    //当前使用哪种武器
    public int curGun { get; private set; }//0 手枪,1 散弹,2 自动步枪
    //开火函数,由角色脚本调用
    //keyDown代表这一帧按下开火键,keyPressed代表开火键正在持续按下
    //这样区分是为了实现手枪和步枪的不同手感
    public void Fire(bool keyDown,bool keyPressed)
    {
        //根据当前武器,调用对应的开火函数
        switch(curGun)
        {
            case 0:
                if(keyDown)
                {
                    PistolFire();
                }
                break;
            case 1:
                if(keyDown)
                {
                    shotgunFire();
                }
                break;
            case 2:
                if(keyPressed)
                {
                    RifleFire();
                }
                break;
        }
    }
    //更换武器
    public int Change()
    {
        curGun += 1;
        if(curGun==3)
        {
            curGun = 0;
        }
        return curGun;
    }
    //手枪射击专用函数
    public void PistolFire()
    {
        if (lastFireTime + pistolFireCD > Time.time) 
        {
            return;
        }
        lastFireTime = Time.time;
        GameObject bullet = Instantiate(prefabBullet, null);
        bullet.transform.position = transform.position + transform.forward * 1.0f;
        bullet.transform.forward = transform.forward;
    }
    //自动步枪射击专用函数
    public void RifleFire()
    {
        if (lastFireTime + rifleCD > Time.time) 
        {
            return;
        }
        lastFireTime = Time.time;
        GameObject bullet = Instantiate(prefabBullet, null);
        bullet.transform.position = transform.position + transform.forward * 1.0f;
        bullet.transform.forward = transform.forward;
    }
    //散弹枪射击专用函数
    public void shotgunFire()
    {
        if(lastFireTime+shotgunFireCD>Time.time)
        {
            return;
        }
        lastFireTime = Time.time;
        //创建5颗子弹,间隔10度,扇形分布
        for(int i = -2; i <= 2; i++)
        {
            GameObject bullet = Instantiate(prefabBullet, null);
            Vector3 dir = Quaternion.Euler(0, i * 10, 0) * transform.forward;

            bullet.transform.position = transform.position + dir * 1.0f;
            bullet.transform.forward = dir;
            //散弹枪的子弹射击距离很短,所以要修改子弹生命周期
            Bullet b = bullet.GetComponent();
            b.lifeTime = 0.3f;
        }
    }
}

 第二天 Unity基本概念及脚本编程_第124张图片

 第二天 Unity基本概念及脚本编程_第125张图片

(1)第二天 Unity基本概念及脚本编程_第126张图片 

(2)

第二天 Unity基本概念及脚本编程_第127张图片

(3)

第二天 Unity基本概念及脚本编程_第128张图片

 (4)

using UnityEngine;

public class Bullet : MonoBehaviour
{
    //子弹飞行速度
    public float speed = 10.0f;
    //子弹生命周期(几秒后消失)
    public float lifeTime = 2;
    //子弹"出生"的时间
    float startTime;//上升空间小了就可以享受了
    void Start()
    {
        startTime = Time.time;
    }
    void Update()
    {
        //子弹移动
        transform.position += speed * transform.forward * Time.deltaTime;
        //超过一定时间销毁自身
        if(startTime+lifeTime

(5)

第二天 Unity基本概念及脚本编程_第129张图片

 第二天 Unity基本概念及脚本编程_第130张图片

 第二天 Unity基本概念及脚本编程_第131张图片

   Weapon weapon;

    void Start()
    {
        //初始满血状态
        hp = maxHp;
        weapon = GetComponent();
    }

    void Update()
    {
        //将键盘的横向、纵向输入,保存在input变量中
        input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        Debug.Log(input);

        bool fireKeyDown = Input.GetKeyDown(KeyCode.J);
        bool fireKeyPressed = Input.GetKeyDown(KeyCode.J);
        bool changeWeapon = Input.GetKeyDown(KeyCode.Q);

        //未死亡则执行移动逻辑
        if (!dead)
        {
            Move();

            weapon.Fire(fireKeyDown, fireKeyPressed);

            if(changeWeapon)
            {
                ChangeWeapon();
            }
        }
    }

 

   private void ChangeWeapon()
    {
        int w = weapon.Change();
    }

 

 第二天 Unity基本概念及脚本编程_第132张图片

 第二天 Unity基本概念及脚本编程_第133张图片

6、实现敌人角色

我做的是这样的:

第二天 Unity基本概念及脚本编程_第134张图片

为敌人编写脚本:

using UnityEngine;

public class Enemy : MonoBehaviour
{
    //用于制作死亡效果的预制体,暂时不用
    public GameObject prefabBoomEffect;

    public float speed = 2;
    public float fireTime = 0.1f;
    public float maxHp = 1;

    Vector3 input;

    Transform player;
    float hp;
    bool dead = false;

    Weapon weapon;

    void Start()
    {
        //根据Tag查找玩家物体
        player = GameObject.FindGameObjectWithTag("Player").transform;
        weapon = GetComponent();
    }
    void Update()
    {
        Move();
        Fire();
    }
    void Move()
    {
        //玩家的input是从键盘输入而来,而敌人的input是始终指向玩家方向
        input = player.position - transform.position;
        input = input.normalized;
        transform.position += input * speed * Time.deltaTime;
        if(input.magnitude>0.1f)
        {
            transform.forward = input;
        }
    }
    void Fire()
    {
        //一直开枪,开枪的频率可以通过武器启动控制
        weapon.Fire(true, true);
    }
    private void OnTriggerEnter(Collider other)
    {
        //稍后实现
    }

}

第二天 Unity基本概念及脚本编程_第135张图片 第二天 Unity基本概念及脚本编程_第136张图片

7、子弹击中的逻辑

第二天 Unity基本概念及脚本编程_第137张图片

 第二天 Unity基本概念及脚本编程_第138张图片

 

//当子弹碰到其他物体时触发
    private void OntriggerEnter(Collider other)
    {
        //如果子弹的Tag与被碰撞的物体的Tag相同,则不算打中
        //这是为了防止同类子弹相互碰撞抵消
        if(CompareTag(other.tag))
        {
            return;
        }
        Destroy(gameObject);

  private void OnTriggerEnter(Collider other)
    {
        if(other.CompareTag("EnemyBullet"))
        {
            if (hp <= 0) { return; }
            hp--;
            if (hp <= 0) { dead = true; }
        }
    }

 

 private void OnTriggerEnter(Collider other)
    {
        if(other.CompareTag("PlayerBullet"))
        {
            Destroy(other.gameObject);
            hp--;
            if(hp<=0)
            {
                dead = true;
                //这里可以添加死亡特效
               // Instantiate(prefabBoomEffect,transform.position,transform.rotation);
                Destroy(gameObject);
            }
        }
    }

 第二天 Unity基本概念及脚本编程_第139张图片

第二天 Unity基本概念及脚本编程_第140张图片

8、完善游戏

第二天 Unity基本概念及脚本编程_第141张图片

using UnityEngine;
using System.Collections.Generic;

public class BoomEffect : MonoBehaviour
{
    List objs = new List();

    const int N = 15;

    void Start()
    {
        for(int i=0;i

第二天 Unity基本概念及脚本编程_第142张图片

9、测试和改进

第二天 Unity基本概念及脚本编程_第143张图片

你可能感兴趣的:(学好Unity只需要13天,unity,c#,游戏引擎)