Unity3D学习笔记(十一):布料和协程

延迟函数:
动态资源加载:
T:Resources.Load<T>(string path);
Assets - Resources,Resources是一个资源管理的工具类,预制体放在Resources 文件夹下
绝对路径:从磁盘的根目录开始
相对路径:相对于Resources文件夹下的路径,用斜杠
斜杠(除号):Unity,网址http
反斜杠:Windows资源管理文件夹
进程:双击一个.exe可执行应用程序,windows就会给我们开启一个进程来运行程序。
线程:每一个进程中,最少有一个主线程(Main函数是主线程的入口),但是可以有多个辅助线程。
主线程卡死,程序会崩溃,辅线程卡死,程序不会崩溃,可以把死循环放在辅线程里。
协程(协同程序):协程是Unity为我们提供的一个模拟多线程的工具,并不是真的多线程。

开启协程:
StartCoroutine(string methodName);//由此就开启一个协程,程序会进入到协程里面执行
StartCoroutine(methodName());//第二种方式
yield return new WaitForSecond(float time);//等待n秒
yield return null或0;//等待一帧
yield return StartCoroutine();//等待此协程执行完毕
yield break;//直接跳出,结束当前协程

停止协程:
StopCoroutines();
//当使用方法名的字符串形式开启的协程,可以用同样的方式停止协程
//用方法名加括号开启的协程,只能用StopAllCoroutines停止协程
StopAllCoroutines();
协程的返回值是一个迭代器对象,Unity引擎会判断条件是否成立,如果成立再继续执行
协程也有生命周期,类似update,每一帧Unity都会去判断条件是否成立

IEnumerator是迭代器
Current指向第一个元素的指针,MoveNext判断是否可以移到下一个元素

协程练习:
1、塔防游戏,5波小怪,没波小怪间隔5秒,每波有20个小怪(间隔1秒生成1个),
3、有一个按钮(开始游戏),
3、按照一定的路点移动,从A点移动到B点,走到B点销毁
 
