深入解析UE4点选机制

摘要

在UE开发中,情景浏览和物件选取常用,需同步更改工具页面。最近学习副本和蓝图编辑器的Viewport编码,深感逻辑性重要。在文件目录中寻找必要代码,点Actor拖AxisBlueprint…感觉如探宝!

正文

在UE软件开发设计中,常常会使用情景浏览对话框的作用,也常常会有点儿选情景里的物件而同歩更改专用工具页面的要求,在网上实例教程多见解读怎么打开一个浏览页面。在近期的一次要求开发设计中,我浅读了副本在线编辑器和宏伟蓝图在线编辑器的Viewport编码,从这当中挑选出了选中的有关逻辑性,文中纪录了一个源代码中找寻必须作用的全过程。

文件目录
  • LevelEditor
    • 点一下Actor
    • 拖动Axis
  • BlueprintEditor
  • 汇总

LevelEditor

点一下Actor

作用:副本在线编辑器下的选中Actor

有关的类(主要是LevelEditor控制模块):

1、FLevelEditorViewportClient、FEditorViewportClient

2、LevelViewportClickedHandlers

3、SLevelViewport

4、UUnrealEdEngine(依靠控制模块UnrealEd)

重现方法:在FLevelEditorViewportClient的InputKey方式 下切断点随后进来看启用栈

virtual bool InputKey(FViewport* Viewport, int32 ControllerId, FKey Key, EInputEvent Event, float AmountDepressed = 1.f, bool bGamepad=false) override;

他的启用栈如下图:

能够见到他是在解决一个MouseButtonDown的事情,UE的功能键事情遵循一个岗位职责链的策略模式,由顶层的SViewport(我猜想是全部UE的Viewport,沒有去考资格证书)先开展解决,随后一路传送到下边的派生类FLevelEditorViewportClient,启用到InputKey

随后这一InputKey干了许多 的事儿,包含:测算click的location,检验有别的的功能键按住(Alt Ctrl),也有一些解决阳光照射和空气的编码(这种做移殖的情况下能够删除),较为重要的是他正中间启用了父类的InputKey

bool bHandled = FEditorViewportClient::InputKey(InViewport,ControllerId,Key,Event,AmountDepressed,bGamepad);

父类做的事儿也许多 ,但最重要的或是他启用ProcessClickInViewport涵数,这一涵数组出了一个HHitProxy目标,这一涵数內部启用到ProcessClick,ProcessClick又被FLevelEditorViewportClient调用了,因而点一下编码关键便是调用InputKey和调用ProcessClick涵数

一个HHitJProxy目标里包含了选中的是哪一个Actor,选中了他的哪一个Component

在线编辑器能够依据点一下实际操作的不一样(双击鼠标、按着Alt点一下等)去让页面做相匹配的转变,例如在宏伟蓝图在线编辑器下就只表明Comp被选定的轮廊,在副本在线编辑器下便是优先选择选定Actor,假如这一Actor有父Actor那麼会优先选择选定父Actor这类的,这就是ProcessClick涵数里应当做的事儿。

他最先是分辨选定是一个什么目标(WidgetAxis、Actor、xxxVert这些),大家关心的主要是假如他是一个Actor,那麼在移殖的情况下有一些多余的支系就都能够删除了(WidgetAxis不要动,好像是选定纵坐标的)

在Actor相关的逻辑性里他例举了假如要选定Comp的好多个标准:

