(UE4 4.21 ) UE4 编辑器(UObject)的Undo撤回系统Transactional(CtrZ和CtrY)

前言

我们在UE4编辑器开发中,各种编辑器的操作经常涉及到(Ctr + Z, Undo)和(Ctr + Y, Redo).那么UE4的编辑器这套回撤系统怎么进行的?

 

针对UObject的回撤系统

首先UE4内部有一套针对UObject系统的回撤系统,不过这套系统针对的基本对象为UObject对象,我们撤回的是某个UObject对象的某个属性,使某个属性回到修改之前,也就是所谓的撤回。想要实现完备的UObject属性撤回得遵守下面几点

UObject创建标记

RF_Transactional(控制UObject是否能回撤)和依赖的UObject链必须存在GetTransientPackage()

一个UObject的EObjectFlags得标记为 “RF_Transactional”,才具备回撤功能。

UTestObject* TestObject = NewObject<UTestObject>(GetTransientPackage(), NAME_None, RF_Transactional);

或者

​TestObject->SetFlags(RF_Transactional)​

具备撤回性质属性得标记UPROPERTY(控制UObject的一个属性是否能回撤)

如果你想要你的UObject的属性在回撤系统中起作用,那么你得为这个属性添加UPROPERTY()标记

UCLASS()
class TESTCTRZ_API UTestObject : public UObject
{
	GENERATED_BODY()

public:
	UPROPERTY()
	float a;

	float b;
};

如上面float a就在某次撤回中值就变为修改之前。

一个问题来了,如果我们希望UOBject的一个属性能把暴露给编辑器,也就是得UROPERTY(EditAnywhere)",但是处于某些因素,我们并不希望这个属性进入回撤系统,那怎么办?UE4有个UROPERTY标记,“NonTransactional”,可以让我们的属性不进入撤回系统,比如下面"float a"暴露属性给编辑器修改的同时又不进入撤回系统

UCLASS()
class TESTCTRZ_API UTestObject : public UObject
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, NonTransactional)
		float a;
};

 

UObject的一次修改记录的界定

并不是我们每次修改一个UObject的属性,都会把这次修改添加到修改记录中(编辑器Undo History),而且我们也需要如果界定何为“一次修改记录”,比如我们移动一个Actor一个单位是一次修改记录,还是移动一百个单位是一次修改距离,还是说从点鼠标选择一个Actor移动一段距离后释放鼠标才视为一次修改记录?这些一次修改记录都添加到UE4编辑器Undo History。

所以“一次修改记录”存在一个界定,UE4提供了内置API让我们可以把UObject属性的每次修改灵活的添加到编辑器Undo History

    

UE4内部有两种限定“一次修改记录”的方法

(1)GEditor->BeginTransaction, GEditor->EndTransaction和UObject的Modify

	GEditor->BeginTransaction(FText::FromString("TestObject"));

	TestObject->Modify();
	TestObject->a = 100.0f;

	GEditor->EndTransaction();

GEditor->BeginTransaction, GEditor->EndTransaction之间的"xxxxx"内容即是UObject的修改内容,当然UObject修改前的调用Modify函数将UObject的属性修改Save到TransactionBuffer

BeginTransaction里的参数为自定义的修改记录的名称。像上面图里的“Click on Actors‘, "Move Actors"

 

(2)FScopedTransaction和UObject的Modify

	FScopedTransaction Transaction(FText::FromString("TestObject"));
	TestObject->Modify();
	TestObject->a = 100.0f;

FScopedTransaction灵活性比GEditor->BeginTransaction, GEditor->EndTransaction低得多,也就是FScopedTransaction变量声明到退出所在的局部函数的时候被视为“一次修改”。

 

 

撤回之后的动作(PostEditUndo)

按照上面的步骤之后,我们按住CtrZ或者CtrY将UObject中被标记的属性值可以撤回或者后退,然而单单是属性值

回撤并不满足我们的需求,我们往往需要用回撤的属性值做些事情以达到UObject完全的回撤。这个时候就用了“PostEditUndo”函数,当我们按照我们的各种标记后,并做了修改记录,按住CtrZ或者CtrY将会触发UObject的回撤函数PostEditUndo,这个函数是执行在UObject的属性值回撤之后的。

UCLASS()
class TESTCTRZ_API UTestObject : public UObject
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, NonTransactional)
		float a;

public:
#if WITH_EDITOR
	virtual void PostEditUndo() override;
#endif
};


void UTestObject::PostEditUndo()
{
	Super::PostEditUndo();

	//do something
}

撤回之前的动作(PreEditUndo)

PostEditUndo,自然就有PreEditUndo, 顾名思义就是在撤销UObject的属性之前调用的函数

class UTestObject: public UObject:
{
    #if WITH_EDITOR
	    virtual void PreEditUndo() override;
    #endif
};

void UTestObject::PreEditUndo()
{
	Super::PreEditUndo();

	//do something
}

 

资料参考

[1].https://answers.unrealengine.com/questions/412356/how-does-the-transaction-undoredo-system-work.html

[2].https://answers.unrealengine.com/questions/477593/view.html

 

 

 

 

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值