ブルヌプリント゚ディタヌを䜿甚しおレベルごずにオブゞェクトを配眮するためのシステムを䜜成する

画像



こんにちは、私の名前はドミトリヌです。 私は趣味ずしおアンリアル゚ンゞンでコンピュヌタヌゲヌムを䜜っおいたす。 私のプロゞェクトでは、プロシヌゞャ生成レベルを開発しおいたす。 私のアルゎリズムは、空間内のポむントルヌトを「ルヌト」ず呌びたすを明確な順序で配眮し、その埌、これらのポむントにメッシュをアタッチしたす。 しかし、ここでは、最初からメッシュをアタッチし、プロゞェクトをコンパむルする必芁があるずいう問題が発生したす。その埌、それがどのように発生したかを確認できたす。 ゚ディタりィンドりからVSりィンドりぞず非垞に長い間継続的に実行するのが自然です。 そしお、このためにブルヌプリント゚ディタを䜿甚するこずが可胜になるず思いたした。レベルごずのオブゞェクトの配眮がブルヌプリントを介しお実装されるDungeon architectプラグむンに目を向けるほど。 実際、ここでは、最初の図にスクリヌンショットを瀺した同様のシステムの䜜成に぀いお説明したす。





そのため、最初から独自のファむルタむプを䜜成したす詳现に぀いおは、この蚘事を参照しおください 。 AssetActionクラスでは、OpenAssetEditor関数を再定矩したす。

void FMyObjectAssetAction::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor) { const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) { UMyObject* PropData = Cast<UMyObject>(*ObjIt); if (PropData) { TSharedRef<FCustAssetEditor> NewCustEditor(new FCustAssetEditor()); NewCustEditor->InitCustAssetEditor(Mode, EditWithinLevelEditor, PropData); } } }
      
      







このファむルを開こうずするず、通垞のりィンドりではなく、FCustAssetEditorクラスで定矩するりィンドりが開きたす。

 class FCustAssetEditor : public FAssetEditorToolkit, public FNotifyHook { public: ~FCustAssetEditor(); // IToolkit interface virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override; virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override; // FAssetEditorToolkit virtual FName GetToolkitFName() const override; virtual FText GetBaseToolkitName() const override; virtual FLinearColor GetWorldCentricTabColorScale() const override; virtual FString GetWorldCentricTabPrefix() const override; void InitCustAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UMyObject* PropData); int N; protected: void OnGraphChanged(const FEdGraphEditAction& Action); void SelectAllNodes(); bool CanSelectAllNodes() const; void DeleteSelectedNodes(); bool CanDeleteNode(class UEdGraphNode* Node); bool CanDeleteNodes() const; void DeleteNodes(const TArray<class UEdGraphNode*>& NodesToDelete); void CopySelectedNodes(); bool CanCopyNodes() const; void PasteNodes(); void PasteNodesHere(const FVector2D& Location); bool CanPasteNodes() const; void CutSelectedNodes(); bool CanCutNodes() const; void DuplicateNodes(); bool CanDuplicateNodes() const; void DeleteSelectedDuplicatableNodes(); /** Called when the selection changes in the GraphEditor */ void OnSelectedNodesChanged(const TSet<class UObject*>& NewSelection); /** Called when a node is double clicked */ void OnNodeDoubleClicked(class UEdGraphNode* Node); void ShowMessage(); TSharedRef<class SGraphEditor> CreateGraphEditorWidget(UEdGraph* InGraph); TSharedPtr<SGraphEditor> GraphEditor; TSharedPtr<FUICommandList> GraphEditorCommands; TSharedPtr<IDetailsView> PropertyEditor; UMyObject* PropBeingEdited; TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args); FDelegateHandle OnGraphChangedDelegateHandle; TSharedPtr<FExtender> ToolbarExtender; TSharedPtr<FUICommandList> MyToolBarCommands; bool bGraphStateChanged; void AddToolbarExtension(FToolBarBuilder &builder); };
      
      





このクラスで最も重芁なメ゜ッドはInitCustAssetEditorです。 以䞋に説明するように、このメ゜ッドは最初に新しい゚ディタヌを䜜成し、次に2぀の新しい空のタブを䜜成したす。

 const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("CustomEditor_Layout") ->AddArea ( FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f) ->SetHideTabWell(true) ->AddTab(GetToolbarTabId(), ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(0.2f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.8f) ->SetHideTabWell(true) ->AddTab(FCustomEditorTabs::ViewportID, ETabState::OpenedTab) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.2f) ->SetHideTabWell(true) ->AddTab(FCustomEditorTabs::DetailsID, ETabState::OpenedTab) ) ) );
      
      





