[CListCtrl]拖曳檔案至List上方

如要操作行為正確,此方法需先繼承CListCtrl之後,並改寫OnDropFiles()。

如不太強調行為正確,則改寫Dialog的OnDropFiles()也可以。

這邊選用偷懶的方式,直接改寫Dialog的OnDropFiles()。

1.先要將Dialog(CListCtrl)的Accept File屬性打開,這樣才能將檔案拖到Dialog上面並丟下。

2.加入自定訊息的

3.ON_WM_DROPFILES()

enum eMyListCtrl{ WM_USER_CHANGE_LIST = WM_APP + 0x0100 };  
   
 ON_MESSAGE( WM_USER_CHANGE_LIST, OnDropFilesToList )  
   
 void CFileSearchDlg::OnDropFiles(HDROP hDropInfo)  
 {  
   // TODO: Add your message handler code here and/or call default  
    char  cFilePathName[_MAX_PATH] = {0};  
    UINT nNumOfFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0); //文件的个数  
    for ( UINT nIndex=0 ; nIndex< nNumOfFiles; ++nIndex )  
    {  
      DragQueryFile(hDropInfo, nIndex, cFilePathName, _MAX_PATH); //得到文件名  
      // 把得到的文件名传给父窗口  
      LPARAM lParam = (LPARAM)cFilePathName;  
      //GetParent()->SendMessage(WM_USER_CHANGE_LIST,0,lParam);  
      this->SendMessage(WM_USER_CHANGE_LIST,0,lParam);  
    }  
   
   CDialog::OnDropFiles(hDropInfo);  
 }  
   
 LRESULT CFileSearchDlg::OnDropFilesToList(WPARAM wParam, LPARAM lParam)  
 {  
   //m_wndListCtrl.DeleteAllItems();  
   char * cFilePath = (char *)lParam;// 得到拖放文件的路径  
   
   //Check is dir or File Path  
   this->SearchFileList(cFilePath);  
   
   return true;  
 }  

[Unity]AnimationState

參考資料:AnimationState
Unity版本:3.5.6f4

        一般在控制AnimationClip播放時,都會使用Animation類別來控制。但如果想要控制播放速度時,確沒有介面可以控制。所以如果要變更播放各個AnimationClip的播放速度的話,就需要直接操作Animation內所儲存的AnimationStates。底下就針對AnimationState的各個屬性與操作介面來進行測試。

I.屬性:
1.enabled:(bool)
        此屬性是用來控制目前所對應的AnimationClip能不能進行播放。所以在Animation Clip播放時,將AnimationState.enabled設為false時,時間軸就會停止在當下的時間。之後再把AnimationState.enabled設為true時,時間軸就會從目前停止的時間繼續往下播放。

2.weight:(float)
        目前文件寫的看不懂,所以先跳過。

3.wrapMode:(WrapMode)
        AnimationClip的播放模式,可以參考[Unity]Animation WarpMode

4.time:(float)
        動畫的播放時間軸,一般是從0到無限大。可以透過強制指定時間軸來讓動畫的時間軸移動到指定的時間,但此時動畫物件本身並不會到達指定時間的狀態,也就是動畫物件會停留在上次停止的位置。當開始播放動畫的時候,就會從指定的時間開始播放。

5.normalizedTime:(float)
        normalize的動畫時間。此屬性為0到1。0.5代表動畫的時間的中點。

6.speed:(float)
        動畫播放速度,此屬性等於1時,就是正常播放。如要反向播放的話,就只要給定負值就好。為了達到反向播放的效果,也要注意到WrapMode的問題,可以參考[Unity]Animation WarpMode

7.normalizedSpeed:(float)
        normalize的播放速度,一般是做為在兩個動畫間做同步播放使用。根據官方的說法,此屬性會比Animation.SyncLayer()易於使用。

8.length:(float)
        Animation Clip的總播放時間,單位為秒。

9.layer:(int)
        此屬性用來設定AnimationClip播放時的層級,層級會影響到計算動畫播放時的權重值。越高層級的AnimationClip在計算最後繪製權重時,比較可以優先得到自已所預期需要的權重值。而低層級的AnimationClip僅能使用高層級所不需用到的權重值,換句話說,也就是低層級的僅能撿高層級剩下的來用。

10.clip:(AnimationClip)
        要用來播放的AnimationClip。

11.name:(String)
        AnimationClip的名稱。

12.blendMode:(AnimationBlendMode)
        動畫的繪製模式。可參考     。

