本文首發蠻牛,次發博客園。接系列 第一篇,第二篇,本文為第三篇,再次感謝“武裝三藏”在前兩篇無私且精彩的問題解答
寫在最前,時光煮雨,為了懷念
以下引用曾今讀過的一些教程文章
其實這3種動畫都有它特定的使用場合。
第一種動畫適合創建簡單的對象位移及直接性質的屬性更改(在后面的教程中,我還將更深入的挖掘Storyboard動畫的潛力,動態創建更復雜的基於KeyFrame的關鍵幀動畫)。
第二種動畫適合全局屬性的時時更改,例如我們后面要講到的敵人或NPC以及地圖等全體性的相對位移及屬性更改時就要用到它了。
第三種動畫則非常適合運用在Spirit(角色)的個人動畫中,例如角色的移動,戰斗,施法等動作。
小結:前三節分別講解了Storyboard動畫,CompositionTarget動畫,DispatcherTimer動畫,並橫向分析了不同的場合對應不同的動畫應用模式,這些將是構成WPF/Silverlight游戲引擎的基礎。
這里的三種動畫形式分別可以類比到Unity3d中的,
第一種,基於DoTween的各種MoveTo(Vector3,duration),或者是第一篇的直接移動;
第二種,基於Update的逐幀更新;
第三種,基於FixUpdate的定時更新,比如這里提到的戰斗可能是有物理碰撞,或者是一種類似自定義的計時器的Timer(下篇會分析下)。
這些東西比較底層了,需要了解FixUpdate和Update的區別,以及UI線程和非UI線程之間的關系(wpf中的DispatcherTimer的概念)
這塊東西有點深,我也不敢妄言,是否正確有大師路過,可以解惑一下。列出兩篇參考文章,供延伸閱讀吧
Difference between Update method and FixedUpdate in Unity?
WPF中的Timer與DispatcherTimer的區別與應用
這三種動畫形式,很多人都知道,但是如何使用和區別,卻在博文中只字未提。
這里引用列出來只為懷念。
背景
前兩篇都比較基礎,運用一些基礎知識,其實早都有一些大牛封裝好了插件和工具,不必大家再重復制造輪子。但各種封裝難免有功能重疊,且可能用法也會有不同,這可能是我們需要稍微留意的東西。這篇主要羅列下基於DoTween插件UGUI的直接移動和Unity Native2D實現鼠標點擊逐幀移動的功能實現,關於這兩個插件和功能不再詳解,因為有的是教程,若想學習自己搜索吧。圖片還是一樣的
實現一
基於DoTween的UGUI平移,這里自己計算了下 duration可能不對歡迎指正,代碼如下:
using UnityEngine; using System.Collections; using UnityEngine.UI; using DG.Tweening; public class PanelContollerDoTween : MonoBehaviour { // Use this for initialization public Image sprite; private float speed=2; void Start () { } // Update is called once per frame void Update () { if (Input.GetButton("Fire1")) { //這里寫的該坐標是像素坐標,也就是屏幕坐標的意思(比世界坐標小) Vector3 mouseWorldPostion = Input.mousePosition;//Camera.main.ScreenToWorldPoint(); float duration = Vector3.Distance(mouseWorldPostion , sprite.transform.position) / speed * Application.targetFrameRate; sprite.transform.DOMove(mouseWorldPostion, duration).SetEase(Ease.Linear); } } }
實現二
這塊稍微說一下,看過很多教程一般都是單講UGUI或者單講Natvie2D,很少有一起使用的,這里自己實驗了下,直接建立一個Scene和UGUI一起使用即可,比較簡單,深色的框是我給Panel設置的顏色便於區別,這里發現二者可以很好的共存的,效果圖如下:
代碼如下:
using UnityEngine; using System.Collections; public class PlayerController : MonoBehaviour { private Vector3 currentPositon; private Vector3 moveDirection; private float speed = 2; private Vector3 targetPositon; Vector3 mouseWorldPositon = Vector3.zero; // Use this for initialization void Start() { moveDirection = Vector3.right; } // Update is called once per frame void Update() { currentPositon = transform.position; //是鼠標左鍵點擊 if (Input.GetButton("Fire1")) { mouseWorldPositon = Camera.main.ScreenToWorldPoint(Input.mousePosition); moveDirection = mouseWorldPositon - currentPositon; moveDirection.z = 0; moveDirection.Normalize(); } //Debug.Log(string.Format("x1:{0},y1:{1},z1:{2},x2:{3},y2:{4},z2:{5},d:{6}", mouseWorldPositon.x, mouseWorldPositon.y,mouseWorldPositon.z, currentPositon.x, currentPositon.y,currentPositon.z, Vector3.Distance(mouseWorldPositon, currentPositon))); if (Vector3.Distance(new Vector3( mouseWorldPositon.x,mouseWorldPositon.y,0), currentPositon) > 1) { targetPositon = moveDirection * speed + currentPositon; transform.position = Vector3.Lerp(currentPositon, targetPositon, Time.deltaTime); } else { transform.position = targetPositon; } } }
這里留下了一個小問題就是關於移動了某一點的判斷問題,這里我簡單的使用了兩點的距離小與某個絕對值來做的,但在Natvie2D下發現移動有跳躍,主要是坐標系的單位問題,如果有高手路過可以幫忙提供更好的方法。
問題總結
根據三篇的學習,這篇是收獲比較大的,特別是通過這篇的學習,找到了上篇中遇到的問題,主要是
1、鼠標點擊的坐標問題?
2、是關於Vecotr3.Lerp插值的問題
如果細心的朋友可能會發現2個函數我在UGUI中都是注釋掉的
Camera.main.ScreenToWorldPoint(Input.mousePosition)
Vector3.Lerp(currentPositon, targetPositon, Time.deltaTime);
主要的問題其實是在坐標系的值上,UGUI專門做了一次優化,使用的2D世界的屏幕坐標單位是像素,值都很大,而Native2D使用的是3D世界的坐標系統單位是浮點百分值,所以在轉換和使用上有差異的。
這篇也留下了一個問題,就是UGUI和Native2D的鼠標事件的遮擋問題,現在看到的現象是鼠標事件是可以穿越的,這個問題等到以后再解決吧。