// We want to process the click on the component only if:
// 1. The actor clicked is already selected
// 2. The actor selected is the only actor selected
// 3. The actor selected is blueprintable
// 4. No components are already selected and the click was a double click
// 5. OR, a component is already selected and the click was NOT a double click
const bool bActorAlreadySelectedExclusively = GEditor->GetSelectedActors()->IsSelected(ConsideredActor) && (GEditor->GetSelectedActorCount() == 1);
const bool bActorIsBlueprintable = FKismetEditorUtilities::CanCreateBlueprintOfClass(ConsideredActor->GetClass());
const bool bComponentAlreadySelected = GEditor->GetSelectedComponentCount() > 0;
const bool bWasDoubleClick = (Click.GetEvent() == IE_DoubleClick);
const bool bSelectComponent = bActorAlreadySelectedExclusively && bActorIsBlueprintable && (bComponentAlreadySelected != bWasDoubleClick);
if (bSelectComponent)
{
	LevelViewportClickHandlers::ClickComponent(this, ActorHitProxy, Click);
}
else
{
	LevelViewportClickHandlers::ClickActor(this, ConsideredActor, Click, true);
}

LevelViewportClickHandlers是一个类名,这方面编码有一些涵数沒有xx_API,表明沒有dll导出来,并不是对别的控制模块公布的,因而能够将其內部的重要涵数完成抄出去产生自身的版本号

别的的error,一般引入库函数 加上控制模块依靠就可以处理

当ActorSelection有变化的情况下,一般会做一些事情广播节目,能够完成一些本来被选定的物件收到事情撤销选定的外轮廊这些的实际效果,这方面的编码的部位非常复杂,在LevelEditor中,他享有的工资待遇非常好,立即给写到UnrealEdEngine里

void UUnrealEdEngine::UpdateFloatingPropertyWindowsFromActorList(const TArray<UObject*>& ActorList, bool bForceRefresh)
{
   FLevelEditorModule& LevelEditor = FModuleManager::LoadModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));

   LevelEditor.BroadcastActorSelectionChanged(ActorList, bForceRefresh);
}

能够见到他实际上便是把一个Actor二维数组传进去随后更新一下

但大家的工资待遇就没那么好啦,必须自身手动式调一下这一事情,我选择将其加上刚抄出去的类名下的ClickActorSelectActor的后边

TArray<UObject*> Objects;
Objects.Add(Actor);
FModelShapeEditorModule::BroadcastActorSelectionChanged(Objects);

这儿我说了静态函数来做这件事情

副本在线编辑器他在这一控制模块的完成类上申请注册了一个OnActorSelectionChanged,用以同歩ActorDetail控制面板的转变(要是没有能够除掉这一段)

void SLevelEditor::OnActorSelectionChanged(const TArray<UObject*>& NewSelection, bool bForceRefresh)
{
   for( auto It = AllActorDetailPanels.CreateIterator(); It;   It )
   {
      TSharedPtr<SActorDetails> ActorDetails = It->Pin();
      if( ActorDetails.IsValid() )
      {
         ActorDetails->SetObjects(NewSelection, bForceRefresh || bNeedsRefresh);
      }
      else
      {
         // remove stray entries here
      }
   }
   bNeedsRefresh = false;
}

在SLevelViewport里他申请注册了一个同名的涵数,随后里边承担改动ViewportClient里的EngineShowFlags,SetSelectionOutline和选定的外轮廊相关,这方面必须改动改动抄过来

void SLevelViewport::OnActorSelectionChanged(const TArray<UObject*>& NewSelection, bool bForceRefresh)
{
   // On the first actor selection after entering Game View, enable the selection show flag
   if (IsVisible() && IsInGameView() && NewSelection.Num() != 0)
   {
      if( LevelViewportClient->bAlwaysShowModeWidgetAfterSelectionChanges )
      {
         LevelViewportClient->EngineShowFlags.SetModeWidgets(true);
      }
      LevelViewportClient->EngineShowFlags.SetSelection(true);
      LevelViewportClient->EngineShowFlags.SetSelectionOutline(GetDefault<ULevelEditorViewportSettings>()->bUseSelectionOutline);
   }

   bNeedToUpdatePreviews = true;
}

把两个核心的涵数及其授权委托完成了,大部分就可以选定Actor了,而且能够有外轮廊,按住w键能够表明纵坐标

可是这时拖动纵坐标还不可以更改物件在world中的部位,还必须调用许多 涵数