AsyncOperation异步加载
YieldInstruction包含所有的异步对象
1、是否加载完成之后启动场景
2、加载完成
3、
4、加载进度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightOnOff : MonoBehaviour {
    //public int lightOnTime;
    //public int lightOffTime;
    //private Light light;
    public GameObject directionalLight;
    public GameObject[] points;
    private int index = 0;
    // Use this for initialization
    void Start () {
        //思考题
        //地面,灯-点光源(白,红,蓝,绿),依次亮灭
        //light = GetComponent<Light>();
        //InvokeRepeating("LightOn", lightOnTime, 5);
        //InvokeRepeating("LightOff", lightOffTime, 5);
        directionalLight.SetActive(false);
        InvokeRepeating("ChangePointLightState", 1, 1);
    }
    // Update is called once per frame
    void Update () {
              
       }
    //void LightOn()
    //{
    //    Debug.Log("LightOn");
    //    light.range = 10;
    //}
    //void LightOff()
    //{
    //    Debug.Log("LightOff");
    //    light.range = 0;
    //}
    void ChangePointLightState()
    {
        for (int i = 0; i < points.Length; i++)
        {
            if (i == index)
            {
                points[i].SetActive(true);
            }
            else
            {
                points[i].SetActive(false);
            }
        }
        index++;
        index %= points.Length;//防止数组越界
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttackMonster : MonoBehaviour {
    private int hp = 100;
       // Use this for initialization
       void Start () {
        InvokeRepeating("MonsterUnderAttack", 1, 1);
    }
       
       // Update is called once per frame
       void Update ()
    {
              if (Input.GetMouseButton(0))
        {
            CancelInvoke();
            Debug.Log("你取消了进攻");
        }
    }
    void MonsterUnderAttack()
    {
        hp -= 10;
        Debug.Log("怪兽被攻击" + hp);      
        if (hp <= 0)
        {
            CancelInvoke();
            Debug.Log("怪兽被打死了");
        }
     
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TimeWait : MonoBehaviour {
       // Use this for initialization
       void Start () {
        StartCoroutine(DelayTime());
        Debug.Log("等待两秒");
    }
       
       // Update is called once per frame
       void Update () {
    }
    IEnumerator DelayTime()
    {    
        yield return new WaitForSeconds(2f);
        Debug.Log("两秒到了");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResourcesScript : MonoBehaviour {
       // Use this for initialization
       void Start () {
        //动态资源加载
        GameObject cube = Resources.Load<GameObject>("Prefabs/Cube");
        Instantiate(cube);
        //加载多个资源
        //Resources.LoadAll<GameObject>();
        //异步资源加载
        //异步场景切换
    }
    // Update is called once per frame
    void Update () {
              
       }
}
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class LessonTest : MonoBehaviour {
       // Use this for initialization
       void Start () {
        //开启线程
        Thread lxmThread = new Thread(Hello);
        //开启协程,方法名的字符串形式
        StartCoroutine("HelloWorld");//程序从此进入,遇到yield return关键词又从此跳出
        Debug.Log("this is start");
        //开启协程,方法名加括号形式
        //StartCoroutine(HelloWorld());
        //停止协程,方法名的字符串形式,被挂起的程序不会执行
        StopCoroutine("HelloWorld");
        //停止所有协程
        StopAllCoroutines();
        //停止协程,不能用方法名加括号形式
        //用方法名加括号开启协程,只能用StopAllCoroutines关闭
        //StopCoroutine(HelloWorld());
    }
    // Update is called once per frame
    void Update () {
              
       }
    void Hello()
    {
    }
    IEnumerator HelloWorld()
    {
        //StopAllCoroutines();//"this is before HelloWorld"仍会执行
        Debug.Log("this is before HelloWorld");//程序执行到此包括之前,和执行一个普通的方法没有任何区别
        yield return new WaitForSeconds(2);//直到遇到yield return关键字,程序会跳出,从哪来跳哪去(程序被挂起2秒之后再执行)
        Debug.Log("this is after HelloWorld");//如果迭代器对象满足条件了,程序就会再次从此处执行。
        yield return new WaitForSeconds(2);//程序从Unity引擎进入,并跳回Unity引擎,不会跳到主线程的StartCoroutine
        Debug.Log("this is last HelloWorld");
        //等最后一帧判断
        //yield return new WaitForEndOfFrame();
        //等待一帧,可以开启另一个update
        //yield return null;
        //while (true)//模拟update,卡死模拟线程,
        //{
        //    yield return null;//程序从此跳出,等一帧再进来
        //}
        //协程的嵌套
        yield return StartCoroutine("ThankYou");
        Debug.Log("this is second last HelloWorld");
        //等待物理帧更新
        yield return new WaitForFixedUpdate();
        //等待百度响应
        yield return new WWW("www.baidu.com");
        //WWW的资源热更新
    }
    IEnumerator ThankYou()
    {
        Debug.Log("this is before ThankYou");
        yield return new WaitForSeconds(2);
        Debug.Log("this is after ThankYou");
    }
 
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GUITest : MonoBehaviour {
    public Slider slider;
    public Texture image;
    public float height;
    public float width;
    public float addHeight;
    public float uiNormalFactor = 4;//血条缩放因子的系数,控制血条缩放大小
    private float totelHealth;
    private Transform player;
    private Camera camera;
    private float uiScaleFactor = 1;//血条缩放因子
    private float _progress;//真实进度
    private float m_progress;//虚拟进度
    // Use this for initialization
    void Start () {
        player = GameObject.Find("CJY").transform;
        camera = Camera.main;
        totelHealth = width;
    }
       
       // Update is called once per frame
       void Update () {
        //减血,血条左边框位置固定的,从右边减血条宽度
        if (Input.GetKeyDown(KeyCode.Space))
        {
            width -= totelHealth * 0.1f;//减剩余血量的百分之十
            if (width <= 0)
            {
                Dead();
            }
        }
    }
    private void Dead()
    {
        Destroy(gameObject);
    }
    void OnGUI()
    {
        //OnGUI在商业中只负责调试工具,实际开发用UGUI
        //Rect类似屏幕坐标系坐标,x指的是UI左上角离屏幕左边框的距离
        //绘制血条
        //位置:屏幕坐标转世界转世界坐标
        //Vector3 screenPosl = camera.W
        Vector3 targetPos = new Vector3(player.position.x, player.position.y + addHeight, player.position.z);
        Vector3 screenPos = camera.WorldToScreenPoint(targetPos);
        uiScaleFactor = 1 / screenPos.z * uiNormalFactor;//血条缩放因子,血条近大远小,z分量去调节
        //屏幕坐标转世界坐标系,无论在摄像机前后,都换算出一个坐标
        //用点乘,判断摄像机前后位置,在后面不绘制
        Vector3 cameraForward = camera.transform.forward;
        Vector3 camera2Player = transform.position - camera.transform.position;
        if (Vector3.Dot(cameraForward, camera2Player) > 0)
        {
            GUI.DrawTexture(new Rect(screenPos.x - width / 2 * uiScaleFactor,
                Screen.height - screenPos.y - height / 2 * uiScaleFactor,
                width * uiScaleFactor,
                height * uiScaleFactor),
                image);
        }
        //场景切换
        //1、场景打包,Build Setting 加入场景
        //2、引用命名空间,using UnityEngine.SceneManagement;
        //异步切换场景,场景大,加载慢,用SceneManager只有加载完毕,才会显示场景
        if (GUI.Button(new Rect(Screen.width / 2 - width / 2, Screen.height / 2 - height / 2, width, height), "开始游戏"))
        {
            AsyncOperation oepration = SceneManager.LoadSceneAsync("GameScene");
            StartCoroutine(LoadSceneAsync(oepration));        //在协程里加载
        }
        GUILayout.Label("加载进度: " + m_progress);//把加载进度显示在屏幕右上角
        slider.value = m_progress;//把加载进度赋值给滚动条
    }
    IEnumerator LoadSceneAsync(AsyncOperation oepration)
    {
        oepration.allowSceneActivation = false;//自动加载场景关闭,改为手动切换
        while (m_progress < 1.0)
        {
            if (_progress < 0.9f)//小于0.9f时,让虚拟进度追赶真实进度,真实进度会卡在0.9f自动加载场景处
            {
                _progress = oepration.progress;
                m_progress = Mathf.MoveTowards(m_progress, _progress, 0.01f);//显示虚拟进度,,速度0.01f
            }
            else//大于等于0.9f时,让虚拟进度超过真实进度,改为追赶1.0
            {
                m_progress = Mathf.MoveTowards(m_progress, 1.0f, 0.01f);
            }
            yield return 0;//等待1帧
        }
        yield return new WaitForSeconds(1);//等待1秒再做切换
        oepration.allowSceneActivation = true;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FindPath : MonoBehaviour {
    public Transform[] paths;
    public Vector3 dir;
    public float moveSpeed = 0.1f;
    public float rotSpeed = 5;
    int index = 0;
    // Use this for initialization
    void Start () {
              
       }
       
       // Update is called once per frame
       void Update () {
        if (Vector3.Distance(paths[index].position, transform.position) <= 0.5f)
        {
            if (index == 4)
            {
                Destroy(gameObject);
            }
            index++;
            index %= paths.Length;
        }
        else
        {
            dir = paths[index].position - transform.position;
            Quaternion targetRotation = Quaternion.LookRotation(dir);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1 / Quaternion.Angle(transform.rotation, targetRotation) * rotSpeed);
            transform.position = Vector3.Lerp(transform.position, paths[index].position, 1 / Vector3.Distance(transform.position, paths[index].position) * moveSpeed);               
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour {
    public float monsterRate = 1f;
    private int monsterNum;
    // Use this for initialization
    void Start () {
       
    }
       
       // Update is called once per frame
       void Update () {
      
    }
    IEnumerator EnemyTeamBirth()
    {
        InvokeRepeating("EnemyBirth", 1, monsterRate);
        yield return new WaitForSeconds(25);
        InvokeRepeating("EnemyBirth", 1, monsterRate);
        yield return new WaitForSeconds(25);
        InvokeRepeating("EnemyBirth", 1, monsterRate);
        yield return new WaitForSeconds(25);
        InvokeRepeating("EnemyBirth", 1, monsterRate);
        yield return new WaitForSeconds(25);
        InvokeRepeating("EnemyBirth", 1, monsterRate);
    }
    void EnemyBirth()
    {
        monsterNum++;
        GameObject cube = Resources.Load<GameObject>("Prefabs/Cube");
        Instantiate(cube);
        Debug.Log(monsterNum);
        if (monsterNum >= 20)
        {
            CancelInvoke();
            monsterNum = 0;
        }
       
    }
    void OnGUI()
    {
        if (GUI.Button(new Rect(1, 1, 100, 20), "开始游戏"))
        {
            StartCoroutine("EnemyTeamBirth");
        }
    }
}

复习

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class w07d3 : MonoBehaviour
{
    Rigidbody rig;
    public float force = 10;
    public float radius = 5;
    void Start()
    {
        //rig = GetComponent<Rigidbody>();
        //rig.AddForce(transform.up * force, ForceMode.Impulse);
        /*                       Ft = mv
           Force = 0,    持续力   F = ma
           //
           // 摘要:
           //     ///
           //     Add an instant force impulse to the rigidbody, using its mass.
           //     ///
           Impulse = 1,         t = 1,  F = mv
           //
           // 摘要:
           //     ///
           //     Add an instant velocity change to the rigidbody, ignoring its mass.
           //     ///
           VelocityChange = 2,   t = m = 1,  F = v
           //
           // 摘要:
           //     ///
           //     Add a continuous acceleration to the rigidbody, ignoring its mass.
           //     ///
           Acceleration = 5      m = 1   F = v/t = a
           */
        // 射线检测:必须要有碰撞器组件
        // 相交球
        //Collider[] cols = Physics.OverlapSphere(transform.position, radius, LayerMask.GetMask("Enemy", "Boss"));
        //foreach (var item in cols)
        //{
        //    Debug.Log(item.transform.name);
        //}
        // 开始按钮
        // 5波小怪  每波之间间隔5秒
        // 每一波有20个小怪 每个小怪 间隔1秒
    }
    private void OnDrawGizmos()
    {
        Gizmos.color = new Color(0, 1, 0, 0.3f);
        Gizmos.DrawSphere(transform.position, radius);
    }
    void Update1()
    {
        RaycastHit hit;
        Ray ray = new Ray(transform.position, transform.forward);
        if (Physics.Raycast(ray, out hit, 100, LayerMask.GetMask("Enemy", "Boss")))
        {
            Debug.Log("name:" + hit.transform.name);
            // 检测到的游戏物体的位置
            Debug.Log("pos :" + hit.transform.position);
            // 射线与碰撞框相交的点的位置
            Debug.Log("hit pos :" + hit.point);
            //Debug.Log("distance :" + hit.distance);
            Vector3 dir = hit.point - ray.origin;
            float distance = dir.magnitude;
        }
    }
}
用栈作对象池存储对象
list - LinkedListNode,存储节点
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pool<T> where T : class  // 对泛型做限制
    // 限制为 引用类型 where T : class
    // 限制为 值类型   where T : struct
    // 限制T有默认无参构造函数 where T : new()
    // 限制T为某类型的子类    where T : UnityEngine.Object
    // 限制T 继承了某接口     where T : IEnumerable
    // 组合使用 通过逗号分割   组合的时候 new()写在末尾
{
    Stack<T> pool = new Stack<T>();
    Stack<int> pool = new Stack<int>();  // 栈 先进后出
    Queue<int> queue = new Queue<int>();  // 队列 先进先出
    LinkedList<int> link = new LinkedList<int>();
    void Start()
    {
        #region 栈操作
        pool.Push(10);
        pool.Push(5);               // 入栈
        int result = pool.Pop();    // 弹栈
        //result = pool.Pop();
        result = pool.Peek();       // 访问栈顶元素 该元素没有弹栈
        Debug.Log(result);
        Debug.Log(pool.Count);
        #endregion
        #region 队列操作
        queue.Enqueue(10);             // 入队
        queue.Enqueue(5);
        int result = queue.Dequeue();  // 出队  元素会从队列里移除
        result = queue.Peek();         // 访问队头的元素 该元素没有出队
        Debug.Log(result);
        Debug.Log(queue.Count);
        #endregion
        #region 链表操作
        link.AddLast(10);
        link.AddLast(9);
        link.AddFirst(11);
        #endregion
    }
    public void Push(T item)
    {
        pool.Push(item);
    }
    public T Pop()
    {
        if (pool.Count == 0)
        {
            return default(T);      // 使用类型的默认值 如果T是引用类型 返回null
        }
        return pool.Pop();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 管理所有的对象池 对于各个类型 都需要有相应的方法
public class PoolManager : MonoBehaviour {
    enum EPoolType
    {
        Bullet,
        Enemy,
    }
    Dictionary<EPoolType, Pool<GameObject>> pools = new Dictionary<EPoolType, Pool<GameObject>>();
    public GameObject bulletPrefab;
    public Texture t;
    //Pool<GameObject> bulletPool = new Pool<GameObject>();
    //Pool<GameObject> enemyPool = new Pool<GameObject>();
    private void Awake()
    {
        bulletPrefab = Resources.Load<GameObject>("Bullets/Bullet"); //Resources.Load("Bullet") as GameObject;
        t = Resources.Load<Texture>("Effects/Light");
    }
    void Start () {
        // 对于对象池做初始化操作
        pools.Add(EPoolType.Bullet, new Pool<GameObject>());
        pools.Add(EPoolType.Enemy, new Pool<GameObject>());
       }
       
       void Update () {
              
       }
    public GameObject SpawnBullet(Vector3 pos, Quaternion q)
    {
        GameObject bullet = pools[EPoolType.Bullet].Pop();
        //GameObject bullet = bulletPool.Pop();
        if(bullet == null)
        {
            bullet = Instantiate(bulletPrefab, pos, q);
        }
        else
        {
            bullet.SetActive(true);
        }
        return bullet;
    }
    public void PushBullet(GameObject bullet)
    {
        bullet.SetActive(false);
        //bulletPool.Push(bullet);
        pools[EPoolType.Bullet].Push(bullet);
    }
}

猜你喜欢

转载自www.cnblogs.com/ciaowoo/p/10362917.html