1、介紹
我們都知道ue裏面使用輸入時,都是在PlayerController裏面進行獲取,
使用官方的操作映射,軸映射,以及目前最新的增强型輸入
但是我們發現了一個問題 那就是輸入會被消耗
就是儅我鼠標按在一個按鈕上時 你另一個地方接受不到此次的輸入
你會覺得很奇怪,我也覺得很奇怪
現在我們需要一個功能 那就是游戲的全局中 我鼠標點擊一下就會有特效
這該怎麽辦呢 一開始我覺得簡單 推送一個監聽事件 監控這所以輸入就好了
但是似乎有問題 他會被按鈕控件這些給消耗掉輸入 我們猜想他應該第一個接受到輸入才對啊
所以現在我們需要能第一個接受到輸入的地方
ue裏面似乎已經有了
class IInputProcessor 類
2、大致調用流程
ue似乎是在此處集中處理輸入的
我們從
UE_5.0\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsApplication.cpp
int32 FWindowsApplication::ProcessDeferredMessage( const FDeferredWindowsMessage& DeferredMessage ) 函數開始看起
我們就看按鍵按下時 2218行
MessageHandler->OnMouseDown( CurrentNativeEventWindowPtr, MouseButton, CursorPos );
MessageHandler 是FGenericApplicationMessageHandler類型的 一個 共享指針
FGenericApplicationMessageHandler 内部基本都是虛函數 一看是虛函數我們就應該知道 他主要是看子類來實現的了
FSlateApplication 類是一個繼承自 FGenericApplicationMessageHandler
Slate ue自己封裝的一個UI框架(大概 我不是很懂 我目前只是做筆記狀態
我們看到他將OnMouseDown虛函數重寫了
我們看到這裏繼續傳遞 還傳遞了一個Lambda函數 使用參數類型為
IInputProcessor 進行調用 IInputProcessor::HandleMouseButtonDownEvent
這裏我們注意到了 調用返回了一個返回值 bool 類型
為true就跳出 不再往下循環調用的 IInputProcessor 的事件了
這裏意味著什麽呢?我們只要能將我們自己IInputProcessor類加入 InputPreProcessorList 中 我們就有機會是第一時間處理輸入的
最後也是返回這個 返回值
我們的 IInputProcessor
好了現在我們需要看看調用最初的位置了
假如我們這裏返回true了就跳出了 不在向下執行了
我們看看下面是什麽
我們似乎看到了一個眼熟的東西
InMouseCaptorWidget.Widget->OnPreviewMouseButtonDown(InMouseCaptorWidget.Geometry, Event);
OnPreviewMouseButtonDown函數
我們似乎在UserWidget裏面也看到過
但是這裏的這個是 SWidget裏面的
是個虛函數 所以現在我們要有一個猜想 UserWidget是否是繼承這個SWidget的?
很可惜並沒有
但是我找到了另一個東西
SObjectWidget 有繼承 SWidget 且重寫了這個函數
WidgetObject
看到了是什麽呢? 是UserWidget !!!
我們找到了
現在看到他傳遞過來了
所以我們在 IInputProcessor 中處理輸入一定比UI快一步拿到
我們看到鼠標點擊和觸摸點擊是同時處理的
流程大概我也只會這裏了
3、使用自己定義的 IInputProcessor 進行處理輸入
首先先定義一個繼承 IInputProcessor 類的類型 FInputHelp_Ysp
然後將所以 IInputProcessor 中 的虛函數全部重寫 且全返回為false
爲何返回false? 看這裏 爲了不住儅向下處理
比如我們想處理鼠標按鍵事件
首先我們使用DECLARE_DELEGATE_OneParam 宏 靜態單播代理
DECLARE_DELEGATE_OneParam(FOnInputProcessorMouseButtonEvent, const FPointerEvent&);
`bool FInputHelp_Ysp::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent)
{
OnInputMouseButtonEvent.ExecuteIfBound(MouseEvent);
GEngine->AddOnScreenDebugMessage(-1, 2, FColor::Blue, MouseEvent.GetEffectingButton().ToString());
return false;
}`
ok 這樣這個類就寫完了
現在我們造一個 **APlayerController **類
ASMPlayerController類
`void ASMPlayerController::BeginPlay()
{
Super::BeginPlay();
InputHelp = MakeShareable(new FInputHelp_Ysp());
//注册输入
if (InputHelp)
{
FSlateApplication::Get().RegisterInputPreProcessor(InputHelp);
FPointerEvent MouseEvent;
//绑定鼠标或触摸按下/抬起
InputHelp->OnInputMouseButtonEvent.BindLambda(//this,
[this](const FPointerEvent& MouseEvent)
{
GEngine->AddOnScreenDebugMessage(-1, 2, FColor::Red, MouseEvent.GetEffectingButton().ToString());
this->MouseBottonEvent(MouseEvent);
}
);// BindUObject(this, &ASMPlayerController::MouseBottonEvent);
//绑定鼠标/触摸 移动
InputHelp->OnInputMouseMoveEvent.BindLambda(
[this](const FPointerEvent& MouseEvent)
{
GEngine->AddOnScreenDebugMessage(-1, 2, FColor::Red, MouseEvent.GetScreenSpacePosition().ToString());
this->MouseMoveEvent(MouseEvent);
}
);
}
}`
*MakeShareable **函數幹嘛的呢?
說是一個共享指針包裝器
可以容納一個對象的指針
TSharedPtr<FInputHelp_Ysp> InputHelp;
總得來説就是爲了將普通轉換成共享指針的
我們還需要取消注冊
你們可能好奇我爲什麽不使用動態單播
因爲我寫的那個 **FInputHelp_Ysp **用不了
我猜想應該是我沒有使用到反射 ue 有個反射頭文件 不太清楚 也可能是沒有繼承UObject
4、藍圖方面
在重寫函數裏面找到我們所寫的 MosueBottonEvent 函數
然後從中處理邏輯就好
比如跟隨鼠標 移動一張圖片
好了述説解釋
個反射頭文件 不太清楚 也可能是沒有繼承UObject
好了述説結束
知乎大佬
https://zhuanlan.zhihu.com/p/336178531