Cocos Creator_实现策略_多点触控之触控管理器监听单例_TypeScript
觸控管理器(TypeScript實現)?
【主要功能】
1.實時訪問每個觸摸手指的狀態(手指順序,touch位置,按鈕狀態,Touch類)
2.使鼠標與觸摸的API兼容訪問
3.實時訪問鍵盤按鈕狀態
4.增加基礎數據結構 List Dictionary Statck Queue
?
開頭說一下我也是最近才開始接觸CocosCreator,所以有哪些錯誤望指出。
完成版我會放到GitHub.
CocosCreator在使用的過程中對事件的監聽事件方式我用著很別扭所以才特意的早了個輪子,起始就是簡單的對其內部API進行了加工而已,大佬就不用看了-_-。
? CocosCreator的觸摸互交監聽事件需要先綁定到指定的Node上,所以想由單例調用的話就必須綁定到一個合適的Node上。而且這個Node的觸摸面積必須是最大的!
? 那顯而易見的就是Canvas了或者Camera,Camera我沒試過你感興趣的話可以試試。首先Canva符合我們的需要啊,真是剛需。
先看下最終效果20多秒的Gif:包括了TouchFinger的?手指順序記錄、點擊、滑動、彈起、失效( |?與 1?不一樣哦在圖里, |?代表無觸摸)
? 接下來就開始制定實現策略,不過你必須先了解一下CocosCreator的內置觸摸API,才能進行加工啊!!!
? 對了順便一提鍵盤的實現策略我會順便一提的。
1.EventType
cc.Node.EventType 包含著觸控與鼠標的事件,至于為什么沒有鍵盤的呢?因為觸摸與鼠標的監聽事件需要實體(Node)啊! 而鍵盤并不需要特定實體,Cocos早已在內部留有了一個系統事件單例,來方便全局使用,所以鍵盤就 不要綁定特定了實體了直接綁這個全局的就行(systemEvent)向深入理解的看官方的“節點系統事件”就好。 看看源碼你就清楚了,在這暫不詳述,存在即合理^_^。【看源碼理解一下吧】
| cocos2d/core/event/system-event.js:198 |
2.枚舉對象定義
| cc.Node.EventType.TOUCH_START | 自定義 | 當手指觸點落在目標節點區域內時 |
| cc.Node.EventType.TOUCH_MOVE | 自定義 | 當手指在屏幕上目標節點區域內移動時 |
| cc.Node.EventType.TOUCH_END | 自定義 | 當手指在目標節點區域內離開屏幕時 |
| cc.Node.EventType.TOUCH_CANCEL | 自定義 | 當手指在目標節點區域外離開屏幕時 |
3.Touch?類型
? Touch類封裝了觸摸手指的具體信息
- getLocation?獲取當前觸點位置。
- getLocationX?獲取當前觸點 X 軸位置。
- getLocationY?獲取當前觸點 Y 軸位置。
- getPreviousLocation?獲取觸點在上一次事件時的位置對象,對象包含 x 和 y 屬性。
- getStartLocation?獲獲取觸點落下時的位置對象,對象包含 x 和 y 屬性。
- getDelta?獲取觸點距離上一次事件移動的距離對象,對象包含 x 和 y 屬性。
- getLocationInView?獲取當前事件在游戲窗口內的坐標位置對象,對象包含 x 和 y 屬性。
- getPreviousLocationInView?獲取觸點在上一次事件時在游戲窗口中的位置對象,對象包含 x 和 y 屬性。
- getStartLocationInView?獲取觸點落下時在游戲窗口中的位置對象,對象包含 x 和 y 屬性。
- getID?觸點的標識 ID,可以用來在多點觸摸中跟蹤觸點。
- setTouchInfo?設置觸摸相關的信息。
4.?cc.Event.EventTouch
? 觸摸事件綁定的回調參數類型,里面包含著觸摸事件的當前觸摸狀態的所有信息
| cocos2d/core/event/event.js:202 |
? ?
[Tip]Cocos的觸摸事件的touch信息是以棧形式存儲【主體策略】
1.為主Canvas綁定枚舉對象,的回調方法
this.node.on(cc.Node.EventType.TOUCH_START, this.touchBtnDownMonitor);this.node.on(cc.Node.EventType.TOUCH_END, this.touchBtnUpMonitor);this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.touchBtnDisMonitor);this.node.on(cc.Node.EventType.TOUCH_MOVE, this.touchMoveMonitor);2.靜態訪問觸摸手指的Touch信息,以及觸摸的狀態:按下、移動、彈起(失效)
? ? ? ?
const ButtonStatu= cc.Enum({ Up: 0 , Down: 1, Dis:2,Move:3})? ? ? ?定義按鍵狀態:ButtonStatu[],并一開始初始化為10(cocos指出8點觸控,具體可自行設置)
3.對觸摸手指數據進行數組存儲(在這里我并不想用List、Dictionary等數據結構(需自行實現))
? ? ?
?touchs : cc.Touch[];? ? //存儲Touch信息touchStatu : ButtonStatu[];? ? //存儲狀態信息? ? ? ?根據枚舉對象在綁定觸摸事件后,訪問的綁定枚舉對象的回調方法時對數據記錄
3.根據CocosCreator API?將觸摸手機數據進行保留與更新.
? ? 需要兩個共用函數,
? ? ? ? a.手指加入? ?--touchFingetMonitor
private touchFingetMonitor(event :cc.Event.EventTouch){//手指數組為空則直接進行保存,否則將進行數據更新if(this.touchs){//初始化變量let temp : cc.Touch[] = []; //最終的手指數組信息let havThis :Boolean= false; //當前手指是否已經被保存過let havThisID :number= -1; //當前手指ID,為-1則當前手指未被保留//檢測當前手指是否已經被保存過,未保存則記錄其IDfor(let i=0;i<this.touchs.length;i++){temp[i] = this.touchs[i];if(!havThis && temp[i] == event.touch){havThis = true;}//處理getTouches()中不區分,觸摸手指的前后信息,即第幾根手指觸摸其該手指排序就是第次(例如有三手指按順序觸摸A,B,C,B一直按下彈起但其保存位置一直是第二位)if(havThisID == -1 && ((temp[i] == null && event.touch.getID() == i) ||temp[i].getID() == event.touch.getID())){havThisID = i;}}if(!havThis){if(havThisID != -1){temp[havThisID] = event.touch;}else{if(event.touch.getID() < this.touchs.length){for(let i=this.touchs.length;i>event.touch.getID();i--){temp[i] = temp[i-1];}temp[event.touch.getID()] = event.touch;}else{temp[this.touchs.length] = event.touch;}}}this.touchs = temp;}else{this.touchs = [event.touch];}}? ? ? ? b手指減去(CocosCreator默認用的是Stack),我覺得不怎么好使.? ?--touchFingetOutMonitor
private touchFingetOutMonitor(event :cc.Event.EventTouch){let touchID = event.touch.getID();//只有一根手指就直接清除數據,更新數據if(this.touchs.length == 1){this.touchs = [];}else{let temp : cc.Touch[] = [];let thisindex :number= -1;for(let i=0;i<this.touchs.length;i++){if(this.touchs[i].getID() == event.touch.getID()){thisindex = i;break;}}let i=0;for(i ;i<thisindex;i++){temp[i] = this.touchs[i];}for(i ;i<this.touchs.length-1 ;i++){temp[i] = this.touchs[i+1];}this.touchs = temp;}}4.數據處理
private touchBtnDownMonitor(event :cc.Event.EventTouch){this.touchFingetMonitor(event);this.touchStatu[event.touch.getID()] = BtnStatu.Down;}private touchMoveMonitor(event :cc.Event.EventTouch){this.touchFingetMonitor(event);this.touchStatu[event.touch.getID()] = BtnStatu.Move;}private touchBtnUpMonitor(event :cc.Event.EventTouch){this.touchStatu[event.touch.getID()] = BtnStatu.Up;this.touchFingetOutMonitor(event);}private touchBtnDisMonitor(event :cc.Event.EventTouch){this.touchStatu[event.touch.getID()] = BtnStatu.Dis;this.touchFingetOutMonitor(event);}? ? 這四個方法在響應時傳入的EventTouch信息,會時刻的進行更新,所以需要時刻的將其中的數據進行記錄。
而touchBtnDownMonitor 和?touchBtnUpMonitor?只需要處理 手指加入,touchBtnDisMonitor?和?touchMoveMonitor只需要處理 手指減去即可(所以只能實現三種狀態:按下、彈起、移動),可自行設計。
5.測試處理
? 順便建個腳本就能用,這里我用到了數據結構比較方便
finger : Dictionary<number,cc.Node>;if(InputMonitor.Instance().Touchs() != null){for(let i=0;i<InputMonitor.Instance().Touchs().length;i++){if(!this.finger.ContainKey(id)){let obj:cc.Node = cc.instantiate(this.fingerPrefab);obj.parent = cc.director.getScene();obj.position = InputMonitor.Instance().Touchs()[i].getLocation();obj.getComponentInChildren(cc.Label).string = id.toString();this.finger.Add(id,obj);}else{this.finger.Item(id).position = InputMonitor.Instance().Touchs()[i].getLocation();}}}let del : List<number> = new List<number>();for(let j=0;j<this.finger.Count();j++){let id : number = this.finger.ItemKeyofIndex(j);if(!InputMonitor.Instance().ContainID(id)){del.Add(id);}}for(let j =0;j<del.Count();j++){this.finger.Item(del.Item(j)).destroy();this.finger.Remove(del.Item(j));}第二次更新
這次支持了鼠標顯示世界位置
提要:
? 在cocosCreate中的要獲取鼠標的世界位置,就必須是在使用兩臺攝像機的情況下(一臺的話你還費什么勁^_^)。
? ? a.一臺是UI的相機
? ? b.一臺是世界相機
? 當然這時的世界原點還是以Canvas的(0,0)點為準,鼠標的世界位置也是以此為原點計算。
? 世界相機有時會跟隨玩家而移動(UI相機當然不可能,不然你的UI元素還要不要了)
[Tip]新手可能會將UI相機與世界相機搞混。所以我在這闡述一下,首先Canvas只是畫布并不會將UI圖像顯示出來,所以需要一個特定的相機來獲取UI(Canvas中的元素)圖像,cocosCreate在你的默認場景的Canvas中的MainCamera相機就是的,但他默認是世界元素與UI元素都會顯示。世界元素就是不以Canvas為根節點,UI元素才是(這里只是我的個人區分),這樣區分要實現就需要自己定義Group了。所以我們通常用一個或多個世界相機只顯示世界元素,一個UI相機只顯示UI元素,來實現UI永遠顯示在世界元素之上.(可能cocosCreate的3D成熟了自然就是了)【警惕點】
1.屏幕的分辨率變化
2.世界位置的與觸點位置的轉換
【實現策略】
1.獲取觸點的屏幕位置
2.獲取屏幕的實際尺寸
3.將觸點位置通過屏幕實際尺寸轉換為實際的屏幕位置(觸點的屏幕位置只會根據canvas的大小來計算,子啊屏幕拉伸后回不準確,所以需要再次轉換為實際的屏幕位置)
4.根據世界相機將實際的屏幕尺寸轉換為世界位置
【實現方法】
1.定義參數
@property(cc.Node)worldCamera : cc.Node= null; //世界相機MousePosition() :cc.Vec2 //鼠標屏幕位置 --不是實際位置MouseToWorldPosition() :cc.Vec2 //鼠標的世界位置2.獲取屏幕的實際尺寸
cc.view.setResizeCallback(this.initScreenInfo);//初始化屏幕參數 --啟動時調用或者屏幕大小改變時調用 initScreenInfo(){InputMonitor.Instance().visibleSize = new cc.Vec2(cc.view.getVisibleSize().width/2 ,cc.view.getVisibleSize().height/2); }2.將觸點位置通過屏幕實際尺寸轉換為世界位置
if(this.worldCamera != null){this.mouseWorldPosition.x = this.worldCamera.position.x - this.visibleSize.x + this.mousePosition.x;this.mouseWorldPosition.y = this.worldCamera.position.y - this.visibleSize.y + this.mousePosition.y;return this.mouseWorldPosition;}else{return this.mousePosition;}第三次更新
這次支持了實時訪問鍵盤的響應事件
1.調用接口范例
update(){if(InputMonitor.Instance().GetKeyBeginDown(cc.macro.KEY.a)){if(this.node.width > 0)this.node.width = -this.node.width;this.anim.play("run",0);}if(InputMonitor.Instance().GetKeyBeginDown(cc.macro.KEY.d)){if(this.node.width < 0)this.node.width = -this.node.width;this.anim.play("run",0);}if(InputMonitor.Instance().GetKeyBeginDown(cc.macro.KEY.w)){this.anim.play("jump",0);}if(InputMonitor.Instance().GetKeyBeginDown(cc.macro.KEY.s)){this.anim.play("dying",0);}}?
總結
以上是生活随笔為你收集整理的Cocos Creator_实现策略_多点触控之触控管理器监听单例_TypeScript的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GYP介绍
- 下一篇: 三星 android截屏快捷键,三星手机