II.操作介面:
1.AddMixingTransform(Transform mix, bool recursive = true):
        把要有相同的動畫效果的GameObject.transform加到AnimationState內,這樣就可以使用同一個動畫效果套用到不同的GameObject上。這樣可以減少AnimationClip的製作數量。

        recursive設為true時,代表所有混合的transform的子物件都將會被以同樣的方式播放動畫。
(目前未測試成功)

2.RemoveMixingTransform(Transform mix):
        把加到AnimationState內的GameObject.transform移除。

[Unity]Animation WarpMode

參考資料:Animation.wrapModeWrapMode
Unity版本:3.5.6f4

在Unity內Animation的WrapMode可以透過Script來變更。以下針對各個參數進行說明:

1.WrapMode.Default:
        直接拿Amination Clip內設定的wrapMode來進行動畫播放。預設的wrapMode為WrapMode.Once。

2.WrapMode.Once:
        當動畫時間軸到達Animation Clip終點時,正在播放中的Animation Clip會被自動的停止播放,並且時間軸會被重設回Animation Clip的一開始。

         不過當Animation Clip是從終點反向播放到起點時,雖然在播放到起點時會也會被自動停止,但是時間軸並不會被重置回終點,而是留在起點。

3.WrapMode.Loop:
        當動畫時間軸到達Animation Clip的終點時,時間軸會又回到起點的位置,並且繼續播放動畫。如果將播放模式設為反向時(即將Animation[ClipName].speed設為負值),則會從反向播放動畫,而播放的起點與終點都會跟正向播放時相反。

Note:根據官方的說法,將AnimationState.speed設為負值時,Animation Clip就會被反向播放(A negative playback speed will play the animation backwards.)。但目前測試由3dMax匯出的Animation以及使用Unity Animation所做出的Clip,在播放移動Animation時,把AnimationState.speed設為-1,播放的結果是物件直接跳到起始位置,並沒在從終點移動到起點位置。這邊還需要再確認問題點在那邊。

Note(2012/11/20):
        今找到原因了,原先測試時,只有變更AnimationState.speed,而沒有去變更AnimationState.time。所以播放時,時間軸就已經在0的位置了,也因此看不到動畫做動。如要反向播放動畫則需變更AnimationState.Speed為負值以及設定AnimationState.time不為起點。

4.WrapMode.PingPong:
        當動畫時間軸到達Animation Clip的終點時,時間軸會在往起點的方向前進。這個動畫效果會使物件重複的在Animation Clip的起點與終點之間來回的播放動畫。對於需要來回反複播放的動畫而言,就可以設定成此狀態。

5.WrapMode.ClampForever:
        當動畫時間軸到達Animation Clip的終點時,時間軸將會停止在Animaiton Clip的終點,且動畫播放狀態依然是播放中,也就是Animation不會停止Animation Clip的動畫播放。而如果設定為反向播放時,時間軸到達起點時,也一樣會停止在起點,且Animaiton Clip也是在播放中的狀態。也因此,此設定會使Animation Clip只播放一次。

        根據官方文件的說法,這個設定可以用在播放時間軸到達終點後不打算結束的Additive Animation上。根據測試的結果為,動畫物件是會停在時間軸的結束狀態下,但AnimationStates[].time還是會持續的增加或是減少(依據設定的播放時間值)。


        在Animation以及Animation Clip上都有WrapMode的屬性,而透過Script去設定時,卻有些許的不同。對於wrapMode這個屬性,在Animation本身上,是可以在播放中就去設定,而且會立即生效;但是當Animation Clip正在播放中的時後,AnimationClip.wrapMode是不能被變更的(唯讀狀態)。


以下為操作測試:
I.在Script內去變更Animation.wrapMode時,WrapMode會立即的套用在Animation Clip的播放上(如果是透過Inspector來變更,則WrapMode不會立即的套用在Animation Clip的播放上),但Animation Clip.warpMode還是保持原本的設定。

例如:Animation.wrapMode原本設定為WrapMode.Once,Animation Clip.wrapMode也設定為WrapMode.Once。在Animation.Play()之後,且Animation Clip播放完畢之前,將 Animation.wrapMode改為WrapMode.PingPong。則此時看到的動畫效果就變成來回播放,但是Animation Clip.wrapMode還是依舊為WrapMode.Once。

II.在Script內去變更Animation Clip.wrapMode時,WrapMode會立即套用到Animation Clip.wrapMode,但是並不會影響到正在播放的Animation。

例如:Animation.wrapMode原本設定為WrapMode.Once,Animation Clip.wrapMode也設定為WrapMode.Once。在Animation.Play()之後,且Animation Clip播放完畢之前,將 Animation.wrapMode改為WrapMode.PingPong。則此時看到的動畫還是播完後就停止了,但此時又再重新播放動畫的話,動畫效果還是一樣只播一次。不過在Animation Clip.wrapMode的設定上,是有被變更為WrapMode.PingPong。


