
要完成這樣的工作,我們可以想見有幾個功能要完成: 1. 要有個系統不斷去檢查所有游標與按鈕是否碰撞。
2. 游標要有一般normal與倒數狀態,要有個屬性可以決定倒數的時間長短。
3. 按鈕要有normal、hover與selected狀態。
這幾件事情不難,不過每次都要重寫這些功能的話會很累人,所以我們把基本功能寫進extensions裡面,要用的時候再透過繼承,然後去覆寫主要的方法,就可以節省開發的時間。首先我們建立一個CursorManager類別,它負責管理所有的游標與按鈕的清單,並且會不停的去檢查游標與按鈕的碰撞情形。它被設計成一個Singleton,並且透過呼叫static public方法來做事(就像Facebook AS3 API裡的Facebook類別用法一樣)。不過目前它會自動被按鈕與游標呼叫,並且默默的完成它的工作,所以開發者大概也感覺不到它的存在。
接著我們建立KinectCursor類別,繼承自MovieClip,當這個類別的實體加到display list時它自動會要求加入CursorManager的游標列表。當我們要開始讓user控制這個游標時,呼叫它的startTracking(user, range)方法,並傳入要追蹤的User(User類別)以及一個範圍(Rectangle類別),這個範圍是我們希望可以傳入一個user容易操作的範圍,也就是右手容易觸及到的範圍,將它對應到整個視窗上。示意如下圖:

黑色外框是Kinect截取到的影像,紅色框表示右手最容易活動的範圍,我們需要傳入的就是紅色框框的左上角座標以及寬高,為了在每種影像大小都可以使用,我們使用Relative座標,也就是0~1的值。要停止追蹤游標的話呼叫stopTracking()來停止。
在KinectCursor的子類別中,我們透過holdingTime這個屬性來設定要倒數多少時間,單位是毫秒。覆寫updatePercent(percent)來更新倒數的進度,percent為0~1的值。另外覆寫setNormal()來回到normal狀態。
按鈕的部分我們建立KinectButton類別,它在加入或移出display list時會自動加入或移出CursorManager的按鈕清單。在被KinectCursor選取後會送出CursorEvent.SELECTED事件,這是我們自定的的事件。要在按鈕的三種狀態處發時去處理視覺變化,可以在子類別裡覆寫atHover()、atNormal()與atSelected()方法,或是在主程式指定實體的onHover、onNormal與onSelected方法(類似Progression的設計方式)。
CursorManager、KinectCursor、KinectButton是在com.as3nui.nativeExtensions.air.kinect.extensions.display這個package裡,而CursorEvent則是在com.as3nui.nativeExtensions.air.kinect.extensions.events這個package。下面來看一下實際專案時要寫哪些程式碼。myCursor是游標實體,MyCursor類別繼承KinectCursor。btn是按鈕實體,BtnSquare繼承KinectButton。MyCursor類別需要做以下的事情:
public function MyCursor() { init(); } private function init():void { //設定倒數時間 holdingTime = 500; stop(); } override public function updatePercent(percent:Number):void { //覆寫updatePercent,這邊進度已作成影格動畫,所以跑影格就好 gotoAndStop(1 + int(percent * 100)); } override public function setNormal():void { //覆寫setNormal,回到第1個影格恢復normal狀態 gotoAndStop(1); }
接下來BtnSquare的程式碼:
//只是一個顏色方塊 public var square:Sprite; public function BtnSquare() { init(); } private function init():void { stop(); } override public function atHover():void { //覆寫atHover,改變方塊顏色 TweenMax.to(square, 0.5, {tint:0x990000}); } override public function atNormal():void { //覆寫atNormal,改變方塊顏色 TweenMax.to(square, 0.5, {tint:null}); } override public function atSelected():void { //覆寫atSelected,改變方塊顏色 TweenMax.to(square, 0, {tint:0xff0000}); }
最後,主程式跟游標與按鈕相關的程式碼:
private function init():void { //按鈕加上監聽CursorEvent.SELECTED事件,然後開始追蹤游標 btn.addEventListener(CursorEvent.SELECTED, btnSelected); startTrackingCursor(); } private function startTrackingCursor():void { //追蹤游標,_user是Kinect追蹤到的User myCursor.visible = true; myCursor.startTracking(_user, new Rectangle(0.5, 0.1, 0.25, 0.4)); } private function stopTrackingCursor():void { //停止追蹤 myCursor.visible = false; myCursor.stopTracking(); } private function btnSelected(e:CursorEvent):void { //按鈕選到後做該做的事 removeChild(btn); stopTrackingCursor(); removeChild(myCursor); //做其他事... }
就是這樣!我想應該已經把工作精簡到不能再精簡了。
最後要回頭提一個問題:如果我們直接把user右手對應的座標指定給游標,可以想見游標一定抖動非常厲害!要解決這個問題,參考Kinect Toolbox,要做一些運算去過濾掉抖動的狀態,當然這會使游標反應稍微慢一點,但抖動的情形改善很大。Kinect Toolbox是C#程式,我已經將相關的運算改寫成AS3並整合到CursorManager裡,有興趣的請自行翻出來研究。
程式碼與範例,下一篇再提供連結!
上一篇:Some extensions for AIRKinect(2)KinctSprite
下一篇:Some extensions for AIRKinect(4)KinectGestureRecognizer
嗨!Gray大!我是阿邪!
回覆刪除我目前有一個也是關於Kinect滑鼠點擊的問題
不過點擊的對象不是Sprite也不是MovieClip
而是AIR的HTMLLoader載進來的HTML內容!
一般我們Sprite與MovieClip使用Kinect滑鼠可以dispatch一個MouseEvent去模擬點擊到的滑鼠事件
不過在載入的HTML內容裡,要去點內容裡的連結反而不知該用什麼方法!不知你有沒有在這方面經驗與解決的辦法??
Hello 阿邪:
刪除你好
我懂你的意思
因為我們沒辦法知道Load進來的HTML是甚麼東西
確實是不知道要怎麼判斷我們的滑鼠游標有沒有點到HTML上的button或link
AS3應該也沒有能力去移動真正的滑鼠
反過來想,用Kinect來瀏覽一般網頁好像沒甚麼道理
所以我猜你們載入的HTML內容是你們自己做的特殊內容嗎?
是的話或許可以把感應區位置等等的資訊偷塞給AIR
不是的話...我還真想不出其他解法了
其實我是要做一個多功能系統!
刪除其中一個功能就是用Kinect滑鼠來瀏覽一般網頁!
看來要先放掉網頁瀏覽這一個項目了= =
其實我有想到一個方法!但是不知可不可行!
回覆刪除既然FLASH不能控制滑鼠點擊!交由C#來點擊應該就沒問題(看到C#只要輸入座標就可以模擬滑鼠還有點擊)!
所以就變成要寫一個中介程式來聯絡FLASH與C#,需要的時候就傳送座標呼叫C#滑鼠左鍵的函式!目前的想法是這樣!不過沒寫過C#,要來試一下!
Gray, 你好! 我是個airkinect的新手, 我想問一下第一種方法, 用手向前推來按button, 我該怎麼做,因為我沒有什麼概念去做,可以給我一點方法嗎?
回覆刪除先偵測是否碰到button,再偵測手的z坐標改變量
刪除