これらのタブの1぀はbluetooth゚ディタヌのタブであり、2番目のタブはノヌドのプロパティを衚瀺するために必芁です。 実際にはタブが䜜成されたすので、䜕かを埋める必芁がありたす。 RegisterTabSpawnersメ゜ッドの内容でタブを塗り぀ぶしたす

 void FCustAssetEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) { WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(FText::FromString("Custom Editor")); auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); FAssetEditorToolkit::RegisterTabSpawners(TabManager); TabManager->RegisterTabSpawner(FCustomEditorTabs::ViewportID, FOnSpawnTab::CreateSP(this, &FCustAssetEditor::SpawnTab_Viewport)) .SetDisplayName(FText::FromString("Viewport")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports")); TabManager->RegisterTabSpawner(FCustomEditorTabs::DetailsID, FOnSpawnTab::CreateSP(this, &FCustAssetEditor::SpawnTab_Details)) .SetDisplayName(FText::FromString("Details")) .SetGroup(WorkspaceMenuCategoryRef) .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details")); } TSharedRef<SDockTab> FCustAssetEditor::SpawnTab_Viewport(const FSpawnTabArgs& Args) { return SNew(SDockTab) .Label(FText::FromString("Mesh Graph")) .TabColorScale(GetTabColorScale()) [ GraphEditor.ToSharedRef() ]; } TSharedRef<SDockTab> FCustAssetEditor::SpawnTab_Details(const FSpawnTabArgs& Args) { FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor"); const FDetailsViewArgs DetailsViewArgs(false, false, true, FDetailsViewArgs::HideNameArea, true, this); TSharedRef<IDetailsView> PropertyEditorRef = PropertyEditorModule.CreateDetailView(DetailsViewArgs); PropertyEditor = PropertyEditorRef; // Spawn the tab return SNew(SDockTab) .Label(FText::FromString("Details")) [ PropertyEditorRef ]; }
      
      





プロパティパネルは私たちの暙準に適しおいたすが、bluprin゚ディタヌは独自に䜜成したす。 CreateGraphEditorWidgetメ゜ッドで䜜成されたす。

 TSharedRef<SGraphEditor> FCustAssetEditor::CreateGraphEditorWidget(UEdGraph* InGraph) { // Create the appearance info FGraphAppearanceInfo AppearanceInfo; AppearanceInfo.CornerText = FText::FromString("Mesh tree Editor"); GraphEditorCommands = MakeShareable(new FUICommandList); { GraphEditorCommands->MapAction(FGenericCommands::Get().SelectAll, FExecuteAction::CreateSP(this, &FCustAssetEditor::SelectAllNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanSelectAllNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Delete, FExecuteAction::CreateSP(this, &FCustAssetEditor::DeleteSelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanDeleteNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Copy, FExecuteAction::CreateSP(this, &FCustAssetEditor::CopySelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanCopyNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Paste, FExecuteAction::CreateSP(this, &FCustAssetEditor::PasteNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanPasteNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Cut, FExecuteAction::CreateSP(this, &FCustAssetEditor::CutSelectedNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanCutNodes) ); GraphEditorCommands->MapAction(FGenericCommands::Get().Duplicate, FExecuteAction::CreateSP(this, &FCustAssetEditor::DuplicateNodes), FCanExecuteAction::CreateSP(this, &FCustAssetEditor::CanDuplicateNodes) ); } SGraphEditor::FGraphEditorEvents InEvents; InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FCustAssetEditor::OnSelectedNodesChanged); InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FCustAssetEditor::OnNodeDoubleClicked); TSharedRef<SGraphEditor> _GraphEditor = SNew(SGraphEditor) .AdditionalCommands(GraphEditorCommands) .Appearance(AppearanceInfo) .GraphToEdit(InGraph) .GraphEvents(InEvents) ; return _GraphEditor; }
      
      





ここでは、最初から、゚ディタヌが応答するアクションずむベントが決定され、゚ディタヌのりィゞェット自䜓が䜜成されたす。 最も興味深いパラメヌタヌは.GraphToEditInGraphであり、ポむンタヌをUEdGraphSchema_CustomEditorクラスに枡したす。

 UCLASS() class UEdGraphSchema_CustomEditor : public UEdGraphSchema { GENERATED_UCLASS_BODY() // Begin EdGraphSchema interface virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; virtual void GetContextMenuActions(const UEdGraph* CurrentGraph, const UEdGraphNode* InGraphNode, const UEdGraphPin* InGraphPin, FMenuBuilder* MenuBuilder, bool bIsDebugging) const override; virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override; virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override; virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override; virtual bool ShouldHidePinDefaultValue(UEdGraphPin* Pin) const override; // End EdGraphSchema interface };
      
      





このクラスは、゚ディタヌのコンテキストメニュヌ項目などを定矩し、ノヌドの接続方法などを定矩したす。 私たちにずっお最も重芁なこずは、独自のノヌドを䜜成できるこずです。 これは、GetGraphContextActionsメ゜ッドで行われたす。

 void UEdGraphSchema_CustomEditor::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const { FFormatNamedArguments Args; const FName AttrName("Attributes"); Args.Add(TEXT("Attribute"), FText::FromName(AttrName)); const UEdGraphPin* FromPin = ContextMenuBuilder.FromPin; const UEdGraph* Graph = ContextMenuBuilder.CurrentGraph; TArray<TSharedPtr<FEdGraphSchemaAction> > Actions; CustomSchemaUtils::AddAction<URootNode>(TEXT("Add Root Node"), TEXT("Add root node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<UBranchNode>(TEXT("Add Brunch Node"), TEXT("Add brunch node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<URuleNode>(TEXT("Add Rule Node"), TEXT("Add ruleh node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); CustomSchemaUtils::AddAction<USwitcherNode>(TEXT("Add Switch Node"), TEXT("Add switch node to the prop graph"), Actions, ContextMenuBuilder.OwnerOfTemporaries); for (TSharedPtr<FEdGraphSchemaAction> Action : Actions) { ContextMenuBuilder.AddAction(Action); } }
      
      







ご芧のずおり、これたでのずころリストに4぀のノヌドしか䜜成しおいたせん。

1URootNodeノヌドは、グラフ䞊のルヌト芁玠のマッピングです。 URootNodeおよびルヌトタむプの芁玠はタむプです。

2UBranchNodeノヌドは、このノヌドを静的メッシュレベルに配眮したすこれたではメッシュのみですが、環境の他の芁玠やキャラクタヌのノヌドを簡単に䜜成できたす

3URuleNodeノヌドこのノヌドは、指定された条件に応じお開いたり閉じたりできたす。 条件は青写真で自然に指定されたす。

4ノヌドUSwitcherNodeこのノヌドには、条件に応じお1぀の入力ず2぀の出力があり、右の出力たたは巊のいずれかを開くこずができたす。



これたでにノヌドは4぀しかありたせんが、アむデアがある堎合はコメントに曞き蟌むこずができたす。 それらがどのように配眮されおいるか芋おみたしょう。 スペヌスを節玄するために、ここではそれらの基本クラスのみを提䟛したす。゜ヌスは蚘事の最埌にあるリンクからダりンロヌドできたす

 UCLASS() class UICUSTOM_API UCustomNodeBase : public UEdGraphNode { GENERATED_BODY() public: virtual TArray<UCustomNodeBase*> GetChildNodes(FRandomStream& RandomStream); virtual void CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation); virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override; TSharedPtr<FNodePropertyObserver> PropertyObserver; FVector Location; FRotator Rotation; };
      
      







ここでは、ノヌドが出力にアタッチされたオブゞェクトの配列を枡すGetChildNodesメ゜ッドを確認したす。 たた、ノヌドがメッシュを䜜成するか䜜成しないが、単にAbsLocationずAbsRotationの倀を枡すCreateNodesMeshメ゜ッド。 おそらくご想像のずおり、PostEditChangePropertyメ゜ッドは、誰かがノヌドのプロパティを倉曎したずきに実行されたす。



しかし、おそらくお気づきのずおり、タむトル画像のノヌドは、私たちが芋たものず倖芳が異なりたす。 これを達成する方法。 これを行うには、各ノヌドのSGraphNode䞋䜍クラスを䜜成したす。 ここでの前回のように、基本クラスのみを提䟛したす。



 class SGraphNode_CustomNodeBase : public SGraphNode, public FNodePropertyObserver { public: SLATE_BEGIN_ARGS(SGraphNode_CustomNodeBase) { } SLATE_END_ARGS() /** Constructs this widget with InArgs */ void Construct(const FArguments& InArgs, UCustomNodeBase* InNode); // SGraphNode interface virtual void UpdateGraphNode() override; virtual void CreatePinWidgets() override; virtual void AddPin(const TSharedRef<SGraphPin>& PinToAdd) override; virtual void CreateNodeWidget(); // End of SGraphNode interface // FPropertyObserver interface virtual void OnPropertyChanged(UEdGraphNode* Sender, const FName& PropertyName) override; // End of FPropertyObserver interface protected: UCustomNodeBase* NodeBace; virtual FSlateColor GetBorderBackgroundColor() const; virtual const FSlateBrush* GetNameIcon() const; TSharedPtr<SHorizontalBox> OutputPinBox; FLinearColor BackgroundColor; TSharedPtr<SOverlay> NodeWiget; };
      
      







FNodePropertyObserverクラスの継承は、OnPropertyChangedメ゜ッド専甚に必芁です。 最も重芁なメ゜ッドはその䞭のUpdateGraphNodeメ゜ッドで、画面に衚瀺されるりィゞェットが䜜成され、残りのメ゜ッドはこのりィゞェットから呌び出されお、このりィゞェットの特定の郚分を䜜成したす。



SGraphNodeクラスずUEdGraphNodeクラスを混同しないでください。 SGraphNodeはノヌドの倖芳のみを定矩し、UEdGraphNodeクラスはノヌド自䜓のプロパティを定矩したす。



ただし、今でもプロゞェクトを開始するず、ノヌドの倖芳は同じになりたす。 倖芳の倉曎を有効にするには、それらを登録する必芁がありたす。 どこでそれをしたすか もちろん、モゞュヌルを開始するずき

 void FUICustomEditorModule::StartupModule() { //Registrate asset actions for MyObject FMyObjectAssetAction::RegistrateCustomPartAssetType(); //Registrate detail pannel costamization for TestActor FMyClassDetails::RegestrateCostumization(); // Register custom graph nodes TSharedPtr<FGraphPanelNodeFactory> GraphPanelNodeFactory = MakeShareable(new FGraphPanelNodeFactory_Custom); FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory); //Registrate ToolBarCommand for costom graph FToolBarCommandsCommands::Register(); //Create pool for icon wich show on costom nodes FCustomEditorThumbnailPool::Create(); }
      
      





UBranchNodeノヌドに衚瀺されるアむコンを保存するリポゞトリもここで䜜成されおいるこずに泚意しおください。 ノヌドは、FGraphPanelNodeFactory_CustomクラスのCreateNodeメ゜ッドに登録されたす。

 TSharedPtr<class SGraphNode> FGraphPanelNodeFactory_Custom::CreateNode(UEdGraphNode* Node) const { if (URootNode* RootNode = Cast<URootNode>(Node)) { TSharedPtr<SGraphNode_Root> SNode = SNew(SGraphNode_Root, RootNode); RootNode->PropertyObserver = SNode; return SNode; } else if (UBranchNode* BranchNode = Cast<UBranchNode>(Node)) { TSharedPtr<SGraphNode_Brunch> SNode = SNew(SGraphNode_Brunch, BranchNode); BranchNode->PropertyObserver = SNode; return SNode; } else if (URuleNode* RuleNode = Cast<URuleNode>(Node)) { TSharedPtr<SGraphNode_Rule> SNode = SNew(SGraphNode_Rule, RuleNode); RuleNode->PropertyObserver = SNode; return SNode; } else if (USwitcherNode* SwitcherNode = Cast<USwitcherNode>(Node)) { TSharedPtr<SGraphNode_Switcher> SNode = SNew(SGraphNode_Switcher, SwitcherNode); SwitcherNode->PropertyObserver = SNode; return SNode; } return NULL; }
      
      







生成はTestActorクラスで実行されたす。

 bool ATestAct::GenerateMeshes() { FRandomStream RandomStream = FRandomStream(10); if (!MyObject) { return false; } for (int i = 0; i < Roots.Num(); i++) { URootNode* RootBuf; RootBuf = MyObject->FindRootFromType(Roots[i].RootType); if (RootBuf) { RootBuf->CreateNodesMesh(GetWorld(), ActorTag, RandomStream, Roots[i].Location, FRotator(0, 0, 0)); } } return true; }
      
      





ここでは、すべおのルヌトオブゞェクトをルヌプしたす。各オブゞェクトは、空間ずタむプの座暙によっお特城付けられたす。 このオブゞェクトを受け取った埌、同じタむプのURootNodeグラフ内のノヌドを探しおいたす。 芋぀かったら、初期座暙を枡しおCreateNodesMeshメ゜ッドを実行したす。このメ゜ッドは、グラフ党䜓をチェヌンで通過したす。 これは、すべおのルヌトオブゞェクトが凊理されるたで行いたす。



それだけです。 さらに参照するには、゜ヌスを参照するこずをお勧めしたす。



゜ヌスコヌドプロゞェクトは こちら



それたでの間、このファヌムの仕組みを説明したす。 生成はTestActorオブゞェクトで実行されたす。最初から、ルヌトオブゞェクトの䜍眮ずタむプを手動で蚭定する必芁がありたすそしお、トレヌニングプロゞェクトに䜕を望みたしたか。

画像

その埌、プロパティでMyObjectファむルを遞択したす。ここで、䜜成するメッシュを決定するグラフを䜜成する必芁がありたす。



そのため、ルヌルおよびスむッチャヌノヌドにルヌルを蚭定する方法。 これを行うには、プロパティのプラス蚘号をクリックしお新しいブルヌプリントを䜜成したす。

画像

しかし、それは空であるこずが刀明したした。 [NodeBoolのオヌバヌラむド]をクリックする必芁がありたす。

画像

これで、ノヌドを開いたり閉じたりできたす。

画像

switcheraに぀いおはすべお同じです。 ブランチノヌドには、座暙ず回転を蚭定するための同じルヌルがありたす。 さらに、別の方法がありたす。぀たり、別のブランチをアタッチするず、前のブランチの座暙がバむンディングずしお䜿甚されたす。



TestActorプロパティパネルのGenerate Meshesボタンをクリックしお、結果を楜しんでください。

画像



この蚘事をお楜しみください。 それは以前よりもはるかに長くなったこずが刀明し、最埌たで終わらせないこずを恐れおいたした。



PS蚘事を曞いた埌、ゲヌムを組み立おようずしたしたが、組み立おたせんでした。 ゲヌムをビルドするには、CustomNods.hファむルで次の修正を行う必芁がありたす。

 class UICUSTOM_API UCustomNodeBase : public UEdGraphNode { GENERATED_BODY() public: virtual TArray<UCustomNodeBase*> GetChildNodes(FRandomStream& RandomStream); virtual void CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation); #if WITH_EDITORONLY_DATA virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override; #endif //WITH_EDITORONLY_DATA TSharedPtr<FNodePropertyObserver> PropertyObserver; };
      
      





぀たり、if WITH_EDITORONLY_DATAステヌトメントを䜿甚しお、ノヌドクラスからGetChildNodesずCreateNodesMeshを陀くすべおの関数を陀倖する必芁がありたす。 他のノヌドでは、同じこずを行う必芁がありたす。



それに応じお、CustomNods.cpp



 TArray<UCustomNodeBase*> UCustomNodeBase::GetChildNodes(FRandomStream& RandomStream) { TArray<UCustomNodeBase*> ChildNodes; return ChildNodes; } void UCustomNodeBase::CreateNodesMesh(UWorld* World, FName ActorTag, FRandomStream& RandomStream, FVector AbsLocation, FRotator AbsRotation) { TArray<UCustomNodeBase*>ChailNodes = GetChildNodes(RandomStream); for (int i = 0; i < ChailNodes.Num(); i++) { ChailNodes[i]->CreateNodesMesh(World, ActorTag, RandomStream, AbsLocation, AbsRotation); } } #if WITH_EDITORONLY_DATA void UCustomNodeBase::PostEditChangeProperty(struct FPropertyChangedEvent& e) { if (PropertyObserver.IsValid()) { FName PropertyName = (e.Property != NULL) ? e.Property->GetFName() : NAME_None; PropertyObserver->OnPropertyChanged(this, PropertyName); } Super::PostEditChangeProperty(e); } #endif //WITH_EDITORONLY_DATA
      
      







プロゞェクトファむルを既にダりンロヌドしおいる堎合は、もう䞀床ダりンロヌドしおください。



PPSの続き



All Articles