拖动Axis

作用:拖动Axis,更改他在world中的部位

必须调用或拷贝的涵数

virtual bool InputAxis(FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad) override;
virtual void TrackingStarted( const struct FInputEventState& InInputState, bool bIsDraggingWidget, bool bNudge ) override;
virtual void TrackingStopped() override;
virtual void Tick(float DeltaSeconds) override;
/** Project the specified actors into the world according to the current drag parameters */
void ProjectActorsIntoWorld(const TArray<AActor*>& Actors, FViewport* Viewport, const FVector& Drag, const FRotator& Rot);
virtual bool InputWidgetDelta( FViewport* Viewport, EAxisList::Type CurrentAxis, FVector& Drag, FRotator& Rot, FVector& Scale ) override;
void ApplyDeltaToActor( AActor* InActor, const FVector& InDeltaDrag, const FRotator& InDeltaRot, const FVector& InDeltaScale );
void ApplyDeltaToActors( const FVector& InDrag, const FRotator& InRot, const FVector& InScale );
void ApplyDeltaToComponent(USceneComponent* InComponent, const FVector& InDeltaDrag, const FRotator& InDeltaRot, const FVector& InDeltaScale);
/** Helper functions for ApplyDeltaTo* functions - modifies scale based on grid settings */
void ModifyScale( AActor* InActor, FVector& ScaleDelta, bool bCheckSmallExtent = false ) const;
/**
* Helper function for ApplyDeltaTo* functions - modifies scale based on grid settings.
* Currently public so it can be re-used in FEdModeBlueprint.
*/
void ModifyScale( USceneComponent* InComponent, FVector& ScaleDelta ) const;
void ValidateScale(const FVector& InOriginalPreDragScale, const FVector& CurrentScale, const FVector& BoxExtent,
	                   FVector& ScaleDelta, bool bCheckSmallExtent = false) const;	                   	
/** @return	Returns true if the delta tracker was used to modify any selected actors or BSP.  Must be called before EndTracking(). */
bool HaveSelectedObjectsBeenChanged() const;

或是和以前一样的构思,可是必须留意,如果有相匹配的父类涵数,一般都启用一下,涵数中涉及到的自变量也需要一并摘取自身的版本号,在Tracking涵数里使用了许多自变量

private:
	FTrackingTransaction TrackingTransaction;
	/** A map of actor locations before a drag operation */
	mutable TMap<TWeakObjectPtr<AActor>, FTransform> PreDragActorTransforms;

BlueprintEditor

作用:点一下宏伟蓝图类下边的Comp

有关类:

1、SSCSEditorViewport

2、FBlueprintEditor

3、SListView

4、SSCSEditor

这儿也不一步一步写了,由于因为我沒有仔细观看

留意的点,粗看是点击事件先由TreeWidget接纳回应,随后把viewport里的3D渲染回应关联到ListView的OnSelectionChange上(指每一个UI条目地选定)

汇总

抄源代码作用汇总就一句话——多退少补

兰芳

2021.8.11

关注不迷路

扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!

温馨提示:如果您访问和下载本站资源,表示您已同意只将下载文件用于研究、学习而非其他用途。
文章版权声明 1、本网站名称:宇凡盒子
2、本站文章未经许可,禁止转载!
3、如果文章内容介绍中无特别注明,本网站压缩包解压需要密码统一是:yufanbox.com
4、本站仅供资源信息交流学习,不保证资源的可用及完整性,不提供安装使用及技术服务。点此了解
5、如果您发现本站分享的资源侵犯了您的权益,请及时通知我们,我们会在接到通知后及时处理!提交入口
0

评论0

请先

站点公告

🚀 【宇凡盒子】全网资源库转储中心

👉 注册即送VIP权限👈

👻 全站资源免费下载✅,欢迎注册!

记得 【收藏】+【关注】 谢谢!~~~

立即注册
没有账号?注册  忘记密码?

社交账号快速登录