例外原因:
        會出現上面的狀況是因為Animation是透過AnimationState來控制動畫的播放。根據目前的測試,在編輯模式下,AnimationStates是一個空的陣列(圖1.)。當啟用Play模式時,Animation會把在Animations內所指定的Animation Clip的name以及wrapMode新增到AnimationStates內(圖2.)(Animation Clip的設定請參考圖3.)。由這邊看出Unity看起來是在Animation初始化的時候取得AnimationClip.wrapMode,並加到AnimationState內。

圖1.編輯模式下的Animation States

圖2.Play模式下的Animation States

圖3.AnimationClip的設定

        在上述的狀況下,變更Animation Clip.wrapMode(圖4.),此時卻發現一開始加到AnimationStates的wrapMode卻沒有變更。所以由此推測,這邊的wrapMode是從AnimationClip.wrapMode複製來的,而不是取得參考。這也可以指出,為什麼在Animation沒有重新取得AnimationClip時,播放的結果總是不同於設定的值。所以之後再怎麼變更AnimacionClip.wrapMode,Animatoin也不可能知到目前指定的AnimationClip已經有任何的變化。

                   圖4.變更AnimationClip.wrapMode           圖5.[圖4.]狀態下的Animation資訊

解決方案:
i.在使用Unity Editor的模式下,僅需再重新Play Game Mode,就可以使用到變更後的WrapMode。

ii.在使用編譯後的執行檔時,有三種方法可以使用變更後的WrapMode:
     1.重新載入場景。
     2.刪除目前GameObject所持有的Animation元件,並再重新加入Animation元件與Animation Clip
        後。如要用這方法,則需在刪除Animation後的下一個Frame才可以再新增Animation元件,
        不然Unity會跳出物件還存在且不可重複加入的錯誤訊息。原因是Object.Destroy()所說的
       「物件的刪除總是在Update loop結束之後以及rendering之前發生」。
     3.直接將新的Animation Clip.wrapMode指定給Animation[Animation Clip.name].wrapMode。     

結論:
1.在Inspector修改Animation.wrapMode並不會立刻套用到目前的播放上。(AnimaitonStates不會被立即變更)

2.透過Script修改Animation.wrapMode會立即套用到所有的AnimationClip(包含目前的播放)在Animation Component內的wrapMode上。(AnimationStates會被立即變更)

3.變更過的AnimationClip.wrapMode需要Animation Component進行重載後,才會更新到AnimaitonStates。

4.播放中的Animation Clip是不能進行wrapMode的變更。

[Unity]Animation Component - Attributes

參考資料:Scripting > Runtime Classes > Animation

         跟據官方的說法,這個元件是用來做動畫播放使用。而整個動畫系統是利用「權重」的方式來進行動畫的播放。相關內容可以參考Unity Manual > Animation Scripting。底下針對Animation所提供的屬性來進行說明。

1.clip(Animation Clip)
        在沒有指定播放的clip時進行播放時,所會播放的Animation clip。即在Script內呼叫Animation.Play()時,Animation Component就會播放此組clip。在Inspector底下所看到的屬性如圖.1的紅框框選處。

圖1.Animation設定介面

2.playAutomatically:(bool)
        這個屬性是用來決定在GameObject啟動(Active)時,是否要播放預設的Animation Clip。也就是此值為true時,Animation System則會在GameObject設為啟動(Active)之後,自動播放Animation.clip的動畫內容。在Inspector底下所看到的屬性如圖.1的綠框框選處。

3.wrapMode:(WrapMode)
        此屬性是用來決定當Animation Clip播放完畢時,接下來要做何種處理。可以參考[Unity]Animation WarpMode

4.isPlaying:(bool)
        此屬性可用來判斷Animation Clip是否已經被播放完畢。當此屬性為true時,即是指定的Animation Clip還在播放中;反之為false時,則代表指定的Animation Clip已經停止播放了。

5.this[string name]:(AnimationState)
        此Indexer可以透過Animation Clip的名稱來取得其所用到的AnimationState。因此如有需要修改AnimationState的屬性時,就可以使用此屬性。說明測試也可以參考[Unity]AnimationState

6.animatePhysics:(bool)
        這個屬性是用來設定Animation播放時,會不會受到物理引擎的影響。當此屬性設為true時,Animation Clip播放時,就會被加到物理引擎內進行計算。但如要使此設定有效時,還必需先在要播放Animation Clip的GameObject上加上RigidBody,並設定成會受物理引擎影響。在Inspector底下所看到的屬性如圖1.的黃框框選處。

