文章目录
简介
在Unity中,C#协程(Coroutine)是一种特殊的异步编程机制,它允许我们在不阻塞主线程的情况下执行耗时操作,并且可以按照帧率分阶段地完成任务。以下是5个使用Unity协程的高级用例:
1. 异步加载场景并显示加载进度
IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
while (!asyncLoad.isDone)
{
float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f); // 考虑到加载过程前0.9的部分代表实际资源加载
Debug.Log($"Loading Scene: {progress * 100}%");
yield return null; // 让出当前帧,等待下一帧继续检查加载进度
}
}
void Start()
{
StartCoroutine(LoadSceneAsync("NextScene"));
}
这个例子展示了如何通过协程异步加载场景,并在加载过程中实时反馈进度。
2. 延迟执行与定时器功能
IEnumerator DelayedAction(float delay, Action action)
{
float startTime = Time.time;
while (Time.time < startTime + delay)
{
yield return null;
}
action();
}
void UseDelayedAction()
{
StartCoroutine(DelayedAction(3f, () =>
{
Debug.Log("Delayed action executed after 3 seconds.");
}));
}
在这个案例中,我们创建了一个延迟执行动作的协程,可以在指定时间后执行任意给定的回调函数。
3. 动画序列控制
IEnumerator AnimateSequence(GameObject target, AnimationClip[] clips)
{
foreach (var clip in clips)
{
target.GetComponent<Animator>().Play(clip.name);
while (target.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).normalizedTime < 1.0f)
{
yield return null;
}
}
Debug.Log("Animation sequence completed.");
}
void PlaySequence()
{
GameObject character = GameObject.FindWithTag("Player");
var clips = new AnimationClip[3] { animJump, animIdle, animRun };
StartCoroutine(AnimateSequence(character, clips));
}
此例说明了如何通过协程按顺序播放一组动画片段,在每个片段播放完毕后切换至下一个片段。
4. 网络请求处理
using UnityEngine.Networking;
IEnumerator FetchData(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
string data = www.downloadHandler.text;
Debug.Log("Received data: " + data);
ProcessData(data);
}
else
{
Debug.LogError("Error: " + www.error);
}
}
void RequestData()
{
StartCoroutine(FetchData("http://example.com/data.json"));
}
这个示例展示了如何利用协程处理网络请求,当请求完成时读取返回的数据,并在网络请求期间保持游戏运行流畅。
5. 渐变颜色或透明度变化
IEnumerator FadeInOut(Color startColor, Color endColor, float duration)
{
float timeElapsed = 0f;
Material mat = GetComponent<Renderer>().material;
Color currentColor = mat.color;
while (timeElapsed < duration)
{
timeElapsed += Time.deltaTime;
float t = timeElapsed / duration;
currentColor = Color.Lerp(startColor, endColor, t);
mat.color = currentColor;
yield return null;
}
mat.color = endColor;
}
void FadeOut()
{
StartCoroutine(FadeInOut(Color.white, Color.clear, 2f));
}
在此案例中,协程用于实现颜色或透明度渐变过渡效果,逐渐改变物体的颜色或透明度直至达到目标值。
6. 游戏对象的动态移动序列
IEnumerator MoveToSequence(Transform target, Vector3[] waypoints, float speed)
{
for (int i = 0; i < waypoints.Length; i++)
{
Vector3 destination = waypoints[i];
while (Vector3.Distance(target.position, destination) > 0.1f)
{
target.position = Vector3.MoveTowards(target.position, destination, speed * Time.deltaTime);
yield return null;
}
// 到达一个点后可以暂停一会儿,增加平滑过渡效果
yield return new WaitForSeconds(0.2f);
}
Debug.Log("Move sequence completed.");
}
void StartMoving()
{
Transform playerTransform = GameObject.FindWithTag("Player").transform;
Vector3[] path = { new Vector3(0, 0, 0), new Vector3(5, 0, 0), new Vector3(5, 5, 0) };
StartCoroutine(MoveToSequence(playerTransform, path, 2f));
}
此示例中,协程用于实现游戏对象按照预设路径顺序移动,每到达一个点后等待片刻再继续移动到下一个目标点。
7. 处理帧率依赖的时间间隔
IEnumerator FrameRateIndependentInterval(float realTimeSeconds)
{
float startTime = Time.time;
float elapsedTime = 0f;
while (elapsedTime < realTimeSeconds)
{
elapsedTime += Time.deltaTime;
yield return null;
}
Debug.Log("A frame rate independent interval of " + realTimeSeconds + " seconds has passed since start.");
}
void RunFrameRateIndependentAction()
{
StartCoroutine(FrameRateIndependentInterval(3f));
}
在本例子中,我们创建了一个不受实际帧率影响的定时器,确保无论帧率如何变化,都会在指定的真实时间(例如3秒)之后执行操作。
8. 异步加载资源并在完成后初始化
using UnityEngine.ResourceManagement.AsyncOperations;
IEnumerator LoadAssetAsync<T>(string assetPath, System.Action<T> onLoaded)
{
AsyncOperationHandle<T> operation = Addressables.LoadAssetAsync<T>(assetPath);
while (!operation.IsDone)
{
yield return null;
}
if (operation.Status == AsyncOperationStatus.Succeeded)
{
T loadedAsset = operation.Result;
onLoaded?.Invoke(loadedAsset);
}
else
{
Debug.LogError($"Failed to load asset at path: {assetPath}");
}
Addressables.Release(operation);
}
void InitializeWithLoadedAsset()
{
StartCoroutine(LoadAssetAsync<GameObject>("Assets/Prefabs/MyPrefab.prefab", prefab =>
{
Instantiate(prefab, Vector3.zero, Quaternion.identity);
}));
}
在这个例子中,使用Unity Addressables异步加载系统加载资源,并在加载完成后通过回调函数进行初始化操作。
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(41-50)
————————————————
最后我们放松一下眼睛