This commit is contained in:
2026-10-14 19:39:24 +08:00
parent 4fd5a3bd45
commit 8498afd5cf
202 changed files with 12624 additions and 236 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9b5a024b5076b4e48bf76a9036590c0b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7869f32c05eacac4a91f8018cc9cc875
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine.AddressableAssets;
using static UnityEngine.AddressableAssets.Addressables;
/// <summary>
/// AAResourceManager
/// 通用的 Addressables (aa包) 资源管理器,用于统一管理游戏资源的加载和卸载。
/// 通过标签 (Label) + 当前游戏类型 (GameType) 来筛选资源,
/// 并使用映射字典 (name → id) 将资源绑定到对应的 ID,方便后续查找和使用。
/// </summary>
public static class AAResourceManager
{
/// <summary>
/// 加载资源并存入目标字典
/// </summary>
/// <typeparam name="T">资源类型 (例如 GameObject, AudioClip, Sprite, SkeletonDataAsset)</typeparam>
/// <param name="label">Addressables 标签,用于筛选资源</param>
/// <param name="gameTypeLabel">玩法标签(由调用方/游戏侧传入,框架层不反向依赖游戏层)</param>
/// <param name="mappingDic">映射字典 (资源名 → ID),用于将资源绑定到唯一 ID</param>
/// <param name="targetDic">目标字典 (ID → 资源),存放加载后的资源</param>
/// <param name="onLoaded">可选回调,在资源加载完成时执行 (例如绑定对象池)</param>
/// <remarks>
/// - 使用 Addressables.LoadAssetsAsync 按标签和玩法标签加载资源
/// - 将资源存入 targetDic,键为映射字典中的 ID
/// - 可选执行 onLoaded 回调,例如 Prefab 加入对象池
/// - 最后释放 handle,避免内存泄漏
/// </remarks>
public static async Task LoadAssets<T>(
string label,
string gameTypeLabel,
Dictionary<string, int> mappingDic,
Dictionary<int, T> targetDic,
Action<T, int> onLoaded = null)
where T : UnityEngine.Object
{
// 构建 keys:标签 + 玩法标签
var keys = new List<string> { label, gameTypeLabel };
// 异步加载资源
var handle = Addressables.LoadAssetsAsync<T>(keys, asset =>
{
// 根据资源名查找对应 ID
if (mappingDic.TryGetValue(asset.name, out int id))
{
targetDic[id] = asset; // 存入目标字典
onLoaded?.Invoke(asset, id); // 执行回调
}
}, MergeMode.Intersection);
await handle.Task;
// 释放句柄,避免内存泄漏
Addressables.Release(handle);
}
/// <summary>
/// 卸载资源并从目标字典移除
/// </summary>
/// <typeparam name="T">资源类型 (例如 GameObject, AudioClip, Sprite, SkeletonDataAsset)</typeparam>
/// <param name="label">Addressables 标签,用于筛选资源</param>
/// <param name="gameTypeLabel">玩法标签(由调用方/游戏侧传入,框架层不反向依赖游戏层)</param>
/// <param name="mappingDic">映射字典 (资源名 → ID),用于查找对应 ID</param>
/// <param name="targetDic">目标字典 (ID → 资源),存放已加载的资源</param>
/// <remarks>
/// - 使用 Addressables.LoadAssetsAsync 获取当前标签下的资源列表
/// - 遍历资源,查找对应 ID 并从 targetDic 移除
/// - 最后释放 handle,避免内存泄漏
/// </remarks>
public static async Task UnloadAssets<T>(
string label,
string gameTypeLabel,
Dictionary<string, int> mappingDic,
Dictionary<int, T> targetDic)
where T : UnityEngine.Object
{
// 构建 keys:标签 + 玩法标签
var keys = new List<string> { label, gameTypeLabel };
// 异步加载资源列表(仅用于获取引用)
var handle = Addressables.LoadAssetsAsync<T>(keys, null, MergeMode.Intersection);
await handle.Task;
// 遍历资源并移除对应条目
foreach (var asset in handle.Result)
{
if (mappingDic.TryGetValue(asset.name, out int id))
{
targetDic.Remove(id);
}
}
// 释放句柄,避免内存泄漏
Addressables.Release(handle);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18852f331ebfd804999b378e8fce13da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 148474591fcaf1849b134c7b8150d9aa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+212
View File
@@ -0,0 +1,212 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 知识点
/// 1.AB包相关的API
/// 2.单例模式
/// 3.委托——>Lambda表达式
/// 4.协程
/// 5.字典
/// </summary>
public class ABMgr : AutoMonoSingleton<ABMgr>
{
//AB包管理器 目的是
//让外部更方便的进行资源加载
//主包
private AssetBundle mainAB = null;
//依赖包获取用的配置文件
private AssetBundleManifest manifest = null;
//AB包不能够重复加载 重复加载会报错
//字典 用字典来存储 加载过的AB包
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
/// <summary>
/// 这个AB包存放路径 方便修改
/// </summary>
private string PathUrl
{
get
{
return Application.streamingAssetsPath + "/";
}
}
/// <summary>
/// 主包名 方便修改
/// </summary>
private string MainABName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "StandaloneWindows";
#endif
}
}
/// <summary>
/// 加载AB包
/// </summary>
/// <param name="abName"></param>
public void LoadAB( string abName )
{
//加载AB包
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
//我们获取依赖包相关信息
AssetBundle ab = null;
string[] strs = manifest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
//判断包是否加载过
if (!abDic.ContainsKey(strs[i]))
{
ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
abDic.Add(strs[i], ab);
}
}
//加载资源来源包
//如果没有加载过 再加载
if (!abDic.ContainsKey(abName))
{
ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
}
//同步加载 不指定类型
public Object LoadRes(string abName, string resName)
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
Object obj = abDic[abName].LoadAsset(resName);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
//同步加载 根据type指定类型
public Object LoadRes(string abName, string resName, System.Type type)
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
Object obj = abDic[abName].LoadAsset(resName, type);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
//同步加载 根据泛型指定类型
public T LoadRes<T>(string abName, string resName) where T:Object
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
T obj = abDic[abName].LoadAsset<T>(resName);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
//异步加载的方法
//这里的异步加载 AB包并没有使用异步加载
//知识从AB包中 加载资源时 使用异步
//根据名字异步加载资源
public void LoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
yield return abr;
//异步加载结束后 通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
//根据Type异步加载资源
public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName, type);
yield return abr;
//异步加载结束后 通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
//根据泛型 异步加载资源
public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
//加载AB包
LoadAB(abName);
//为了外面方便 在加载资源时 判断一下 资源是不是GameObject
//如果是 直接实例化了 再返回给外部
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
//异步加载结束后 通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset) as T);
else
callBack(abr.asset as T);
}
//单个包卸载
public void UnLoad(string abName)
{
if( abDic.ContainsKey(abName) )
{
abDic[abName].Unload(false);
abDic.Remove(abName);
}
}
//所有包的卸载
public void ClearAB()
{
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
mainAB = null;
manifest = null;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11e3c2c0028c7c44d8523bc91ef4fb1b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 60b851e1a0e38524296024ab447bc15d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AutoMonoSingleton<T>: MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if(_instance==null)
{
GameObject obj = new GameObject();
obj.name = typeof(T).ToString();
DontDestroyOnLoad(obj);
_instance = obj.AddComponent<T>();
}
return _instance;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 83e2c93ea050f244487572f6c78a1dbb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,29 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if (_instance==null)
{
_instance = FindObjectOfType<T>();
if (_instance == null)
{
_instance = new GameObject().AddComponent<T>();
}
}
return _instance;
}
}
protected virtual void Awake()
{
_instance = this as T;
DontDestroyOnLoad(this.gameObject);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bcd03eada2a3a604984f7f1708bf6d00
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+17
View File
@@ -0,0 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> where T:new()
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
_instance = new T();
return _instance;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a3b4544c50b6e8b4b9122f3dc35f907b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d74fb167e3f2c9f4892e944235780644
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,144 @@
#region zijixie
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Device;
using Screen = UnityEngine.Screen;
public static class CoordinateTransformation
{
/// <summary>
/// 世界坐标转换成总父 Canvas 下的 anchoredPosition
/// </summary>
public static Vector2 WorldPos_ToCanvas(Vector3 worldPos, Canvas canvas)
{
var screenPos = Camera.main.WorldToScreenPoint(worldPos);
RectTransform canvasRT = canvas.GetComponent<RectTransform>();
// 2. 屏幕 → Canvas 局部坐标(Overlay 模式 cam 必须为 null)
Vector2 canvasLocalPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvasRT,
screenPos,
canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera,
out canvasLocalPos
);
return canvasLocalPos;
}
/// <summary>
/// 屏幕坐标 → Canvas 坐标(RectTransform 的 anchoredPosition)
/// </summary>
public static Vector2 ScreenPoint_ToCanvas(Vector2 screenPos, Canvas canvas)
{
RectTransform canvasRect = canvas.GetComponent<RectTransform>();
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvasRect,
screenPos,
canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera,
out localPoint);
return localPoint;
}
public static Vector3 UIToWorld(RectTransform targetUI, RectTransform targetCanvas)
{
return CanvasToWorld(GetLocalPositionRelativeToCanvas(targetUI, targetCanvas), targetCanvas, Camera.main);
}
/// <summary>
/// 计算某个 UI 元素相对于指定 Canvas 的局部坐标(基于 Canvas 轴心)
/// </summary>
/// <param name="targetUI">要计算的 UI 元素的 RectTransform</param>
/// <param name="targetCanvas">目标 Canvas 的 RectTransform</param>
/// <returns>相对于 Canvas 轴心的局部坐标(Vector3)</returns>
public static Vector3 GetLocalPositionRelativeToCanvas(RectTransform targetUI, RectTransform targetCanvas)
{
Vector3 worldPos = targetUI.position; // 轴心世界坐标
return targetCanvas.InverseTransformPoint(worldPos);
}
public static Vector3 CanvasToWorld(Vector2 canvasPos, RectTransform canvas, Camera cam)
{
// 1. 获取 Canvas 实际像素尺寸(自动适配所有设备)
float canvasWidth = canvas.rect.width;
float canvasHeight = canvas.rect.height;
// 2. 正交相机的世界高度
float worldHeight = cam.orthographicSize * 2f;
// 3. 世界宽度 = 世界高度 * 屏幕宽高比
float worldWidth = worldHeight * cam.aspect;
// 4. 画布单位 → 世界单位比例(横竖一致)
float scaleX = worldWidth / canvasWidth;
float scaleY = worldHeight / canvasHeight;
// 5. 你的 canvasPos 是以中心为原点的坐标
float worldX = canvasPos.x * scaleX;
float worldY = canvasPos.y * scaleY;
// 6. 映射到世界 z = 0 平面
return new Vector3(worldX, worldY, 0f);
}
/// <summary>
/// 从子坐标转换成总父canvas坐标
/// </summary>
/// <param name="target"></param>
/// <param name="canvas"></param>
/// <returns></returns>
public static Vector2 AnchoredPos_ToCanvas(RectTransform target, Canvas canvas)
{
// 1. 先把 anchoredPosition(父坐标)转换成世界坐标
Vector3 worldPos = target.TransformPoint(target.anchoredPosition);
// 2. 再把世界坐标转换成 Canvas 的局部坐标(等价于 Canvas 下的 anchoredPosition)
RectTransform canvasRT = canvas.GetComponent<RectTransform>();
Vector2 canvasLocalPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvasRT,
RectTransformUtility.WorldToScreenPoint(canvas.worldCamera, worldPos),
canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera,
out canvasLocalPos
);
return canvasLocalPos;
}
public static Vector3 ScreenToWord(Vector3 screenVector3)
{
return Camera.main.ScreenToWorldPoint(screenVector3);
}
public static Vector3 ScreenToCamera(Vector3 screenPos,Camera cam=null)
{
float targetZ = 0;
if (cam==null)
{
cam=Camera.main;
}
// 1. 屏幕左下角原点 → 屏幕中心原点
float cx = screenPos.x - Screen.width * 0.5f;
float cy = screenPos.y - Screen.height * 0.5f;
// 2. 屏幕中心原点 → Unity 标准屏幕坐标(左下角原点)
float ux = cx + Screen.width * 0.5f;
float uy = cy + Screen.height * 0.5f;
// 3. 屏幕 → 世界
float distance = Mathf.Abs(cam.transform.position.z - targetZ);
Vector3 worldPos = cam.ScreenToWorldPoint(new Vector3(ux, uy, distance));
worldPos.z = targetZ;
// 4. 世界 → 相机坐标(相机中心为原点)
float worldHeight = cam.orthographicSize;
return cam.transform.InverseTransformPoint(worldPos);
}
}
#endregion
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf0db1470318abc41bf6af07f8f9918b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f7ac6af63e83c94fbc2268aaafb8658
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,198 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if !DOTWEEN_NOAUDIO // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using UnityEngine;
using UnityEngine.Audio; // Required for AudioMixer
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleAudio
{
#region Shortcuts
#region Audio
/// <summary>Tweens an AudioSource's volume to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this AudioSource target, float endValue, float duration)
{
if (endValue < 0) endValue = 0;
else if (endValue > 1) endValue = 1;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.volume, x => target.volume = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an AudioSource's pitch to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOPitch(this AudioSource target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.pitch, x => target.pitch = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region AudioMixer
/// <summary>Tweens an AudioMixer's exposed float to the given value.
/// Also stores the AudioMixer as the tween's target so it can be used for filtered operations.
/// Note that you need to manually expose a float in an AudioMixerGroup in order to be able to tween it from an AudioMixer.</summary>
/// <param name="floatName">Name given to the exposed float to set</param>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOSetFloat(this AudioMixer target, string floatName, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(()=> {
float currVal;
target.GetFloat(floatName, out currVal);
return currVal;
}, x=> target.SetFloat(floatName, x), endValue, duration);
t.SetTarget(target);
return t;
}
#region Operation Shortcuts
/// <summary>
/// Completes all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens completed
/// (meaning the tweens that don't have infinite loops and were not already complete)
/// </summary>
/// <param name="withCallbacks">For Sequences only: if TRUE also internal Sequence callbacks will be fired,
/// otherwise they will be ignored</param>
public static int DOComplete(this AudioMixer target, bool withCallbacks = false)
{
return DOTween.Complete(target, withCallbacks);
}
/// <summary>
/// Kills all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens killed.
/// </summary>
/// <param name="complete">If TRUE completes the tween before killing it</param>
public static int DOKill(this AudioMixer target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
/// <summary>
/// Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens flipped.
/// </summary>
public static int DOFlip(this AudioMixer target)
{
return DOTween.Flip(target);
}
/// <summary>
/// Sends to the given position all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
/// <param name="to">Time position to reach
/// (if higher than the whole tween duration the tween will simply reach its end)</param>
/// <param name="andPlay">If TRUE will play the tween after reaching the given position, otherwise it will pause it</param>
public static int DOGoto(this AudioMixer target, float to, bool andPlay = false)
{
return DOTween.Goto(target, to, andPlay);
}
/// <summary>
/// Pauses all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens paused.
/// </summary>
public static int DOPause(this AudioMixer target)
{
return DOTween.Pause(target);
}
/// <summary>
/// Plays all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlay(this AudioMixer target)
{
return DOTween.Play(target);
}
/// <summary>
/// Plays backwards all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayBackwards(this AudioMixer target)
{
return DOTween.PlayBackwards(target);
}
/// <summary>
/// Plays forward all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayForward(this AudioMixer target)
{
return DOTween.PlayForward(target);
}
/// <summary>
/// Restarts all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens restarted.
/// </summary>
public static int DORestart(this AudioMixer target)
{
return DOTween.Restart(target);
}
/// <summary>
/// Rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DORewind(this AudioMixer target)
{
return DOTween.Rewind(target);
}
/// <summary>
/// Smoothly rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DOSmoothRewind(this AudioMixer target)
{
return DOTween.SmoothRewind(target);
}
/// <summary>
/// Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
public static int DOTogglePause(this AudioMixer target)
{
return DOTween.TogglePause(target);
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b766d08851589514b97afb23c6f30a70
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,146 @@
using UnityEngine;
#if DOTWEEN_EPO || EPO_DOTWEEN // MODULE_MARKER
using EPOOutline;
using DG.Tweening.Plugins.Options;
using DG.Tweening;
using DG.Tweening.Core;
namespace DG.Tweening
{
public static class DOTweenModuleEPOOutline
{
public static int DOKill(this SerializedPass target, bool complete)
{
return DOTween.Kill(target, complete);
}
public static TweenerCore<float, float, FloatOptions> DOFloat(this SerializedPass target, string propertyName, float endValue, float duration)
{
var tweener = DOTween.To(() => target.GetFloat(propertyName), x => target.SetFloat(propertyName, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SerializedPass target, string propertyName, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SerializedPass target, string propertyName, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<Vector4, Vector4, VectorOptions> DOVector(this SerializedPass target, string propertyName, Vector4 endValue, float duration)
{
var tweener = DOTween.To(() => target.GetVector(propertyName), x => target.SetVector(propertyName, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<float, float, FloatOptions> DOFloat(this SerializedPass target, int propertyId, float endValue, float duration)
{
var tweener = DOTween.To(() => target.GetFloat(propertyId), x => target.SetFloat(propertyId, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SerializedPass target, int propertyId, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SerializedPass target, int propertyId, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<Vector4, Vector4, VectorOptions> DOVector(this SerializedPass target, int propertyId, Vector4 endValue, float duration)
{
var tweener = DOTween.To(() => target.GetVector(propertyId), x => target.SetVector(propertyId, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static int DOKill(this Outlinable.OutlineProperties target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
public static int DOKill(this Outliner target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
/// <summary>
/// Controls the alpha (transparency) of the outline
/// </summary>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Outlinable.OutlineProperties target, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.Color, x => target.Color = x, endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the color of the outline
/// </summary>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Outlinable.OutlineProperties target, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.Color, x => target.Color = x, endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of blur applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DOBlurShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of blur applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DOBlurShift(this Outliner target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of dilation applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DODilateShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of dilation applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DODilateShift(this Outliner target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e944529dcaee98f4e9498d80e541d93e
timeCreated: 1602593330
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,216 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if !DOTWEEN_NOPHYSICS // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics
{
#region Shortcuts
#region Rigidbody
/// <summary>Tweens a Rigidbody's position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMove(this Rigidbody target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's X position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveX(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Y position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveY(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Z position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveZ(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's rotation to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="mode">Rotation mode</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DORotate(this Rigidbody target, Vector3 endValue, float duration, RotateMode mode = RotateMode.Fast)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
t.plugOptions.rotateMode = mode;
return t;
}
/// <summary>Tweens a Rigidbody's rotation so that it will look towards the given position.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="towards">The position to look at</param><param name="duration">The duration of the tween</param>
/// <param name="axisConstraint">Eventual axis constraint for the rotation</param>
/// <param name="up">The vector that defines in which direction up is (default: Vector3.up)</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DOLookAt(this Rigidbody target, Vector3 towards, float duration, AxisConstraint axisConstraint = AxisConstraint.None, Vector3? up = null)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, towards, duration)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetLookAt);
t.plugOptions.axisConstraint = axisConstraint;
t.plugOptions.up = (up == null) ? Vector3.up : (Vector3)up;
return t;
}
#region Special
/// <summary>Tweens a Rigidbody's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody target, Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, jumpPower, 0), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue.x, 0, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue.z), duration)
.SetOptions(AxisConstraint.Z, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
// Used by path editor when creating the actual tween, so it can pass a pre-compiled path
internal static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
internal static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dae9aa560b4242648a3affa2bfabc365
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,193 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if !DOTWEEN_NOPHYSICS2D // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics2D
{
#region Shortcuts
#region Rigidbody2D Shortcuts
/// <summary>Tweens a Rigidbody2D's position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMove(this Rigidbody2D target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's X position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveX(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's Y position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveY(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's rotation to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DORotate(this Rigidbody2D target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
return t;
}
#region Special
/// <summary>Tweens a Rigidbody2D's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>IMPORTANT: a rigidbody2D can't be animated in a jump arc using MovePosition, so the tween will directly set the position</para></summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody2D target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, x => target.position = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, x => target.position = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody2D's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody2D's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
// Used by path editor when creating the actual tween, so it can pass a pre-compiled path
internal static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
return t;
}
internal static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 230fe34542e175245ba74b4659dae700
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,93 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if !DOTWEEN_NOSPRITES // MODULE_MARKER
using System;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleSprite
{
#region Shortcuts
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SpriteRenderer target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Material's alpha color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SpriteRenderer target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a SpriteRenderer's color using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this SpriteRenderer target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region Blendables
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the SpriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this SpriteRenderer target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 188918ab119d93148aa0de59ccf5286b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,662 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if !DOTWEEN_NOUI // MODULE_MARKER
using System;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Options;
using Outline = UnityEngine.UI.Outline;
using Text = UnityEngine.UI.Text;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleUI
{
#region Shortcuts
#region CanvasGroup
/// <summary>Tweens a CanvasGroup's alpha color to the given value.
/// Also stores the canvasGroup as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this CanvasGroup target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.alpha, x => target.alpha = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Graphic
/// <summary>Tweens an Graphic's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Graphic target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Graphic's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Graphic target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Image
/// <summary>Tweens an Image's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Image target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Image target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's fillAmount to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFillAmount(this Image target, float endValue, float duration)
{
if (endValue > 1) endValue = 1;
else if (endValue < 0) endValue = 0;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.fillAmount, x => target.fillAmount = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's colors using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Image target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region LayoutElement
/// <summary>Tweens an LayoutElement's flexibleWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOFlexibleSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.flexibleWidth, target.flexibleHeight), x => {
target.flexibleWidth = x.x;
target.flexibleHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's minWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMinSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.minWidth, target.minHeight), x => {
target.minWidth = x.x;
target.minHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's preferredWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPreferredSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.preferredWidth, target.preferredHeight), x => {
target.preferredWidth = x.x;
target.preferredHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Outline
/// <summary>Tweens a Outline's effectColor to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Outline target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectColor alpha to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Outline target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectDistance to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOScale(this Outline target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.effectDistance, x => target.effectDistance = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region RectTransform
/// <summary>Tweens a RectTransform's anchoredPosition to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPos(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3D(this RectTransform target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Z to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DZ(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMax to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMax(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMax, x => target.anchorMax = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMin to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMin(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMin, x => target.anchorMin = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivot(this RectTransform target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotX(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotY(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's sizeDelta to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOSizeDelta(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.sizeDelta, x => target.sizeDelta = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Punches a RectTransform's anchoredPosition towards the given direction and then back to the starting one
/// as if it was connected to the starting position via an elastic.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="punch">The direction and strength of the punch (added to the RectTransform's current position)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="vibrato">Indicates how much will the punch vibrate</param>
/// <param name="elasticity">Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards.
/// 1 creates a full oscillation between the punch direction and the opposite direction,
/// while 0 oscillates only between the punch and the start position</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOPunchAnchorPos(this RectTransform target, Vector2 punch, float duration, int vibrato = 10, float elasticity = 1, bool snapping = false)
{
return DOTween.Punch(() => target.anchoredPosition, x => target.anchoredPosition = x, punch, duration, vibrato, elasticity)
.SetTarget(target).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, float strength = 100, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, true, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength on each axis</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, Vector2 strength, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
#region Special
/// <summary>Tweens a RectTransform's anchoredPosition to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJumpAnchorPos(this RectTransform target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
// Separate Y Tween so we can elaborate elapsedPercentage on that insted of on the Sequence
// (in case users add a delay or other elements to the Sequence)
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(()=> startPosY = target.anchoredPosition.y);
s.Append(DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
s.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector2 pos = target.anchoredPosition;
pos.y += DOVirtual.EasedValue(0, offsetY, s.ElapsedDirectionalPercentage(), Ease.OutQuad);
target.anchoredPosition = pos;
});
return s;
}
#endregion
#endregion
#region ScrollRect
/// <summary>Tweens a ScrollRect's horizontal/verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DONormalizedPos(this ScrollRect target, Vector2 endValue, float duration, bool snapping = false)
{
return DOTween.To(() => new Vector2(target.horizontalNormalizedPosition, target.verticalNormalizedPosition),
x => {
target.horizontalNormalizedPosition = x.x;
target.verticalNormalizedPosition = x.y;
}, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's horizontalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOHorizontalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.horizontalNormalizedPosition, x => target.horizontalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOVerticalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.verticalNormalizedPosition, x => target.verticalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
#endregion
#region Slider
/// <summary>Tweens a Slider's value to the given value.
/// Also stores the Slider as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<float, float, FloatOptions> DOValue(this Slider target, float endValue, float duration, bool snapping = false)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.value, x => target.value = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Text
/// <summary>Tweens a Text's color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Text target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>
/// Tweens a Text's text from one integer to another, with options for thousands separators
/// </summary>
/// <param name="fromValue">The value to start from</param>
/// <param name="endValue">The end value to reach</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="addThousandsSeparator">If TRUE (default) also adds thousands separators</param>
/// <param name="culture">The <see cref="CultureInfo"/> to use (InvariantCulture if NULL)</param>
public static TweenerCore<int, int, NoOptions> DOCounter(
this Text target, int fromValue, int endValue, float duration, bool addThousandsSeparator = true, CultureInfo culture = null
){
int v = fromValue;
CultureInfo cInfo = !addThousandsSeparator ? null : culture ?? CultureInfo.InvariantCulture;
TweenerCore<int, int, NoOptions> t = DOTween.To(() => v, x => {
v = x;
target.text = addThousandsSeparator
? v.ToString("N0", cInfo)
: v.ToString();
}, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's alpha color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Text target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's text to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end string to tween to</param><param name="duration">The duration of the tween</param>
/// <param name="richTextEnabled">If TRUE (default), rich text will be interpreted correctly while animated,
/// otherwise all tags will be considered as normal text</param>
/// <param name="scrambleMode">The type of scramble mode to use, if any</param>
/// <param name="scrambleChars">A string containing the characters to use for scrambling.
/// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters.
/// Leave it to NULL (default) to use default ones</param>
public static TweenerCore<string, string, StringOptions> DOText(this Text target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null)
{
if (endValue == null) {
if (Debugger.logPriority > 0) Debugger.LogWarning("You can't pass a NULL string to DOText: an empty string will be used instead to avoid errors");
endValue = "";
}
TweenerCore<string, string, StringOptions> t = DOTween.To(() => target.text, x => target.text = x, endValue, duration);
t.SetOptions(richTextEnabled, scrambleMode, scrambleChars)
.SetTarget(target);
return t;
}
#endregion
#region Blendables
#region Graphic
/// <summary>Tweens a Graphic's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Graphic as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Graphic target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Image
/// <summary>Tweens a Image's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Image target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Text
/// <summary>Tweens a Text's color BY the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Text target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#region Shapes
/// <summary>Tweens a RectTransform's anchoredPosition so that it draws a circle around the given center.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations.<para/>
/// IMPORTANT: SetFrom(value) requires a <see cref="Vector2"/> instead of a float, where the X property represents the "from degrees value"</summary>
/// <param name="center">Circle-center/pivot around which to rotate (in UI anchoredPosition coordinates)</param>
/// <param name="endValueDegrees">The end value degrees to reach (to rotate counter-clockwise pass a negative value)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="relativeCenter">If TRUE the <see cref="center"/> coordinates will be considered as relative to the target's current anchoredPosition</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, CircleOptions> DOShapeCircle(
this RectTransform target, Vector2 center, float endValueDegrees, float duration, bool relativeCenter = false, bool snapping = false
)
{
TweenerCore<Vector2, Vector2, CircleOptions> t = DOTween.To(
CirclePlugin.Get(), () => target.anchoredPosition, x => target.anchoredPosition = x, center, duration
);
t.SetOptions(endValueDegrees, relativeCenter, snapping).SetTarget(target);
return t;
}
#endregion
#endregion
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class Utils
{
/// <summary>
/// Converts the anchoredPosition of the first RectTransform to the second RectTransform,
/// taking into consideration offset, anchors and pivot, and returns the new anchoredPosition
/// </summary>
public static Vector2 SwitchToRectTransform(RectTransform from, RectTransform to)
{
Vector2 localPoint;
Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * 0.5f + from.rect.xMin, from.rect.height * 0.5f + from.rect.yMin);
Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position);
screenP += fromPivotDerivedOffset;
RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint);
Vector2 pivotDerivedOffset = new Vector2(to.rect.width * 0.5f + to.rect.xMin, to.rect.height * 0.5f + to.rect.yMin);
return to.anchoredPosition + localPoint - pivotDerivedOffset;
}
}
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a060394c03331a64392db53a10e7f2d1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,161 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2026/01/08
#if DOTWEEN_UITOOLKIT && UNITY_2021_3_OR_NEWER // MODULE_MARKER
using UnityEngine;
using UnityEngine.UIElements;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleUIToolkit
{
#region Shortcuts
#region VisualElement
/// <summary>Tweens a VisualElement's position (via style.translate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMove(this VisualElement target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t
= DOTween.To(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's position (via style.translate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMove(this VisualElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t
= DOTween.To(() => (Vector2)target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, 0), endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's X position (via style.translate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveX(this VisualElement target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t
= DOTween.To(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's Y position (via style.translate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveY(this VisualElement target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t
= DOTween.To(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's Z position (via style.translate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveZ(this VisualElement target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t
= DOTween.To(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's scale (via style.scale) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOScale(this VisualElement target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t
= DOTween.To(() => (Vector2)target.resolvedStyle.scale.value, x => target.style.scale = new Scale(x), endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's scale (via style.scale) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOScale(this VisualElement target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t
= DOTween.To(() => (Vector2)target.resolvedStyle.scale.value, x => target.style.scale = new Scale(x), new Vector2(endValue, endValue), duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a VisualElement's rotation (via style.rotate) to the given value.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DORotate(this VisualElement target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t
= DOTween.To(() => target.resolvedStyle.rotate.angle.value, x => target.style.rotate = new Rotate(x), endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Punches a VisualElement's position towards the given direction and then back to the starting one
/// as if it was connected to the starting position via an elastic.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="punch">The direction and strength of the punch (added to the VisualElement's current position)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="vibrato">Indicates how much will the punch vibrate</param>
/// <param name="elasticity">Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards.
/// 1 creates a full oscillation between the punch direction and the opposite direction,
/// while 0 oscillates only between the punch and the start position</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOPunch(this VisualElement target, Vector3 punch, float duration, int vibrato = 10, float elasticity = 1, bool snapping = false)
{
return DOTween.Punch(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), punch, duration, vibrato, elasticity)
.SetTarget(target).SetOptions(snapping);
}
/// <summary>Shakes a VisualElement's position with the given values.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShake(this VisualElement target, float duration, float strength = 100, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), duration, strength, vibrato, randomness, true, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
/// <summary>Shakes a VisualElement's position with the given values.
/// Also stores the VisualElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength on each axis</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShake(this VisualElement target, float duration, Vector2 strength, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.resolvedStyle.translate, x => target.style.translate = new Translate(x.x, x.y, x.z), duration, strength, vibrato, randomness, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c0a6d2683fb84e4193f2aa968264881
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,389 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
using System;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
//#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0)
//using Task = System.Threading.Tasks.Task;
//#endif
#pragma warning disable 1591
namespace DG.Tweening
{
/// <summary>
/// Shortcuts/functions that are not strictly related to specific Modules
/// but are available only on some Unity versions
/// </summary>
public static class DOTweenModuleUnityVersion
{
#region Material
/// <summary>Tweens a Material's color using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Material target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
/// <summary>Tweens a Material's named color property using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param>
/// <param name="property">The name of the material property to tween (like _Tint or _SpecColor)</param>
/// <param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Material target, Gradient gradient, string property, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.SetColor(property, c.color);
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, property, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region CustomYieldInstructions
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or complete.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForCompletion(true);</code>
/// </summary>
public static CustomYieldInstruction WaitForCompletion(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForCompletion(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or rewinded.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForRewind();</code>
/// </summary>
public static CustomYieldInstruction WaitForRewind(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForRewind(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForKill();</code>
/// </summary>
public static CustomYieldInstruction WaitForKill(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForKill(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or has gone through the given amount of loops.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForElapsedLoops(2);</code>
/// </summary>
/// <param name="elapsedLoops">Elapsed loops to wait for</param>
public static CustomYieldInstruction WaitForElapsedLoops(this Tween t, int elapsedLoops, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForElapsedLoops(t, elapsedLoops);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed
/// or has reached the given time position (loops included, delays excluded).
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForPosition(2.5f);</code>
/// </summary>
/// <param name="position">Position (loops included, delays excluded) to wait for</param>
public static CustomYieldInstruction WaitForPosition(this Tween t, float position, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForPosition(t, position);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or started
/// (meaning when the tween is set in a playing state the first time, after any eventual delay).
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForStart();</code>
/// </summary>
public static CustomYieldInstruction WaitForStart(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForStart(t);
}
#endregion
#if UNITY_2018_1_OR_NEWER
#region Unity 2018.1 or Newer
#region Material
/// <summary>Tweens a Material's named texture offset property with the given ID to the given value.
/// Also stores the material as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
/// <param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOOffset(this Material target, Vector2 endValue, int propertyID, float duration)
{
if (!target.HasProperty(propertyID)) {
if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
return null;
}
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureOffset(propertyID), x => target.SetTextureOffset(propertyID, x), endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Material's named texture scale property with the given ID to the given value.
/// Also stores the material as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
/// <param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOTiling(this Material target, Vector2 endValue, int propertyID, float duration)
{
if (!target.HasProperty(propertyID)) {
if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
return null;
}
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureScale(propertyID), x => target.SetTextureScale(propertyID, x), endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region .NET 4.6 or Newer
#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0)
#region Async Instructions
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or complete.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.WaitForCompletion();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForCompletion(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && !t.IsComplete()) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or rewinded.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForRewind();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForRewind(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0)) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForKill();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForKill(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or has gone through the given amount of loops.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForElapsedLoops();</code>
/// </summary>
/// <param name="elapsedLoops">Elapsed loops to wait for</param>
public static async System.Threading.Tasks.Task AsyncWaitForElapsedLoops(this Tween t, int elapsedLoops)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && t.CompletedLoops() < elapsedLoops) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or started
/// (meaning when the tween is set in a playing state the first time, after any eventual delay).
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForPosition();</code>
/// </summary>
/// <param name="position">Position (loops included, delays excluded) to wait for</param>
public static async System.Threading.Tasks.Task AsyncWaitForPosition(this Tween t, float position)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && t.position * (t.CompletedLoops() + 1) < position) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForKill();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForStart(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && !t.playedOnce) await System.Threading.Tasks.Task.Yield();
}
#endregion
#endif
#endregion
#endregion
#endif
}
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ CLASSES █████████████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class DOTweenCYInstruction
{
public class WaitForCompletion : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && !t.IsComplete();
}}
readonly Tween t;
public WaitForCompletion(Tween tween)
{
t = tween;
}
}
public class WaitForRewind : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0);
}}
readonly Tween t;
public WaitForRewind(Tween tween)
{
t = tween;
}
}
public class WaitForKill : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active;
}}
readonly Tween t;
public WaitForKill(Tween tween)
{
t = tween;
}
}
public class WaitForElapsedLoops : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && t.CompletedLoops() < elapsedLoops;
}}
readonly Tween t;
readonly int elapsedLoops;
public WaitForElapsedLoops(Tween tween, int elapsedLoops)
{
t = tween;
this.elapsedLoops = elapsedLoops;
}
}
public class WaitForPosition : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && t.position * (t.CompletedLoops() + 1) < position;
}}
readonly Tween t;
readonly float position;
public WaitForPosition(Tween tween, float position)
{
t = tween;
this.position = position;
}
}
public class WaitForStart : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && !t.playedOnce;
}}
readonly Tween t;
public WaitForStart(Tween tween)
{
t = tween;
}
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 63c02322328255542995bd02b47b0457
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,167 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
using System;
using System.Reflection;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
/// <summary>
/// Utility functions that deal with available Modules and rewrite them.
/// Modules defines:
/// - DOTAUDIO
/// - DOTPHYSICS
/// - DOTPHYSICS2D
/// - DOTSPRITE
/// - DOTUI
/// Extra defines set and used for implementation of external assets:
/// - DOTWEEN_TMP ► TextMesh Pro
/// - DOTWEEN_TK2D ► 2D Toolkit
/// </summary>
public static class DOTweenModuleUtils
{
static bool _initialized;
#region Reflection
/// <summary>
/// Called via Reflection by DOTweenComponent on Awake
/// </summary>
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static void Init()
{
if (_initialized) return;
_initialized = true;
DOTweenExternalCommand.SetOrientationOnPath += Physics.SetOrientationOnPath;
#if UNITY_EDITOR
#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1
UnityEditor.EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
#else
UnityEditor.EditorApplication.playModeStateChanged += PlaymodeStateChanged;
#endif
#endif
}
#if UNITY_2018_1_OR_NEWER
#pragma warning disable
[UnityEngine.Scripting.Preserve]
// Just used to preserve methods when building, never called
static void Preserver()
{
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
MethodInfo mi = typeof(MonoBehaviour).GetMethod("Stub");
}
#pragma warning restore
#endif
#endregion
#if UNITY_EDITOR
// Fires OnApplicationPause in DOTweenComponent even when Editor is paused (otherwise it's only fired at runtime)
#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1
static void PlaymodeStateChanged()
#else
static void PlaymodeStateChanged(UnityEditor.PlayModeStateChange state)
#endif
{
if (DOTween.instance == null) return;
DOTween.instance.OnApplicationPause(UnityEditor.EditorApplication.isPaused);
}
#endif
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class Physics
{
// Called via DOTweenExternalCommand callback
public static void SetOrientationOnPath(PathOptions options, Tween t, Quaternion newRot, Transform trans)
{
#if !DOTWEEN_NOPHYSICS // PHYSICS_MARKER
if (options.isRigidbody) ((Rigidbody)t.target).rotation = newRot;
else trans.rotation = newRot;
#else
trans.rotation = newRot;
#endif
}
// Returns FALSE if the DOTween's Physics2D Module is disabled, or if there's no Rigidbody2D attached
public static bool HasRigidbody2D(Component target)
{
#if !DOTWEEN_NOPHYSICS2D // PHYSICS2D_MARKER
return target.GetComponent<Rigidbody2D>() != null;
#else
return false;
#endif
}
#region Called via Reflection
// Called via Reflection by DOTweenPathInspector
// Returns FALSE if the DOTween's Physics Module is disabled, or if there's no rigidbody attached
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static bool HasRigidbody(Component target)
{
#if !DOTWEEN_NOPHYSICS // PHYSICS_MARKER
return target.GetComponent<Rigidbody>() != null;
#else
return false;
#endif
}
// Called via Reflection by DOTweenPath
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static TweenerCore<Vector3, Path, PathOptions> CreateDOTweenPathTween(
MonoBehaviour target, bool tweenRigidbody, bool isLocal, Path path, float duration, PathMode pathMode
){
TweenerCore<Vector3, Path, PathOptions> t = null;
bool rBodyFoundAndTweened = false;
#if !DOTWEEN_NOPHYSICS // PHYSICS_MARKER
if (tweenRigidbody) {
Rigidbody rBody = target.GetComponent<Rigidbody>();
if (rBody != null) {
rBodyFoundAndTweened = true;
t = isLocal
? rBody.DOLocalPath(path, duration, pathMode)
: rBody.DOPath(path, duration, pathMode);
}
}
#endif
#if !DOTWEEN_NOPHYSICS2D // PHYSICS2D_MARKER
if (!rBodyFoundAndTweened && tweenRigidbody) {
Rigidbody2D rBody2D = target.GetComponent<Rigidbody2D>();
if (rBody2D != null) {
rBodyFoundAndTweened = true;
t = isLocal
? rBody2D.DOLocalPath(path, duration, pathMode)
: rBody2D.DOPath(path, duration, pathMode);
}
}
#endif
if (!rBodyFoundAndTweened) {
t = isLocal
? target.transform.DOLocalPath(path, duration, pathMode)
: target.transform.DOPath(path, duration, pathMode);
}
return t;
}
#endregion
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7bcaf917d9cf5b84090421a5a2abe42e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0450fce0e45b5004c9f535129c35e6cb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
public class ConstEventString
{
public const string SyncGameData_Rotate = "SyncGameData_Rotate";
public const string SyncGameData_FireBullet = "SyncGameData_FireBullet";
// SyncGameData_CreateFish 已废弃:鱼创建改由服务端 OnFishSpawn 事件下发
public const string SyncGameData_ChangeTargetMonster = "SyncGameData_ChangeTargetMonster";
public const string SyncGameData_RendromDieFish = "SyncGameData_RenderDieFish";
public const string SyncGameData_TurretState = "SyncGameData_TurretState";
public const string SyncGameData_ChangeTurret = "SyncGameData_ChangeTurret";
public const string SyncGameData_FreezeFish = "SyncGameData_FreezeFish";
public const string SyncGameData_ChangeCannonMultiple = "SyncGameData_ChangeCannonMultiple";
public const string SyncGameData_ChangeWing = "SyncGameData_ChangeWing";
/// <summary>战神切换帧同步(changeZhanShen):其他玩家装备/卸下战神,对应座位加载/清除战神模型</summary>
public const string SyncGameData_ChangeZhanShen = "SyncGameData_ChangeZhanShen";
/// <summary>表情包帧同步(biaoQing):某玩家发送表情(spine动画/文字),对应座位显示表情</summary>
public const string SyncGameData_BiaoQing = "SyncGameData_BiaoQing";
public const string SyncGameData_BotFireAngle = "SyncGameData_BotFireAngle";
// SyncGameData_RequestSyncFish 已废弃:鱼同步改由服务端 OnFishSpawn(type=sync) 下发
/// <summary>爆奖结束帧同步(baoJiangEnd):某玩家爆奖流程完成,其他客户端显示最终 BJEndUI 并加分</summary>
public const string BaoJiangEnd = "BaoJiangEnd";
/// <summary>钻头蟹/激光蟹释放帧同步(zuanTouRelease):击杀者点击(或超时)发射,所有客户端(含击杀者回广播)统一时刻发射钻头/激光</summary>
public const string SyncGameData_ZuanTouRelease = "SyncGameData_ZuanTouRelease";
/// <summary>加金币帧同步(addGold):刮刮卡等 HTTP 途径获得金币后广播,各客户端给对应座位加金币并刷新显示</summary>
public const string SyncGameData_AddGold = "SyncGameData_AddGold";
// ================================================================
// 服务端 → 客户端事件 (新协议)
// ================================================================
/// <summary>服务端出鱼事件(破坏性替代 createFish 帧同步)</summary>
public const string OnFishSpawn = "OnFishSpawn";
/// <summary>鱼列表刷新</summary>
public const string OnFishList = "OnFishList";
/// <summary>冰冻道具生效(40003),鱼存活时间延长 15 秒,客户端写死 15s 倒计时</summary>
public const string FishFrozen = "FishFrozen";
/// <summary>玩家挂机通知</summary>
public const string PlayerAfkNotice = "PlayerAfkNotice";
/// <summary>玩家取消挂机通知</summary>
public const string PlayerCancelAfkNotice = "PlayerCancelAfkNotice";
/// <summary>玩家信息同步(GetPlayerInfo 的新响应,含完整玩家数据)</summary>
public const string OnPlayerInfo = "OnPlayerInfo";
/// <summary>召唤卡召唤通知:某玩家使用召唤卡,服务端已创建召唤鱼(实际鱼由 OnFishSpawn 下发)</summary>
public const string SummonCardFishNotice = "SummonCardFishNotice";
/// <summary>全局击杀公告(真人击杀/机器人模拟)</summary>
public const string KillNotice = "KillNotice";
/// <summary>机器人退出房间</summary>
public const string BotLeaveRoomNotice = "BotLeaveRoomNotice";
/// <summary>房主断线,其他玩家可接受机器人控制权</summary>
public const string HostDisconnect = "HostDisconnect";
/// <summary>座位变更</summary>
public const string OnSeatChange = "OnSeatChange";
/// <summary>房主控制权移交</summary>
public const string ChangeControllerUser = "ChangeControllerUser";
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a12b4d76c42f8d49b6af72e52653bb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,89 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public interface IEventInfo{
}
public class EventInfo<T>:IEventInfo
{
public UnityAction<T> actions;
public EventInfo(UnityAction<T> action)
{
actions += action;
}
}
public class EventInfo : IEventInfo
{
public UnityAction actions;
public EventInfo(UnityAction action)
{
actions += action;
}
}
public class EventCenter : Singleton<EventCenter>
{
private Dictionary<string, IEventInfo> eventDic
= new Dictionary<string, IEventInfo>();
public void AddEventListener<T>(string name,UnityAction<T> action)
{
if(eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo<T>).actions += action;
}
else
{
eventDic.Add(name, new EventInfo<T>(action));
}
}
public void AddEventListener(string name, UnityAction action)
{
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo).actions += action;
}
else
{
eventDic.Add(name, new EventInfo(action));
}
}
public void EventTrigger<T>(string name,T info)
{
if(eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo<T>).actions?.Invoke(info);
}
}
public void EventTrigger(string name)
{
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo).actions?.Invoke();
}
}
public void RemoveEventListener<T>(string name, UnityAction<T> action)
{
if (eventDic.ContainsKey(name))
{
//移除这个委托
(eventDic[name] as EventInfo<T>).actions -= action;
}
}
public void RemoveEventListener(string name, UnityAction action)
{
if (eventDic.ContainsKey(name))
{
//移除这个委托
(eventDic[name] as EventInfo).actions -= action;
}
}
public void Clear()
{
eventDic.Clear();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae1cccb3b95b50f489c0aa9af1b41cb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3c2f6fe8649ee1d4a92f5a5ab95d9f4a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+84
View File
@@ -0,0 +1,84 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputMgr : Singleton<InputMgr>
{
private bool isStart = false;
public InputMgr()
{
MonoMgr.Instance.AddUpdateListener(MyUpdate);
}
public void StartOrEndCheck(bool isOpen)
{
isStart = isOpen;
}
private void MyUpdate()
{
if (!isStart)
return;
CheckKeyCode(KeyCode.J);
CheckKeyCode(KeyCode.K);
}
private void CheckKeyCode(KeyCode key)
{
if(Input.GetKeyDown(key))
{
EventCenter.Instance.EventTrigger("KeyisDown", key);
}
if (Input.GetKeyUp(key))
{
EventCenter.Instance.EventTrigger("KeyisUp", key);
}
}
}
#region 用法
//public class Inputtest : MonoBehaviour
//{
// void Start()
// {
// //开启输入检测
// InputMgr.GetInstance().StartOrEndCheck(true);
// //添加事件监听
// EventCenter.GetInstance().AddEventListener<KeyCode>("KeyisDown", CheckInputDown);
// EventCenter.GetInstance().AddEventListener<KeyCode>("KeyisUp", CheckInputUp);
// }
// private void CheckInputDown(KeyCode obj)
// {
// switch (obj)
// {
// case KeyCode.W:
// Debug.Log("前进");
// break;
// case KeyCode.A:
// break;
// case KeyCode.S:
// break;
// case KeyCode.D:
// break;
// }
// }
// private void CheckInputUp(KeyCode obj)
// {
// switch (obj)
// {
// case KeyCode.W:
// Debug.Log("不再前进");
// break;
// case KeyCode.A:
// break;
// case KeyCode.S:
// break;
// case KeyCode.D:
// break;
// }
// }
// private void OnDestroy()
// {
// EventCenter.GetInstance().RemoveEventListener<KeyCode>("KeyisDown", CheckInputDown);
// EventCenter.GetInstance().RemoveEventListener<KeyCode>("KeyisUp", CheckInputUp);
// }
//}
#endregion
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1e2766e5e0166f242b79517926d95597
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0d41394e5140f494fbf59c37a666ffbe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+80
View File
@@ -0,0 +1,80 @@
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;
namespace Douyin.LiveOpenSDK
{
public static class LogManager
{
private static string logPath = Path.Combine(Application.persistentDataPath, "GameLogs");
private static int maxLogFiles = 7;
private static LogLevel currentLogLevel = LogLevel.Verbose;
public enum LogLevel
{
Error = 0,
Warning = 1,
Info = 2,
Verbose = 3
}
[RuntimeInitializeOnLoadMethod]
private static void Initialize()
{
if (!Directory.Exists(logPath))
{
Directory.CreateDirectory(logPath);
}
CleanOldLogs();
}
public static void Log(string message, LogLevel level = LogLevel.Info)
{
if (level > currentLogLevel) return;
string logFile = Path.Combine(logPath, $"{DateTime.Now:yyyy-MM-dd}.log");
string logMessage = $"[{DateTime.Now:HH:mm:ss}] [{level}] {message}\n";
try
{
File.AppendAllText(logFile, logMessage);
}
catch (Exception e)
{
Debug.LogError($"Failed to write log: {e.Message}");
}
}
private static void CleanOldLogs()
{
try
{
var files = new DirectoryInfo(logPath).GetFiles("*.log");
if (files.Length > maxLogFiles)
{
Array.Sort(files, (a, b) => b.CreationTime.CompareTo(a.CreationTime));
for (int i = maxLogFiles; i < files.Length; i++)
{
files[i].Delete();
}
}
}
catch (Exception e)
{
Debug.LogError($"Failed to clean logs: {e.Message}");
}
}
public static void SetLogLevel(LogLevel level)
{
currentLogLevel = level;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21abda7a9f0e0fa4b8d7391e62a90bd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 39d079abfb60e4f4b9766473690fdc2f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class MonoController : MonoBehaviour
{
private event UnityAction updateEvent;
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this.gameObject);
}
// Update is called once per frame
void Update()
{
if(updateEvent!=null)
{
updateEvent();
}
}
public void AddUpdateListener(UnityAction func)
{
updateEvent += func;
}
public void RemoveUpdateListener(UnityAction func)
{
updateEvent -= func;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f382d5951cb60254785d2d0c5e1a912e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+37
View File
@@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Internal;
public class MonoMgr : Singleton<MonoMgr>
{
private MonoController controller;
public MonoMgr()
{
GameObject obj = new GameObject("MonoController");
controller = obj.AddComponent<MonoController>();
}
public void AddUpdateListener(UnityAction func)
{
controller.AddUpdateListener(func);
}
public void RemoveUpdateListener(UnityAction func)
{
controller.RemoveUpdateListener(func);
}
public Coroutine StartCoroutine(IEnumerator routine)
{
return controller.StartCoroutine(routine);
}
public Coroutine StartCoroutine(string methodName,[DefaultValue("null")]object value)
{
return controller.StartCoroutine(methodName, value);
}
public Coroutine StartCoroutine(string methodName)
{
return controller.StartCoroutine(methodName);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c28f170c2c1ab9e42a71fb2131d920e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c7deb4e7874fad7478108786b33d426e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+115
View File
@@ -0,0 +1,115 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class MusicMgr : Singleton<MusicMgr>
{
private AudioSource bkMusic = null;
private float bkVaule = 1;
private float soundVaule = 1;
private GameObject soundObj = null;
private List<AudioSource> soundList = new List<AudioSource>();
public MusicMgr()
{
MonoMgr.Instance.AddUpdateListener(MyUpdate);
}
private void MyUpdate()
{
for(int i=soundList.Count-1;i>=0;i--)
{
if(soundList[i].isPlaying)
{
Object.Destroy(soundList[i]);
soundList.RemoveAt(i);
}
}
}
public void PlayBKMusic(string name)
{
if(bkMusic==null)
{
GameObject obj = new GameObject("BKMusic");
bkMusic = obj.AddComponent<AudioSource>();
}
ResMgr.Instance.LoadAsync<AudioClip>("Music/BackgrondMusic/" + name,
(clip) =>
{
bkMusic.clip = clip;
bkMusic.loop = true;
bkMusic.volume = bkVaule;
bkMusic.Play();
});
}
public void ChangeBKValue(float v)
{
bkVaule = v;
if(bkMusic=null)
{
return;
}
bkMusic.volume = bkVaule;
}
public void PauseBKMusic()
{
if (bkMusic = null)
{
return;
}
bkMusic.Pause();
}
public void StopBKMusic()
{
if (bkMusic = null)
{
return;
}
bkMusic.Stop();
}
public void PlaySound(string name,bool isLoop,UnityAction<AudioSource> callback=null)
{
if(soundObj==null)
{
soundObj = new GameObject();
soundObj.name = "Sounds";
}
AudioSource source = soundObj.AddComponent<AudioSource>();
ResMgr.Instance.LoadAsync<AudioClip>("Music/Sounds/" + name,
(clip) =>
{
source.clip = clip;
source.loop = isLoop;
source.volume = soundVaule;
source.Play();
soundList.Add(source);
if (callback != null)
{
callback(source);
}
});
}
public void ChangeSoundValue(float value)
{
soundVaule = value;
for(int i=0;i<soundList.Count;++i)
{
soundList[i].volume = value;
}
}
public void StopSound(AudioSource source)
{
if(soundList.Contains(source))
{
soundList.Remove(source);
source.Stop();
Object.Destroy(source);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ea7711fd37c7d449bcd48c4c9bf1dda
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3cb18cec2edfeb049b9c7ced2fbc6b10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+202
View File
@@ -0,0 +1,202 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 子弹专用对象池 — 按 prefab.GetInstanceID() 分桶,与鱼的 Pool 完全隔离
/// 用法:
/// var go = BulletPool.Instance.Get(prefab, pos, rot, parent);
/// BulletPool.Instance.Return(go); // 代替 Destroy(单个回收)
/// BulletPool.Instance.ClearAll(); // 换炮台/切场景调用:销毁所有活跃子弹 + 清池
/// prefabID 直接用 prefab.GetInstanceID()(Unity 内部 hash,全局唯一)
/// 活跃子弹→prefabID 的映射用 Dictionary<instanceID, prefabID> 存储,不挂组件不改 name
/// </summary>
public class BulletPool : Singleton<BulletPool>
{
// prefab.GetInstanceID() → 该 prefab 的池
private Dictionary<int, BulletPoolData> dic = new Dictionary<int, BulletPoolData>();
// 活跃子弹映射:子弹GameObject → prefab.GetInstanceID()
// key 用 GameObject 本身(Unity 重载了 GetHashCode/Equals,按实例区分)
// value 是 prefabID,回收时凭此找到对应池
private Dictionary<GameObject, int> activeMap = new Dictionary<GameObject, int>();
// 每个池子的最大缓存数(超出直接 Destroy,防止内存膨胀)
private const int MaxCachePerPrefab = 200;
// 池子根节点(隐藏在场景里)
private GameObject poolRoot;
/// <summary>从池中取一个子弹(池空则 Instantiate)</summary>
public GameObject Get(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent)
{
if (prefab == null) return null;
int prefabID = prefab.GetInstanceID();
GameObject obj = null;
if (dic.TryGetValue(prefabID, out var data))
{
// ⭐ 循环跳过已销毁的坏对象(ClearAll 用 Destroy 延迟销毁,时序竞争中可能残留)
while (data.poolList.Count > 0)
{
obj = data.GetObj();
if (obj != null) break; // Unity 重载 ==,能识别已 Destroy 的假 null
obj = null; // 坏对象丢弃,继续取下一个
}
}
if (obj != null)
{
// ⭐ 必须先 SetParent 再设 position:模仿 Instantiate(prefab, pos, rot, parent)
obj.transform.SetParent(parent, false);
obj.transform.position = position;
obj.transform.rotation = rotation;
obj.SetActive(true);
}
else
{
obj = GameObject.Instantiate(prefab, position, rotation, parent);
obj.SetActive(true);
}
// 记录映射:子弹实例 → prefabID(回收时凭此找到对应池)
activeMap[obj] = prefabID;
return obj;
}
/// <summary>无 parent 重载</summary>
public GameObject Get(GameObject prefab, Vector3 position, Quaternion rotation)
{
return Get(prefab, position, rotation, null);
}
/// <summary>回收子弹到池(超容量则 Destroy)</summary>
public void Return(GameObject obj)
{
if (obj == null) return;
// 取不到映射 → 非 pool 对象 → 兜底 Destroy
if (!activeMap.TryGetValue(obj, out int prefabID) || prefabID == 0)
{
GameObject.Destroy(obj);
return;
}
activeMap.Remove(obj);
if (!dic.TryGetValue(prefabID, out var data))
dic[prefabID] = data = new BulletPoolData(EnsurePoolRoot().transform, prefabID);
if (data.poolList.Count >= MaxCachePerPrefab)
{
GameObject.Destroy(obj);
return;
}
// 重置子弹状态(若有 BullitMove 组件)
var bm = obj.GetComponent<BullitMove>();
if (bm != null) bm.ResetState();
data.PushObj(obj);
}
/// <summary>预加载 N 个某 prefab 到池</summary>
public void Preload(GameObject prefab, int count)
{
if (prefab == null || count <= 0) return;
int prefabID = prefab.GetInstanceID();
if (!dic.TryGetValue(prefabID, out var data))
dic[prefabID] = data = new BulletPoolData(EnsurePoolRoot().transform, prefabID);
for (int i = 0; i < count; i++)
{
var obj = GameObject.Instantiate(prefab, EnsurePoolRoot().transform);
// 预加载的对象直接入池,不进 activeMap(它们没被"借出")
data.PushObj(obj);
}
}
/// <summary>销毁所有活跃子弹 + 清空所有池(换炮台/切场景调用)</summary>
public void ClearAll()
{
// 销毁所有借出未归还的子弹
foreach (var kv in activeMap.Keys)
{
if (kv != null) GameObject.Destroy(kv);
}
activeMap.Clear();
// 清空所有池
foreach (var kv in dic.Values)
kv.Clear();
dic.Clear();
if (poolRoot != null)
{
GameObject.Destroy(poolRoot);
poolRoot = null;
}
}
/// <summary>只销毁活跃子弹,保留池缓存(换炮台时调用:清屏但池能复用)</summary>
public void ClearActive()
{
foreach (var kv in activeMap.Keys)
{
if (kv != null) GameObject.Destroy(kv);
}
activeMap.Clear();
// ⭐ 不清 dic,池里的缓存保留,同 prefab 下次能复用
}
private GameObject EnsurePoolRoot()
{
if (poolRoot == null)
{
poolRoot = new GameObject("[BulletPool]");
poolRoot.SetActive(false); // 池根节点隐藏,池内对象跟随隐藏
}
return poolRoot;
}
}
/// <summary>单个 prefab 的子弹池数据</summary>
public class BulletPoolData
{
public Transform fatherObj;
public List<GameObject> poolList;
public BulletPoolData(Transform root, int id)
{
fatherObj = new GameObject("bulletPool_" + id).transform;
fatherObj.SetParent(root, false);
poolList = new List<GameObject>();
}
public void PushObj(GameObject obj)
{
if (obj == null) return;
poolList.Add(obj);
obj.transform.SetParent(fatherObj, false);
obj.SetActive(false);
}
public GameObject GetObj()
{
GameObject obj = poolList[poolList.Count - 1];
poolList.RemoveAt(poolList.Count - 1);
return obj;
}
public void Clear()
{
foreach (var obj in poolList)
{
if (obj != null) GameObject.Destroy(obj);
}
poolList.Clear();
if (fatherObj != null)
GameObject.Destroy(fatherObj.gameObject);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b450d462c4ecd3349b396f1ff2014f40
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+217
View File
@@ -0,0 +1,217 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 特效专用对象池 — 按 prefab.GetInstanceID() 分桶
/// 粒子播放完自动回池(通过 EffectAutoReturn 组件检测)
/// 用法:
/// var go = EffectPool.Instance.Get(prefab, pos, rot, parent);
/// // 无需手动回收,EffectAutoReturn 会在粒子播完后自动回池
/// EffectPool.Instance.ClearAll(); // 切场景时彻底清理
/// </summary>
public class EffectPool : Singleton<EffectPool>
{
// prefab.GetInstanceID() → 该 prefab 的池
private Dictionary<int, BulletPoolData> dic = new Dictionary<int, BulletPoolData>();
// 活跃特效映射:特效GameObject → prefab.GetInstanceID()
private Dictionary<GameObject, int> activeMap = new Dictionary<GameObject, int>();
private const int MaxCachePerPrefab = 100;
private GameObject poolRoot;
/// <summary>从池中取一个特效(池空则 Instantiate),取出后自动播放并在播完时回池</summary>
public GameObject Get(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent)
{
return Get(prefab, position, rotation, parent, autoReturn: true);
}
/// <summary>
/// 从池中取一个特效。
/// autoReturn=true: 粒子特效,EffectAutoReturn 检测粒子播完自动回池
/// autoReturn=false: 动画/UI 驱动特效(如 BJBase/DieEffect_TSY),由动画事件手动调用 Return()
/// </summary>
public GameObject Get(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent, bool autoReturn)
{
return GetCore(prefab, position, rotation, parent, autoReturn);
}
/// <summary>
/// 从池中取一个特效,不设置位置/旋转——位置、大小完全保留预制体里配置好的
/// (爆奖特效用,z 也用预制体自带的,不被生成位置带偏)。
/// </summary>
public GameObject Get(GameObject prefab, Transform parent, bool autoReturn)
{
return GetCore(prefab, null, null, parent, autoReturn);
}
/// <summary>取用核心:position/rotation 传 null 时不设置,保留预制体配置好的变换</summary>
private GameObject GetCore(GameObject prefab, Vector3? position, Quaternion? rotation, Transform parent, bool autoReturn)
{
if (prefab == null) return null;
int prefabID = prefab.GetInstanceID();
GameObject obj = null;
if (dic.TryGetValue(prefabID, out var data))
{
// 循环跳过已销毁的坏对象
while (data.poolList.Count > 0)
{
obj = data.GetObj();
if (obj != null) break;
obj = null;
}
}
if (obj != null)
{
obj.transform.SetParent(parent, false);
// ⭐ 只在传入时才设置位置/旋转;不传则保留预制体配置好的位置和大小
if (position.HasValue) obj.transform.position = position.Value;
if (rotation.HasValue) obj.transform.rotation = rotation.Value;
obj.SetActive(true);
}
else
{
obj = position.HasValue
? GameObject.Instantiate(prefab, position.Value, rotation ?? Quaternion.identity, parent)
: GameObject.Instantiate(prefab, parent);
obj.SetActive(true);
}
activeMap[obj] = prefabID;
if (autoReturn)
{
// 粒子特效:挂上自动回收组件(已挂则复用)
var auto = obj.GetComponent<EffectAutoReturn>();
if (auto == null)
auto = obj.AddComponent<EffectAutoReturn>();
auto.prefabID = prefabID;
auto.Play();
}
// autoReturn=false: 动画/UI 驱动特效,不挂自动回收组件
// 由动画事件(coinEvent/ScoreNumScrollEvent 等)调用 EffectPool.Instance.Return(gameObject) 回池
return obj;
}
/// <summary>回收特效到池(通常由 EffectAutoReturn 自动调用)</summary>
public void Return(GameObject obj)
{
if (obj == null) return;
if (!activeMap.TryGetValue(obj, out int prefabID) || prefabID == 0)
{
GameObject.Destroy(obj);
return;
}
activeMap.Remove(obj);
if (!dic.TryGetValue(prefabID, out var data))
dic[prefabID] = data = new BulletPoolData(EnsurePoolRoot().transform, prefabID);
if (data.poolList.Count >= MaxCachePerPrefab)
{
GameObject.Destroy(obj);
return;
}
data.PushObj(obj);
}
/// <summary>销毁所有活跃特效 + 清空所有池(切场景调用)</summary>
public void ClearAll()
{
foreach (var kv in activeMap.Keys)
{
if (kv != null) GameObject.Destroy(kv);
}
activeMap.Clear();
foreach (var kv in dic.Values)
kv.Clear();
dic.Clear();
if (poolRoot != null)
{
GameObject.Destroy(poolRoot);
poolRoot = null;
}
}
private GameObject EnsurePoolRoot()
{
if (poolRoot == null)
{
poolRoot = new GameObject("[EffectPool]");
poolRoot.SetActive(false);
}
return poolRoot;
}
}
/// <summary>挂在池内特效上,粒子播放完自动回池</summary>
public class EffectAutoReturn : MonoBehaviour
{
[HideInInspector] public int prefabID;
private ParticleSystem[] particles;
private float checkTimer;
private const float MinPlayTime = 0.3f; // 至少播 0.3s 再检测,避免第一帧 IsAlive=false 误判
private const float MaxLifetime = 6f; // ⭐ 兜底:超过 6 秒强制回池,防止 looping 残留导致特效永生
/// <summary>重新播放所有粒子</summary>
public void Play()
{
if (particles == null || particles.Length == 0)
particles = GetComponentsInChildren<ParticleSystem>(true);
checkTimer = 0f;
foreach (var p in particles)
{
if (p != null)
{
// ⭐ 强制关闭 looping:有些预制体子级 ParticleSystem 设了 looping=1,
// 会导致 IsAlive(true) 永远返回 true,特效一直累加直至内存爆满死机
var main = p.main;
main.loop = false;
p.Clear(true);
p.Play(true);
}
}
}
void Update()
{
checkTimer += Time.deltaTime;
if (checkTimer < MinPlayTime) return;
// ⭐ 6 秒兜底:无论是否还存活,超过 6 秒强制回池
if (checkTimer >= MaxLifetime)
{
EffectPool.Instance.Return(gameObject);
return;
}
// 所有粒子都播完 → 回池
if (particles == null || particles.Length == 0)
{
EffectPool.Instance.Return(gameObject);
return;
}
bool anyAlive = false;
foreach (var p in particles)
{
if (p != null && p.IsAlive(true)) { anyAlive = true; break; }
}
if (!anyAlive)
{
EffectPool.Instance.Return(gameObject);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e095098a1433eb4408b49fa20449bcb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+176
View File
@@ -0,0 +1,176 @@
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
public class PoolData
{
public GameObject fatherObj;
public List<GameObject> poolList;
public PoolData(GameObject obj,GameObject poolParent,int id)
{
fatherObj = new GameObject(obj.name);
fatherObj.transform.parent = poolParent.transform;
poolList = new List<GameObject>();
PushObj(obj,id);
}
public void PushObj(GameObject obj,int id)
{
// 先实例化,再隐藏(原代码对 prefab 调 SetActive(false) 无效且语义混乱)
obj = GameObject.Instantiate(obj);
obj.name = id.ToString();
obj.transform.parent = fatherObj.transform;
obj.SetActive(false);
poolList.Add(obj);
}
public void PushObj(GameObject obj)
{
poolList.Add(obj);
obj.transform.parent = fatherObj.transform;
obj.SetActive(false);
}
public GameObject GetObj()
{
GameObject obj;
obj = poolList[0];
poolList.RemoveAt(0);
obj.SetActive(true);
obj.transform.parent = null;
return obj;
}
/// <summary>
/// 清理当前池子,销毁所有对象并释放父节点
/// </summary>
public void Clear()
{
foreach (var obj in poolList)
{
if (obj != null)
GameObject.Destroy(obj);
}
poolList.Clear();
if (fatherObj != null)
GameObject.Destroy(fatherObj);
}
}
public class Pool : Singleton<Pool>
{
public Dictionary<int, PoolData> dic = new Dictionary<int, PoolData>();//生成一个字典
private GameObject poolObj;//Scene窗口中的“pool”总收纳盒
/// <summary>获取/创建池总父节点(初始化和 Return 共用同一个 poolObj)</summary>
public GameObject EnsurePoolRoot()
{
if (poolObj == null)
poolObj = new GameObject("pool");
return poolObj;
}
public GameObject Get(int id, Vector3 position, Quaternion rotation)//返回一个预制体,
{
GameObject obj;
if (dic.ContainsKey(id) && dic[id].poolList.Count > 0)//如果字典里有这个东西,并且它的数量大于0就取出来
{
obj = dic[id].GetObj();
obj.transform.position = position;//实例化时候的参数传过来
obj.transform.rotation = rotation;//同上
}
else
{
GameObject temp = FishResourcesData.GetFishPrefab(id);
//if (rotation == Quaternion.identity)
//{
// rotation = temp.transform.rotation;
//}
obj = Object.Instantiate(temp, position, rotation) as GameObject;//没有就读取一个,不用存入字典
obj.name = id.ToString();
}
return obj;
}
public GameObject Get(int id, Vector3 position, Quaternion rotation, Transform parent )//返回一个预制体,
{
GameObject obj;
if (dic.ContainsKey(id) && dic[id].poolList.Count > 0)//如果字典里有这个东西,并且它的数量大于0就取出来
{
obj = dic[id].GetObj();
// ⭐ 设置位置不带 z 轴:z 用预制体自带的深度,不被生成位置(如 9999,9999,0)擦掉
obj.transform.position = new Vector3(position.x, position.y, obj.transform.position.z);
obj.transform.rotation = rotation;//同上
obj.transform.SetParent(parent);
}
else
{
//GameObject temp = FishResourcesData.GetFishPrefab(id);
//if (rotation == Quaternion.identity)
//{
// rotation = temp.transform.rotation;
//}
var prefab = FishResourcesData.GetFishPrefab(id);
if (prefab == null)
{
Debug.LogError($"[Pool] 找不到鱼 prefab, fishNumber={id}");
return null;
}
// ⭐ 无位置实例化(保留预制体自带的位置/深度),再只覆盖 x/y,z 用预制体自带的
obj = Object.Instantiate(prefab, parent) as GameObject;//没有就读取一个,不用存入字典
obj.transform.rotation = rotation;
obj.transform.position = new Vector3(position.x, position.y, obj.transform.position.z);
obj.SetActive(true);
obj.name = id.ToString();
}
return obj;
}
public GameObject Return(GameObject obj)//隐藏掉
{
if(obj.activeSelf)
{
// ⭐ 统一用 poolObj 作为池总父节点(初始化时也用 poolObj,保证 Clear 能统一销毁)
if(poolObj==null)
{
poolObj = new GameObject("pool");
}
int id =int.Parse( obj.name);
if (dic.ContainsKey(id))//如果找到了这个名字
{
dic[id].PushObj(obj);
}
else
{
//dic.Add(id, new PoolData(obj, poolObj) { });
GameObject.Destroy(obj);
}
}
return obj;
}
//public void Clear()//切换场景时将所有缓存清除
//{
// dic.Clear();
// poolObj = null;
//}
/// <summary>
/// 清理所有池子,销毁对象并释放资源
/// </summary>
public void Clear()
{
// ⭐ 防重入:已经清空过直接返回
if (dic.Count == 0 && poolObj == null) return;
foreach (var kv in dic.Values)
{
if (kv != null) kv.Clear();
}
dic.Clear();
if (poolObj != null)
{
GameObject.Destroy(poolObj);
poolObj = null;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 680ca01afe29bb84481776c727d9886c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 583a80fd7e23470499d70f7440bcb14e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+88
View File
@@ -0,0 +1,88 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.AsyncOperations;
public class ResMgr : Singleton<ResMgr>
{
public T Load<T>(string name)where T:Object
{
T res = Resources.Load<T>(name);
if (res is GameObject)
return Object.Instantiate(res);
else
return res;
}
public T Load<T>(string name,Vector3 position,Quaternion rotation) where T : Object
{
T res = Resources.Load<T>(name);
if (res is GameObject)
return Object.Instantiate(res, position, rotation);
else
return res;
}
public void LoadAsync<T>(string name,UnityAction<T> callback)where T:Object
{
MonoMgr.Instance.StartCoroutine(ReallyLoadAsync(name,callback));
}
private IEnumerator ReallyLoadAsync<T>(string name,UnityAction<T> callback)where T:Object
{
ResourceRequest r = Resources.LoadAsync<T>(name);
yield return r;
if (r.asset is GameObject)
{
callback(Object.Instantiate(r.asset) as T);
}
else
{
callback(r.asset as T);
}
}
#region 异步加载使用方法(得到加载物体并设定位置等)
//需要注意的是,异步加载中,调用异步加载后,物体并没有被加载,需要等n帧才会被加载,所以我们不能直接返回物体,而是在方法中将物体传出去。
//private void Update()
//{
// if (Input.GetMouseButtonDown(1))
// {
// ResMgr.Instance.LoadAsync<GameObject>("cube", DoSome);
// }
//}
//private void DoSome(GameObject obj)
//{
// Debug.Log("调用了回调函数");
//}
////为了方便,我们还可以直接使用Lambda表达式来方便书写
//private void Update()
//{
// if (Input.GetMouseButtonDown(1))
// {
// ResMgr.GetInstance().LoadAsync<GameObject>("cube", (obj) =>
// {
// Debug.Log("调用了回调函数");
// });
// }
//}
#endregion
//Addressable
public void AALoadAsync<T>(string name, UnityAction<T> callback) where T : Object
{
MonoMgr.Instance.StartCoroutine(AAReallyLoadAsync(name, callback));
}
private IEnumerator AAReallyLoadAsync<T>(string name, UnityAction<T> callback) where T : Object
{
AsyncOperationHandle async = Addressables.LoadAssetAsync<T>(name);
yield return async;
if (async.Result is GameObject)
{
callback(Object.Instantiate(async.Result as GameObject) as T);
}
else
{
callback(async.Result as T);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb81f807b0e79ff4a80b2972cdb0a1ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2de5017dd0315fb4a844080a4dfa73f8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DontDestroyMgr : Singleton<DontDestroyMgr>
{
List<GameObject> dontDesObj = new List<GameObject>();
public void DontDesOnLoad(GameObject obj)
{
if(!dontDesObj.Contains(obj))
{
Object.DontDestroyOnLoad(obj);
dontDesObj.Add(obj);
}
}
public void Clear()
{
foreach(GameObject obj in dontDesObj)
{
Object.DestroyImmediate(obj);
}
dontDesObj.Clear();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79fbb7224a32bfa4fa3620ce2ab28027
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
public class SceneMgr : Singleton<SceneMgr>
{
public void LoadScene(string name,UnityAction func)
{
SceneManager.LoadScene(name);
func();
}
public void LoadSceneAsync(string name,UnityAction func)
{
MonoMgr.Instance.StartCoroutine(ReallyLoadSceneAsync(name, func));
}
private IEnumerator ReallyLoadSceneAsync(string name,UnityAction func)
{
AsyncOperation ao = SceneManager.LoadSceneAsync(name);
while(!ao.isDone)
{
EventCenter.Instance.EventTrigger("Loading", ao.progress);
yield return ao.progress;
}
func();
}
public string GetActiveSceneName()
{
return SceneManager.GetActiveScene().name;
}
public void AALoadSceneAsync(string name, UnityAction func)
{
MonoMgr.Instance.StartCoroutine(AAReallyLoadSceneAsync(name + ".unity", func));
}
private IEnumerator AAReallyLoadSceneAsync(string name, UnityAction func)
{
AsyncOperationHandle async = Addressables.LoadSceneAsync(name);
while (!async.IsDone)
{
EventCenter.Instance.EventTrigger("Loading", async.PercentComplete);
yield return async.PercentComplete;
}
func();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0ed3cda81921ae4e8f401c8bcb7afb7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58059954ae8931742a7c9a3813847f51
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ee414068f48db7e4b9f9b39a5c04ee64
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
{
"name": "Game.Hotfix.Editor.StaticTool",
"rootNamespace": "",
"references": [
"Game.Hotfix",
"CameraShake",
"spine-unity",
"Coffee.UIParticle",
"Unity.Addressables",
"Unity.ResourceManager",
"Unity.TextMeshPro",
"UnityEngine.UI",
"Unity.InputSystem",
"Unity.VisualScripting.Core"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: eb2d3645caea19c4e90cbf31b9c8afa0
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1 @@

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9acb66381f2e0ed408f0666b0c47df0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,82 @@
using UnityEngine;
using UnityEditor;
using System.Linq;
#if UNITY_EDITOR
/// This just exposes the Sorting Layer / Order in MeshRenderer since it's there
/// but not displayed in the inspector. Getting MeshRenderer to render in front
/// of a SpriteRenderer is pretty hard without this.
[CustomEditor(typeof(MeshRenderer))]
public class MeshRendererSortingEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
MeshRenderer renderer = target as MeshRenderer;
var layers = SortingLayer.layers;
EditorGUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
int newId = DrawSortingLayersPopup(renderer.sortingLayerID);
if (EditorGUI.EndChangeCheck())
{
renderer.sortingLayerID = newId;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
int order = EditorGUILayout.IntField("Sorting Order", renderer.sortingOrder);
if (EditorGUI.EndChangeCheck())
{
renderer.sortingOrder = order;
}
EditorGUILayout.EndHorizontal();
}
int DrawSortingLayersPopup(int layerID)
{
var layers = SortingLayer.layers;
var names = layers.Select(l => l.name).ToArray();
if (!SortingLayer.IsValid(layerID))
{
layerID = layers[0].id;
}
var layerValue = SortingLayer.GetLayerValueFromID(layerID);
var newLayerValue = EditorGUILayout.Popup("Sorting Layer", layerValue, names);
return layers[newLayerValue].id;
}
}
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org/>
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 512428fac1f0ad7489f05b039e604f5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cb45e8174068d9e4d864cf995e3164f0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a88821ac8cb24fb4199e26f58fb95a6f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8448f2800dcf3d441adb407db216308e
folderAsset: yes
timeCreated: 1501133226
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e3371e9602fc12543b4026c95d444839
folderAsset: yes
timeCreated: 1501134707
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,211 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.IO;
using System.Threading.Tasks;
/// <summary>
/// 保存需要烘焙的动画的相关数据
/// </summary>
public struct AnimData
{
#region 字段
public int vertexCount;
public int mapWidth;
public List<AnimationState> animClips;
public string name;
private Animation animation;
private SkinnedMeshRenderer skin;
#endregion
public AnimData(Animation anim, SkinnedMeshRenderer smr, string goName)
{
vertexCount = smr.sharedMesh.vertexCount;
mapWidth = Mathf.NextPowerOfTwo(vertexCount);
animClips = new List<AnimationState>(anim.Cast<AnimationState>());
animation = anim;
skin = smr;
name = goName;
}
#region 方法
public void AnimationPlay(string animName)
{
this.animation.Play(animName);
}
public void SampleAnimAndBakeMesh(ref Mesh m)
{
this.SampleAnim();
this.BakeMesh(ref m);
}
private void SampleAnim()
{
if (this.animation == null)
{
Debug.LogError("animation is null!!");
return;
}
this.animation.Sample();
}
private void BakeMesh(ref Mesh m)
{
if (this.skin == null)
{
Debug.LogError("skin is null!!");
return;
}
this.skin.BakeMesh(m);
}
#endregion
}
/// <summary>
/// 烘焙后的数据
/// </summary>
public struct BakedData
{
#region 字段
public string name;
public float animLen;
public byte[] rawAnimMap;
public int animMapWidth;
public int animMapHeight;
#endregion
public BakedData(string name, float animLen, Texture2D animMap)
{
this.name = name;
this.animLen = animLen;
this.animMapHeight = animMap.height;
this.animMapWidth = animMap.width;
this.rawAnimMap = animMap.GetRawTextureData();
}
}
/// <summary>
/// 烘焙器
/// </summary>
public class AnimMapBaker{
#region 字段
private AnimData? animData = null;
private List<Vector3> vertices = new List<Vector3>();
private Mesh bakedMesh;
private List<BakedData> bakedDataList = new List<BakedData>();
#endregion
#region 方法
public void SetAnimData(GameObject go)
{
if(go == null)
{
Debug.LogError("go is null!!");
return;
}
Animation anim = go.GetComponent<Animation>();
SkinnedMeshRenderer smr = go.GetComponentInChildren<SkinnedMeshRenderer>();
if(anim == null || smr == null)
{
Debug.LogError("anim or smr is null!!");
return;
}
this.bakedMesh = new Mesh();
this.animData = new AnimData(anim, smr, go.name);
}
int animNum;
public List<BakedData> Bake()
{
if(this.animData == null)
{
Debug.LogError("bake data is null!!");
return this.bakedDataList;
}
//每一个动作都生成一个动作图
for(int i = 0; i < this.animData.Value.animClips.Count; i++)
{
animNum = i;
if (!this.animData.Value.animClips[i].clip.legacy)
{
Debug.LogError(string.Format("{0} is not legacy!!", this.animData.Value.animClips[i].clip.name));
continue;
}
BakePerAnimClip(this.animData.Value.animClips[i]);
}
return this.bakedDataList;
}
private void BakePerAnimClip(AnimationState curAnim)
{
int curClipFrame = 0;
float sampleTime = 0;
float perFrameTime = 0;
curClipFrame = Mathf.ClosestPowerOfTwo((int)(curAnim.clip.frameRate * curAnim.length));
perFrameTime = curAnim.length / curClipFrame; ;
Texture2D animMap = new Texture2D(this.animData.Value.mapWidth, curClipFrame, TextureFormat.RGBAHalf, false);
animMap.name = string.Format("{0}_{1}.animMap", this.animData.Value.name, curAnim.name);
this.animData.Value.AnimationPlay(curAnim.name);
for (int i = 0; i < curClipFrame; i++)
{
//EditorUtility.DisplayCancelableProgressBar("转换进度", $"正在处理第 {i}/{curClipFrame} 步", (float)i / curClipFrame);
curAnim.time = sampleTime;
this.animData.Value.SampleAnimAndBakeMesh(ref this.bakedMesh);
for(int j = 0; j < this.bakedMesh.vertexCount; j++)
{
EditorUtility.DisplayCancelableProgressBar("转换进度", $"正在处理第 {i}/{curClipFrame} 步 {j}/{bakedMesh.vertexCount}点", (float)i / curClipFrame);
Vector3 vertex = this.bakedMesh.vertices[j];
animMap.SetPixel(j, i, new Color(vertex.x, vertex.y, vertex.z));
}
sampleTime += perFrameTime;
}
EditorUtility.ClearProgressBar();
animMap.Apply();
Debug.Log($"{animNum}/{animData.Value.animClips.Count-1}");
if (animNum== animData.Value.animClips.Count - 1)
{
Debug.Log("转换完成");
}
this.bakedDataList.Add(new BakedData(animMap.name, curAnim.clip.length, animMap));
}
#endregion
#region 属性
#endregion
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d58f874be9d391e43866e5e334ddf986
timeCreated: 1501134718
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,174 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
public class AnimMapBakerWindow : EditorWindow {
private enum SaveStrategy
{
AnimMap,//only anim map
Mat,//with shader
Prefab//prefab with mat
}
#region 字段
public static GameObject targetGo;
private static AnimMapBaker baker;
private static string path = "GamePlay_ECS\\EntityConvert";
private static string subPath = "SubPath";
private static SaveStrategy stratege = SaveStrategy.AnimMap;
private static Shader _animMapShader;
private static Shader animMapShader
{
get
{
if(_animMapShader == null)
_animMapShader = Shader.Find(animMapShaderName);
return _animMapShader;
}
}
private static string animMapShaderName = "ECSGame/URP/UnlitAnim";
#endregion
#region 方法
[MenuItem("Tools/AnimMapBaker")]
public static void ShowWindow()
{
EditorWindow.GetWindow(typeof(AnimMapBakerWindow));
baker = new AnimMapBaker();
}
void OnGUI()
{
targetGo = (GameObject)EditorGUILayout.ObjectField(targetGo, typeof(GameObject), true);
subPath = targetGo == null ? subPath : targetGo.name;
EditorGUILayout.LabelField(string.Format("保存路径output path:{0}", Path.Combine(path, subPath)));
path = EditorGUILayout.TextField(path);
subPath = EditorGUILayout.TextField(subPath);
stratege = (SaveStrategy)EditorGUILayout.EnumPopup("保存策略output type:", stratege);
if (GUILayout.Button("Bake"))
{
if(targetGo == null)
{
EditorUtility.DisplayDialog("err", "targetGo is null!", "OK");
return;
}
if(baker == null)
{
baker = new AnimMapBaker();
}
baker.SetAnimData(targetGo);
List<BakedData> list =baker.Bake();
if (list != null)
{
for(int i = 0; i < list.Count; i++)
{
BakedData data = list[i];
Save(ref data);
}
}
}
}
private void Save(ref BakedData data)
{
switch(stratege)
{
case SaveStrategy.AnimMap:
SaveAsAsset(ref data);
break;
case SaveStrategy.Mat:
SaveAsMat(ref data);
break;
case SaveStrategy.Prefab:
SaveAsPrefab(ref data);
break;
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private Texture2D SaveAsAsset(ref BakedData data)
{
string folderPath = CreateFolder();
Texture2D animMap = new Texture2D(data.animMapWidth, data.animMapHeight, TextureFormat.RGBAHalf, false);
animMap.LoadRawTextureData(data.rawAnimMap);
AssetDatabase.CreateAsset(animMap, Path.Combine(folderPath, GetValidName(data.name) + ".asset"));
return animMap;
}
public static string GetValidName(string pName)
{
pName = pName.Replace("|", "@");
return pName;
}
private Material SaveAsMat(ref BakedData data)
{
if(animMapShader == null)
{
EditorUtility.DisplayDialog("err", "shader is null!!", "OK");
return null;
}
if(targetGo == null || !targetGo.GetComponentInChildren<SkinnedMeshRenderer>())
{
EditorUtility.DisplayDialog("err", "SkinnedMeshRender is null!!", "OK");
return null;
}
SkinnedMeshRenderer smr = targetGo.GetComponentInChildren<SkinnedMeshRenderer>();
Material mat = new Material(animMapShader);
Texture2D animMap = SaveAsAsset(ref data);
mat.SetTexture("_MainTex", smr.sharedMaterial.mainTexture);
mat.SetTexture("_AnimMap", animMap);
mat.SetFloat("_AnimLen", data.animLen);
string folderPath = CreateFolder();
AssetDatabase.CreateAsset(mat, Path.Combine(folderPath, GetValidName(data.name) + ".mat"));
return mat;
}
private void SaveAsPrefab(ref BakedData data)
{
Material mat = SaveAsMat(ref data);
if(mat == null)
{
EditorUtility.DisplayDialog("err", "mat is null!!", "OK");
return;
}
GameObject go = new GameObject();
go.AddComponent<MeshRenderer>().sharedMaterial = mat;
go.AddComponent<MeshFilter>().sharedMesh = targetGo.GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh;
string folderPath = CreateFolder();
PrefabUtility.CreatePrefab(Path.Combine(folderPath, GetValidName(data.name) + ".prefab").Replace("\\", "/"), go);
}
private string CreateFolder()
{
string folderPath = Path.Combine("Assets/" + path, subPath);
if (!AssetDatabase.IsValidFolder(folderPath))
{
AssetDatabase.CreateFolder("Assets/" + path, subPath);
}
return folderPath;
}
#endregion
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b0821312d64995540ae7372c5af049c0
timeCreated: 1501143281
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
{
"name": "Game.Hotfix.Editor.AnimMapBaker",
"rootNamespace": "",
"references": [
"Game.Hotfix",
"CameraShake",
"spine-unity",
"Coffee.UIParticle",
"Unity.Addressables",
"Unity.ResourceManager",
"Unity.TextMeshPro",
"UnityEngine.UI",
"Unity.InputSystem",
"Unity.VisualScripting.Core"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9dc34cc9588f7c04d887b97a4747f393
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e072dbe8965ad9440aed440c55f81680
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,36 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ECSGame_URP_UnlitAnim
m_Shader: {fileID: 4800000, guid: ebdcc09f7cb55fc44ac470f5bd7735bd, type: 3}
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _AnimMap:
m_Texture: {fileID: 2800000, guid: c97a11d5fda59bf4aac7fa0ed2e9d24f, type: 2}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AnimLen: 0
m_Colors:
- _BaseColor: {r: 1, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4d46dbf44bad4c9499d457c512a24142
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ECSGame_URP_UnlitNormal
m_Shader: {fileID: 4800000, guid: 4f6aed460e447d74185e39330aab44fa, type: 3}
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats: []
m_Colors: []
m_BuildTextureStacks: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0dc5ecf6006d10941a0717457781c1c9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,95 @@
Shader "ECSGame/URP/UnlitAnim"
{
Properties
{
_BaseColor("BaseColor", color) = (1,1,1,1)
_MainTex("Texture", 2D) = "white" {}
_AnimMap("AnimMap", 2D) = "white" {}
_AnimLen("Anim Length", Float) = 0
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalRenderPipeline"}
Cull off
Pass
{
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// Includes
// Changed
//#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
//Changed
//#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
//new
#pragma target 4.5
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl"
//new
struct appdata
{
float2 uv : TEXCOORD0;
float4 pos : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
CBUFFER_START(UnityPerMaterial)
float _AnimLen;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _AnimMap;
float4 _AnimMap_TexelSize;//x == 1/width
float4 _BaseColor;
CBUFFER_END
float4 ObjectToClipPos(float3 pos)
{
return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, float4 (pos,1)));
}
v2f vert(appdata v, uint vid : SV_VertexID)
{
UNITY_SETUP_INSTANCE_ID(v);
float f = _Time.y / _AnimLen;
fmod(f, 1.0);
float animMap_x = (vid + 0.5) * _AnimMap_TexelSize.x;
float animMap_y = f;
float4 pos = tex2Dlod(_AnimMap, float4(animMap_x, animMap_y, 0, 0));
v2f o;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.vertex = ObjectToClipPos(pos);
return o;
}
float4 frag(v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
return _BaseColor;
}
ENDHLSL
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ebdcc09f7cb55fc44ac470f5bd7735bd
ShaderImporter:
externalObjects: {}
defaultTextures:
- _MainTex: {instanceID: 0}
- _AnimMap: {instanceID: 0}
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,83 @@
Shader "ECSGame/URP/UnlitNormal"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalRenderPipeline"}
Cull off
Pass
{
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// Includes
//changed
//#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
//new
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
//changed
//#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
//new
#pragma target 4.5
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl"
//new
struct appdata
{
float2 uv : TEXCOORD0;
float4 pos : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
CBUFFER_START(UnityPerMaterial)
float _AnimLen;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _AnimMap;
float4 _AnimMap_TexelSize;//x == 1/width
CBUFFER_END
float4 ObjectToClipPos(float3 pos)
{
return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, float4 (pos,1)));
}
v2f vert(appdata v, uint vid : SV_VertexID)
{
UNITY_SETUP_INSTANCE_ID(v);
v2f o;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.vertex = ObjectToClipPos(v.pos);
return o;
}
float4 frag(v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDHLSL
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 4f6aed460e447d74185e39330aab44fa
ShaderImporter:
externalObjects: {}
defaultTextures:
- _MainTex: {instanceID: 0}
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d5d425136cef53c4b96119a051acee9d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9c5dd14d58b09344e8068bd676a4ec9d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More