一般编辑功能都有撤销和重做,如下图是VS的编辑菜单下的撤销/重做功能,UE4编辑器的Edit菜单下也有Undo和Redo功能
如果要在游戏中实现撤销/重做就要自己写代码实现了,比如撤销/重做Actor的移动或隐藏,下面来实现这样一个简化版的功能。
每种需要撤销和重做的功能类型都使用一个类来保存所有需要的信息,如物体的位置移动需要保存Actor的指针、移动前的位置和移动后的位置,撤销功能就是将物体移到移动前的位置,而重做就是移到移动后的位置,下列的代码实现移动和隐藏的编辑数据类,他们有一个共同基类FEditData。
class FEditData
{
public:
virtual bool Redo() { return false; }
virtual bool Undo() { return false; }
virtual ~FEditData() {}
};
class FLocationEditData : public FEditData
{
public:
AActor* actor;
FVector location1;//移动前位置
FVector location2;//移动后位置
virtual bool Redo()
{
actor->SetActorLocation(location2);
return true;
}
virtual bool Undo()
{
actor->SetActorLocation(location1);
return true;
}
};
class FVisibleEditData : public FEditData
{
public:
AActor* actor;
bool bHide;//是否为隐藏操作
virtual bool Redo()
{
actor->SetActorHiddenInGame(bHide);
return true;
}
virtual bool Undo()
{
actor->SetActorHiddenInGame(!bHide);
return true;
}
};
当然还有很多种其他编辑数据类型,有的数据类型也可以合并为一种,如位置/旋转/缩放可以合并为一个Transform类型,这里就以这两种最简单的类型为例。
每次撤销操作是撤销最后一步的编辑,与栈数据结构的后进先出很类似,因此可以使用栈作为编辑数据的保存容器,但是由于编辑数据不能无限制的保存下去,需要限制步数长度,所以选用双端队列保存更合适,当步数过长可以在队列的一段删掉最开始的一步操作。
//#include<deque>
std::deque<FEditData*> m_dqRedo;//重做数据队列
std::deque<FEditData*> m_dqUndo;//撤销数据队列
下列Undo和Redo函数从数据队列中取出最后一步操作的数据实现撤销和重做,执行撤销操作需要将m_dqUndo队列最后一步数据弹出并放到m_dqRedo队列中,重做则是相反的方向。
void Undo()
{
if (m_dqUndo.size() > 0)
{
FEditD