本教程適合初學者(學習經歷已有30天的UE4初學者)。
最終效果
由於隱私保護,不想截實際的效果圖,下面給出了示意圖,左邊是背包A,右邊是背包B,將其中的子項目從左側拖往右側的背包,然后在插入位置放置。
第一步:
制作一個user widget(在內容瀏覽器中右鍵-ui widget-user widget),命名為subwidget_singleitem,這個用作單個物品項目
制作兩個user widget,分別作為A和B背包,命名隨意。都要向其中聲明一個Scrollbox,關於Scrollbox的基本樣式設計,可以查看UE4官網,這里不是重點。你可以往Scrollbox里面添加上面的subwidget_singleitem(只需要在palette中鍵入subwidget_singleitem就可以看到自定義的userwidget),但是這里不這樣做。注意是兩個背包都這樣建立。
第二步:初始化一些物品,這些物品(就是上面建立的singleitem)需要有相互辨識度,不然你看不清楚最終的效果是不是合理的。
比如我這里的是生成編號為10到40的物品(注意這里的編號的使用需要自己定義,你應該去了解一下expose-on-spawn的概念,就會知道是怎么做的了)。
這里有一個Scrollbox的語法:Scrollbox->addchild()表示添加單個項目。
背包A和B都這樣做,就會有這個效果:
就是沒有拖動的靜態背包。
第三步【關鍵】:
在單個項目(subwidget_singleitem)中重載onmousebuttondown事件(下面的截圖中由於我已經重載了,所以在列表中看不到):
這個函數表示當鼠標按下(subwidget_singleitem)時觸發的事情,內容如下:
Detectdragifpressed表示監測是否有拖動現象(針對鼠標左鍵),將事件監測結果返回出去。
第四步:
在內容瀏覽器中右鍵創建藍圖(選擇DragAndDrop):
雙擊打開,什么都不用改,只需要改動其中的pivot為centercenter即可:
這里表示拖拽時顯示的樣式將會以centercenter(水平居中和垂直居中於鼠標位置)呈現,效果類似於:
可以看到圖標中心位於鼠標處。
當然,我們Windows的拖拽風格不是centercenter,而是mousedown(在鼠標點擊處):
其它樣式你可以自己探索一下,在完成了本教程之后。
第五步:
【警告:不要只看圖不看字,理解概念很重要!】
在singleitem中重載另一個事件ondragdetected,表示當有拖拽被檢測到時,執行如下過程:
紅色標記處選擇你剛剛新建的DragAndDrop。Payload表示過路費,也就是拖拽后拖拽源(也就是A背包,在本例中)將會損失這一個物件(自動得就消逝了,不用做removefromparent的處理)。Defaultdragvisual表示拖動時拖動顯示物的樣式,也就是黏着在鼠標上的那個圖標,這里也是用self(也就是此singleitem本身)。
其它參數先不管,然后返回一個DragAndDropOperation操作出去。
第六步:
在背包B中重載ondrop事件(如果不記得怎么找重載函數頭請翻到前文看看):
這個事件表示當B背包被drop(拖拽的最后一個瞬間,翻譯為釋放)時調用,這里看到從operation接受到的拖拽操作中,取出payload,然后添加到本地的Scrollbox中(這里的addnewitemat和getfocusindexnow是我自己寫的函數)。
難點:由於UE4本身沒有實現將物品按照鼠標位置所在處插入,所以需要自己實現!
獲得當前屏幕位置-》用“my geometry我的幾何”翻譯這個物理屏幕位置,得到本地位置(本地位置是指游戲窗口里的本地位置,是一個和窗體大小、和窗體所處物理屏幕的位置無關的一個位置值,是代碼內友好的Position)-》用這個本地位置獲得鼠標所在處的排列序號(就是我應該插入到哪個序號上),最后四舍五入后添加物品到這個位置上即可(addnewitemat)。
第七步(解釋getfocusindexnow):
理論解釋:
上圖中的箭頭處就是鼠標最終落腳處。
以下列出一個方程組計算排序序列號和當前鼠標位置的關系表達式:
當前鼠標本地位置(Local Position) = 當前鼠標的絕對位置 經過窗體幾何的absolute_local轉化,即前面提到的:
當前鼠標本地位置 - Scrollbox在帆布上的偏移位置(下圖中的紅色箭頭的長度) = 鼠標相對Scrollbox頂的位置(這個應該很好理解吧!)
鼠標相對Scrollbox頂的位置 + Scrollbox的拉動偏移(拉動偏移是指這個Scrollbox被拉拽了多少) = 鼠標相對Scrollbox的首個物件的理論位置的距離H,即下圖中的紅色箭頭的長度:
上述的H值 ÷ 單個singleitem的高度 = 當前鼠標位置的序列號(類型為小數,將其四舍五入即可)
最終的getfocusindexnow的表達式為:
其中涉及的節點也都在里面可以看到了。
第八步(解釋):
Addnewitemat在Scrollbox中也沒有現成的函數,下圖是我的實現,大致的意思是:
這個序列號大於當前的物品數嗎,是的話,就直接添加一個child即可。
否的話,就取出Scrollbox中所有的物品,然后insert這個物品(以數組insert的形式實現),清空Scrollbox然后再放置到Scrollbox中。
以上就是完成從A背包拖拽物品到B背包的所有步驟。如果你對其中的操作和函數節點尋找有問題,可以多查查UE4官網上的文檔。
——2017年7月8日10:58:01 小江村兒的文傑