Note:目前測試在播放水平移動的動畫時,再加上重力影響時,高度座標的的確是有所改變。
         但其變化量比無播放動畫時的狀況還要來的小很多。

7.cullingType:(AnimationCullingType)
        跟據官的說法,當culling被起動時(也就是設定不是AnimationCullingType.AlwaysAnimate),Unity會在animation不會被使用者看到時,自動的停止AnimatoinClip的播放。因此這個設定是用來節省效能消耗。當動畫元件被culled的時候,AnimatoinState、Event或是Sample Animation(可以參考animation.sample() usage)都不會有做用。在Inspector底下所看到的屬性如圖1.的紫框框選處。(不過目前測試沒有成功的試出來。)

8.localBounds:(Bounds)
      此屬性為Animation的動畫元件(animation component)在區域座標(local space)下的Axis-aligned minimum bounding box(AABB)。跟據官方的說法,此屬性在預設的條件下,是跟據動畫狀態(animation state,也就是所附加的Animation Clip)來計算的。而使用者也可以透過重新指定數值來變更目前的localBounds。
 
      如有要數值更改回原設定值,就僅需將Animation.cullingType設定為AnimationCullingType.BasedOnClipBounds即可。在Animation.cullingType沒有設定為AnimationCullingType.BasedOnClipBounds或是AnimationCullingType.BasedonUse的時候,此屬性是沒有被定義的。然而當Animation.localBounds被設定時,系統就會自動將Animation.cullingType設定為AnimationCullingType.BasedOnUserBounds。

使用Google Code Prettify來顯示程式碼

這邊網路上可以找到不少的參考資料,但為了自己方便尋找,所以就根據參考來源,備份一份資料。

參考來源:
1.優力歐不眠夜[在 blogger 中加入 google-code-prettify]
2.Google-Code-Prettify


I.設定:
使用方式如下:
1.登入網誌後台後選擇『範本』->『修改HTML』

2.在HTML內找到</head>,並將下列程式碼貼在</head>的前面。
<link href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" rel="stylesheet" type="text/css"></link>
<script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js" type="text/javascript"></script>

3.然後在body標籤內加上onload='prettyPrint()'。
(參考資料是利用<script>prettyPrint();</script>; )

4.存檔後,就可以用了。


II.如何使用:
之後如果在文章內需要貼程式碼時,就需要在HTML模式下,加入下面的語法。
<pre class="prettyprint lang-*">
//要顯示的文字
</pre>
「*」表示要用來顯示的語言類型,定義請參考How do I specify the language of my code?


III.實作範例:
用起來的感覺會像是底下這樣(用C++作範例)
[HTML語法]
<pre class="prettyprint lang-cpp">
class MyClass
{
    private:
        int Counter;
        std::vector&lt;int&gt; mCountList;

    public:
        MyClass(void);
        
    public:
        void Show(void);
}
</pre>

[顯示畫面]
class MyClass
{
    private:
        int Counter;
        std::vector<int> mCountList;

    public:
        MyClass(void);
        
    public:
        void Show(void);
}
在要顯示的程式碼內,如果有要用到「<」、「>」,要記得,一定要換成HTML裡面用的「&lt;」及「&gt;」。不然會變成一片空白嚕。


IV.行號顯示:
如果要顯示行號的話,就要在原本的lang後面加上linenums即可。
[HTML碼]
<pre class="prettyprint lang-cpp linenums">
class MyClass
{
    private:
        int Counter;
        
    public:
        MyClass(void);
        
    public:
        void Show(void);
}
</pre>

[顯示畫面]
class MyClass
{
    private:
        int Counter;
        std::vector<int> mCountList;

    public:
        MyClass(void);
        
    public:
        void Show(void);
}


如果在顯示區間內所顯示的程式碼是從原先的程式碼的第100行開始,就可以在linenums後面加上分號以及開頭的行號數值,這樣prettyprint就會把目前這段程式碼應該所在的行號標出來了。
[HTML碼]
<pre class="prettyprint lang-cpp linenums:100">
class MyClass
{
    private:
        int Counter;
        
    public:
        MyClass(void);
        
    public:
        void Show(void);
}
</pre>

[顯示畫面]
class MyClass
{
    private:
        int Counter;
        std::vector<int> mCountList;

    public:
        MyClass(void);
        
    public:
        void Show(void);
}

不過目前google code prettify在顯示行號上,就只會顯示(行號 Mod 5 == 0 &&行號 > 0)的行數的行號嚕。


