ããã«ã¡ã¯ãç§ã®ååã¯ããããªãŒã§ãã ç§ã¯è¶£å³ãšããŠã¢ã³ãªã¢ã«ãšã³ãžã³ã§ã³ã³ãã¥ãŒã¿ãŒã²ãŒã ãäœã£ãŠããŸãã ç§ã®ãããžã§ã¯ãã§ã¯ãããã·ãŒãžã£çæã¬ãã«ãéçºããŠããŸãã ç§ã®ã¢ã«ãŽãªãºã ã¯ã空éå ã®ãã€ã³ãïŒã«ãŒãããã«ãŒãããšåŒã³ãŸãïŒãæ確ãªé åºã§é 眮ãããã®åŸããããã®ãã€ã³ãã«ã¡ãã·ã¥ãã¢ã¿ããããŸãã ããããããã§ã¯ãæåããã¡ãã·ã¥ãã¢ã¿ãããããããžã§ã¯ããã³ã³ãã€ã«ããå¿ èŠããããšããåé¡ãçºçããŸãããã®åŸããããã©ã®ããã«çºçãããã確èªã§ããŸãã ãšãã£ã¿ãŠã£ã³ããŠãã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ã®ç¶ã