雖然用起來有點麻煩,但是顯示上看起來還算可以嚕。
如果覺得上面的方法太麻煩,還有現成的網頁工具可以用,Source Code Formatter for Blogger, Blogspot , Blog & Blogging, Format Formatting Tool
好處是,他可以幫你解決符號轉換的問題,也可以顯示每行的行號,缺點是,就沒有顏色了。XD

[C++, C#]class之間的callback

最近在工作上有看到比較好的方法,所以就在這邊記錄起來。
這邊的作法,就是利用繼承的方式,來讓callback的介面,可以傳遞到下一層的類別內。

[C++]
1.先建立要用來當通知器的介面
//用來Callback用的通知器
class INotifier
{
//要用來Callback的介面
    public:
        virtual void NoReturnFunc(void)  = 0;
        virtual bool BoolReturnFunc(void) = 0;
        virtual void PassValFunc(int Val) = 0;
}

2.建立要用來操作的類別
<head file>
class COperator
{ 
    private:
        INotifier mNotifyTarget;   //被通知的對象

    public:
        COperator(INotifier NotifyTarget); //建構子
}

2.1.這邊的範例是建立操作物件時,就順便指定被通知的對象。
<cpp>
COperator::COperator(INotifier NotifyTarget)
{
    this->mNotifyTarget = NotifyTarget;

    if( this->mNotifyTarget != NULL )
        this->mNotifyTarget->NoReturnFunc();
}

3.建立被通知的對象,被通知的對象需要繼承通知介面。
<head file>
class CReceiver : public INotifier
{
    private:
        COperator *mOperator;

    public:
        CReceiver(void);
  
//繼承來的介面,內容要自行實做
    public:
        virtual void NoReturnFunc(void);
        virtual bool BoolReturnFunc(void);
        virtual void PassValFunc(int Val);
}

3.1.這邊是在被通知對象被建立時,就把自己塞給操作物件。
<cpp>
CReceiver::CReceiver(void)
{
    this->mOperator = new COperator(this);
}

之後,COperator就可以透過INotifier所提供的介面,把事件回傳給CReceiver了。

[C#]
在C#底下,要做這件事情就變得比較簡單了。一開始要先在操作物件內先宣告要用來當事件的函式。
public class COperator
{
//使用委派宣告一個函式介面
    public delegate void OnNoReturnFuncEvent();
 
//宣告此介面為一個事件
    public event OnNoReturnFuncEvent NoReturnFuncNotifier = null;
  
//要做callback事件處理的函式
    void OperatingFunc()
    {
        if(this.NoReturnFuncNotifier != null)
            this.NoReturnFuncNotifier();
    }
}

之後就在要被通知的對象內,將自己要用來作回呼的函式,加到事件內。
這樣的作法,可以添加複數個事件,也就是可以有2個以上的物件將自己的回呼介面,加到這個事件內。
而當事件發生的時候,這些有加入事件的物件,都會依序收到同樣的事件通知。
public class Receiver
{
//宣告操作物件
    private COperator mOperator = new COperator();

    public Receiver()
    {
    //把自已的callback介面加到操作對象去
        this.mOperator.NoReturnFuncNotifier += this.OnNoReturnFucn;
    }

    //這邊的介面宣告要與COperator所宣告的委派函式介面一樣
    public void OnNoReturnFucn()
    {
        //做要做的事情
    }
}

[Eclipse]安裝Android Develop Tools

關於Elipse安裝ADT的教學,在Google上還蠻多的。但為了自己找資料方便,所以就乾脆自己寫一份,這樣之後忘記的時候,還有的地方可以找。

1.選擇Help->Install New Software。



 2.在「Work with:」處,輸入http://dl-ssl.google.com/android/eclipse/site.xml後。
    在這邊可以按下Add,把這個路徑加到「Available Software Sites」裡,以方便之後的更新使用。


3.在輸入完路徑之後,Eclipse的Installer就會開始向遠端主機取得相關的軟體資訊。這邊目前沒有研究個個項目的功能,所以就一併都下載了。(網路上的教學大部分都只說下載前兩項即可)


 4.確認項目是否正確,一樣就按「Next」即可。

5.按下接受授權項目。

6.下載中...

8.下載完成後,會選擇Andorid SDK的取得方式。由於之前為了Unity已經有獨立安裝Android SDK了,所以這邊就選擇已經存在的SDK的資料夾。如先前沒安裝過的,就可以選「Install new SDK」。

就這樣,Android ADT就裝好了。接下來就看要自己要玩些什麼嚕。

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...