From d5a45b3b01d39c9300809f94d06d77f39c2e673e Mon Sep 17 00:00:00 2001
From: Nomango <569629550@qq.com>
Date: Sat, 9 Dec 2017 15:27:11 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E9=83=A8=E5=88=86?=
 =?UTF-8?q?=E5=9C=BA=E6=99=AF=E5=88=87=E6=8D=A2=E5=8A=A8=E7=94=BB=E7=9A=84?=
 =?UTF-8?q?=E6=98=BE=E7=A4=BAbug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
 Demo/main.cpp                                |  21 +--
 Easy2D/Base/EApp.cpp                         |  46 +++----
 Easy2D/Easy2D.vcxproj                        |   3 +-
 Easy2D/Easy2D.vcxproj.filters                |   9 +-
 Easy2D/Transition/ETransition.cpp            |  52 +++++++
 Easy2D/Transition/ETransitionEmerge.cpp      |  50 +++----
 Easy2D/Transition/ETransitionFade.cpp        |  75 ++++++----
 Easy2D/Transition/ETransitionMove.cpp        |  78 +++++------
 Easy2D/Transition/ETransitionScale.cpp       |  40 ------
 Easy2D/Transition/ETransitionScaleEmerge.cpp |  67 ---------
 Easy2D/ebase.h                               |   6 +-
 Easy2D/enodes.h                              |   2 +
 Easy2D/etransitions.h                        | 137 ++++++++-----------
 Easy2D/etypedef.h                            |  20 +++
 14 files changed, 269 insertions(+), 337 deletions(-)
 create mode 100644 Easy2D/Transition/ETransition.cpp
 delete mode 100644 Easy2D/Transition/ETransitionScale.cpp
 delete mode 100644 Easy2D/Transition/ETransitionScaleEmerge.cpp
diff --git a/Demo/main.cpp b/Demo/main.cpp
index 037567c7..e88e2fdf 100644
--- a/Demo/main.cpp
+++ b/Demo/main.cpp
@@ -11,22 +11,21 @@ int WINAPI WinMain(
 	if (!EApp::init(L"Easy2D Demo", 640, 480))
 		return -1;
 
-	float w = EApp::getWidth();
-	float h = EApp::getHeight();
 	auto scene = new EScene();
+	scene->retain();
 
 	auto text = new EText(L"中文测试中文测试中文测试中文测试中文测试中文测试中文测试", L"楷体");
 	text->setPos(EApp::getWidth() / 2, EApp::getHeight() / 2);
 	//text->setWordWrapping(true);
 	//text->setWordWrappingWidth(130);
 	text->setRotation(40);
-	//text->runAction(new EActionLoop(new EActionTwo(new EActionFadeOut(1), new EActionFadeIn(1))));
+	text->runAction(new EActionLoop(new EActionTwo(new EActionFadeOut(1), new EActionFadeIn(1))));
 	scene->add(text);
 
 	auto listener = new EListenerKeyboardPress([=]() {
 		if (EKeyboardMsg::getKeyValue() == EKeyboardMsg::KEY::SPACE)
 		{
-			EApp::backScene(new ETransitionFade(0.5f, 0.5f));
+			EApp::backScene(new ETransitionMove(0.5f, ETransitionMove::DOWN));
 		}
 	});
 	listener->bindWith(scene);
@@ -48,28 +47,30 @@ int WINAPI WinMain(
 	auto btnStartSelected = new ESprite(L"atlas.png", 702, 234, 116, 70);
 	btnStartSelected->setPosY(5);
 	auto button = new EButton(btnStart, btnStartSelected, [=] {
-		if (EApp::isPaused())
+		/*if (EApp::isPaused())
 		{
 			EApp::resume();
 		}
 		else
 		{
 			EApp::pause();
-		}
-		//EApp::enterScene(scene, new ETransitionScaleEmerge(1, ETransitionScaleEmerge::BACK));
+		}*/
+		EApp::enterScene(scene, new ETransitionMove(1, ETransitionMove::RIGHT));
 	});
 	button->setPivot(0.5f, 0.5f);
 	button->setPos(EApp::getWidth() / 2, EApp::getHeight() / 2 + 100);
 	scene2->add(button);
 
-	scene2->runAction(new EActionSequence(5,
+	EMusicUtils::playMusic(L"music.wav", -1);
+
+	/*scene2->runAction(new EActionSequence(5,
 		new EActionCallback([]() { EMusicUtils::playMusic(L"music.wav", -1); }),
 		new EActionDelay(3),
 		new EActionCallback([]() { EMusicUtils::pauseMusic(L"music.wav"); }),
 		new EActionDelay(10),
-		new EActionCallback([]() { EMusicUtils::resumeMusic(L"music.wav"); })));
+		new EActionCallback([]() { EMusicUtils::resumeMusic(L"music.wav"); })));*/
 
-	EApp::enterScene(scene2, new ETransitionFade(0, 1));
+	EApp::enterScene(scene2, new ETransitionMove(1, ETransitionMove::UP));
 
 	return EApp::run();
 }
diff --git a/Easy2D/Base/EApp.cpp b/Easy2D/Base/EApp.cpp
index 2914ef90..a7540dcf 100644
--- a/Easy2D/Base/EApp.cpp
+++ b/Easy2D/Base/EApp.cpp
@@ -25,11 +25,11 @@ e2d::EApp::EApp()
 	: m_bEnd(false)
 	, m_bPaused(false)
 	, m_bManualPaused(false)
-	, m_bTransitional(false)
 	, m_bTopMost(false)
 	, m_bShowConsole(false)
 	, m_nAnimationInterval(17LL)
 	, m_ClearColor(EColor::BLACK)
+	, m_pTransition(nullptr)
 	, m_pCurrentScene(nullptr)
 	, m_pNextScene(nullptr)
 {
@@ -337,14 +337,17 @@ void e2d::EApp::_update()
 	}
 
 	// 正在切换场景时,执行场景切换动画
-	if (m_bTransitional)
+	if (m_pTransition)
 	{
-		EActionManager::ActionProc();
-		// 若场景切换未结束,不执行后面的部分
-		if (m_bTransitional)
+		m_pTransition->_update();
+		if (m_pTransition->isEnding())
 		{
-			return;
+			m_pTransition->release();
+			m_pTransition = nullptr;
+			// 进入下一场景
+			_enterNextScene();
 		}
+		return;
 	}
 
 	// 下一场景指针不为空时,切换场景
@@ -376,7 +379,7 @@ void e2d::EApp::_render()
 		m_pCurrentScene->_render();
 	}
 	// 切换场景时,同时绘制两场景
-	if (m_bTransitional && m_pNextScene)
+	if (m_pTransition && m_pNextScene)
 	{
 		m_pNextScene->_render();
 	}
@@ -447,8 +450,9 @@ e2d::ESize e2d::EApp::getSize()
 	return ESize(GetRenderTarget()->GetSize().width, GetRenderTarget()->GetSize().height);
 }
 
-void e2d::EApp::enterScene(EScene * scene, bool saveCurrentScene /* = true */, ETransition * transition /* = nullptr */)
+void e2d::EApp::enterScene(EScene * scene, ETransition * transition /* = nullptr */, bool saveCurrentScene /* = true */)
 {
+	ASSERT(scene != nullptr, "Next scene NULL pointer exception!");
 	scene->retain();
 	// 保存下一场景的指针
 	getInstance()->m_pNextScene = scene;
@@ -460,17 +464,13 @@ void e2d::EApp::enterScene(EScene * scene, bool saveCurrentScene /* = true */, E
 	// 设置切换场景动画
 	if (transition)
 	{
-		getInstance()->m_bTransitional = true;
+		getInstance()->m_pTransition = transition;
+		transition->retain();
 		transition->_setTarget(
 			getInstance()->m_pCurrentScene, 
-			getInstance()->m_pNextScene, 
-			getInstance()->m_bTransitional
+			getInstance()->m_pNextScene
 		);
 	}
-	else
-	{
-		getInstance()->m_bTransitional = false;
-	}
 }
 
 void e2d::EApp::backScene(ETransition * transition /* = nullptr */)
@@ -492,19 +492,13 @@ void e2d::EApp::backScene(ETransition * transition /* = nullptr */)
 	// 设置切换场景动画
 	if (transition)
 	{
-		getInstance()->m_bTransitional = true;
+		getInstance()->m_pTransition = transition;
+		transition->retain();
 		transition->_setTarget(
 			getInstance()->m_pCurrentScene, 
-			getInstance()->m_pNextScene, 
-			getInstance()->m_bTransitional
+			getInstance()->m_pNextScene
 		);
 	}
-	else
-	{
-		// 把这个变量赋为 false,场景将在下一帧画面
-		// 进行切换
-		getInstance()->m_bTransitional = false;
-	}
 }
 
 void e2d::EApp::clearScene()
@@ -650,7 +644,7 @@ LRESULT e2d::EApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam
 		case WM_MOUSEWHEEL:
 		{
 			// 执行场景切换时屏蔽按键和鼠标消息
-			if (!s_pInstance->m_bTransitional && !s_pInstance->m_pNextScene)
+			if (!s_pInstance->m_pTransition && !s_pInstance->m_pNextScene)
 			{
 				EMsgManager::MouseProc(message, wParam, lParam);
 			}
@@ -663,7 +657,7 @@ LRESULT e2d::EApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam
 		case WM_KEYUP:
 		{
 			// 执行场景切换时屏蔽按键和鼠标消息
-			if (!s_pInstance->m_bTransitional && !s_pInstance->m_pNextScene)
+			if (!s_pInstance->m_pTransition && !s_pInstance->m_pNextScene)
 			{
 				EMsgManager::KeyboardProc(message, wParam, lParam);
 			}
diff --git a/Easy2D/Easy2D.vcxproj b/Easy2D/Easy2D.vcxproj
index 0c917008..d7c5eab3 100644
--- a/Easy2D/Easy2D.vcxproj
+++ b/Easy2D/Easy2D.vcxproj
@@ -245,11 +245,10 @@
     
     
     
+    
     
     
     
-    
-    
     
     
   
diff --git a/Easy2D/Easy2D.vcxproj.filters b/Easy2D/Easy2D.vcxproj.filters
index 3a8e48df..fc324afd 100644
--- a/Easy2D/Easy2D.vcxproj.filters
+++ b/Easy2D/Easy2D.vcxproj.filters
@@ -135,12 +135,6 @@
     
       Transition
     
-    
-      Transition
-    
-    
-      Transition
-    
     
       Tool
     
@@ -219,6 +213,9 @@
     
       Win
     
+    
+      Transition
+    
   
   
     
diff --git a/Easy2D/Transition/ETransition.cpp b/Easy2D/Transition/ETransition.cpp
new file mode 100644
index 00000000..c11441c6
--- /dev/null
+++ b/Easy2D/Transition/ETransition.cpp
@@ -0,0 +1,52 @@
+#include "..\etransitions.h"
+#include "..\Win\winbase.h"
+
+e2d::ETransition::ETransition(float duration)
+	: m_bEnd(false)
+	, m_fTotalDuration(duration * 1000)
+	, m_fDuration(0)
+	, m_fRateOfProgress(0)
+	, m_pPrevScene(nullptr)
+	, m_pNextScene(nullptr)
+{
+}
+
+bool e2d::ETransition::isEnding()
+{
+	return m_bEnd;
+}
+
+bool e2d::ETransition::_isDelayEnough()
+{
+	// 判断时间间隔是否足够
+	if (m_fTotalDuration == 0)
+	{
+		m_fRateOfProgress = 1;
+		return true;
+	}
+
+	if (GetInterval(m_tLast) > 15)
+	{
+		// 重新记录时间
+		m_tLast += milliseconds(15);
+		m_fDuration += 15;
+		// 计算动画进度
+		m_fRateOfProgress = m_fDuration / m_fTotalDuration;
+		return true;
+	}
+	return false;
+}
+
+void e2d::ETransition::_stop()
+{
+	m_bEnd = true;
+	_reset();
+}
+
+void e2d::ETransition::_setTarget(EScene * prev, EScene * next)
+{
+	m_tLast = std::chrono::steady_clock::now();
+	m_pPrevScene = prev;
+	m_pNextScene = next;
+	_init();
+}
diff --git a/Easy2D/Transition/ETransitionEmerge.cpp b/Easy2D/Transition/ETransitionEmerge.cpp
index 246963dd..52b77cb2 100644
--- a/Easy2D/Transition/ETransitionEmerge.cpp
+++ b/Easy2D/Transition/ETransitionEmerge.cpp
@@ -1,39 +1,33 @@
 #include "..\etransitions.h"
-#include "..\eactions.h"
-#include "..\emanagers.h"
+#include "..\enodes.h"
 
-e2d::ETransitionEmerge::ETransitionEmerge(float emergeDuration)
-	: m_fEmergeDuration(emergeDuration)
+e2d::ETransitionEmerge::ETransitionEmerge(float duration)
+	: ETransition(duration)
 {
 }
 
-void e2d::ETransitionEmerge::_setTarget(EScene * prev, EScene * next, bool & transitional)
+void e2d::ETransitionEmerge::_update()
 {
-	// 初始化场景属性
-	next->getRoot()->setOpacity(0);
-
-	// 第一个场景淡出
-	auto action1 = new EActionFadeOut(m_fEmergeDuration);
-	if (prev)
+	if (_isDelayEnough())
 	{
-		action1->setTarget(prev->getRoot());
-	}
+		if (m_pPrevScene) m_pPrevScene->getRoot()->setOpacity(1 - m_fRateOfProgress);
+		m_pNextScene->getRoot()->setOpacity(m_fRateOfProgress);
 
-	// 第二个场景淡入
-	auto action2 = new EActionFadeIn(m_fEmergeDuration);
-	action2->setTarget(next->getRoot());
-
-	// 标志动画结束
-	auto action3 = new EActionCallback([&, prev, next] {
-		transitional = false;
-		// 还原场景状态
-		if (prev)
+		if (m_fDuration >= m_fTotalDuration)
 		{
-			prev->getRoot()->setOpacity(1);
+			this->_stop();
 		}
-		next->getRoot()->setOpacity(1);
-	});
-
-	// 添加顺序动作
-	EActionManager::addAction(new EActionSequence(2, new EActionTwoAtSameTime(action1, action2), action3));
+	}
+}
+
+void e2d::ETransitionEmerge::_init()
+{
+	if (m_pPrevScene) m_pPrevScene->getRoot()->setOpacity(1);
+	m_pNextScene->getRoot()->setOpacity(0);
+}
+
+void e2d::ETransitionEmerge::_reset()
+{
+	if (m_pPrevScene) m_pPrevScene->getRoot()->setOpacity(1);
+	m_pNextScene->getRoot()->setOpacity(1);
 }
diff --git a/Easy2D/Transition/ETransitionFade.cpp b/Easy2D/Transition/ETransitionFade.cpp
index 961361a9..bbca7ddb 100644
--- a/Easy2D/Transition/ETransitionFade.cpp
+++ b/Easy2D/Transition/ETransitionFade.cpp
@@ -1,40 +1,57 @@
 #include "..\etransitions.h"
-#include "..\eactions.h"
-#include "..\emanagers.h"
+#include "..\enodes.h"
 
 e2d::ETransitionFade::ETransitionFade(float fadeOutDuration, float fadeInDuration)
-	: m_fFadeOutDuration(fadeOutDuration)
-	, m_fFadeInDuration(fadeInDuration)
+	: ETransition(0)
+	, m_fFadeOutDuration(fadeOutDuration * 1000)
+	, m_fFadeInDuration(fadeInDuration * 1000)
+	, m_bFadeOutTransioning(true)
 {
+	m_fTotalDuration = m_fFadeOutDuration;
 }
 
-void e2d::ETransitionFade::_setTarget(EScene * prev, EScene * next, bool & transitional)
+void e2d::ETransitionFade::_update()
 {
-	// 初始化场景属性
-	next->getRoot()->setOpacity(0);
-
-	// 第一个场景淡出
-	auto action1 = new EActionFadeOut(m_fFadeOutDuration);
-	if (prev)
+	if (_isDelayEnough())
 	{
-		action1->setTarget(prev->getRoot());
-	}
-	
-	// 第二个场景淡入
-	auto action2 = new EActionFadeIn(m_fFadeInDuration);
-	action2->setTarget(next->getRoot());
-
-	// 标志动画结束
-	auto action3 = new EActionCallback([&, prev, next] {
-		transitional = false;
-		// 还原场景状态
-		if (prev)
+		if (m_bFadeOutTransioning)
 		{
-			prev->getRoot()->setOpacity(1);
+			m_pPrevScene->getRoot()->setOpacity(1 - m_fRateOfProgress);
+			if (m_fDuration >= m_fTotalDuration)
+			{
+				m_bFadeOutTransioning = false;
+				m_fTotalDuration = m_fFadeInDuration;
+				m_fDuration = 0;
+			}
 		}
-		next->getRoot()->setOpacity(1);
-	});
+		else
+		{
+			m_pNextScene->getRoot()->setOpacity(m_fRateOfProgress);
+			if (m_fDuration >= m_fTotalDuration)
+			{
+				this->_stop();
+			}
+		}
+	}
+}
 
-	// 添加顺序动作
-	EActionManager::addAction(new EActionSequence(3, action1, action2, action3));
-}
\ No newline at end of file
+void e2d::ETransitionFade::_init()
+{
+	if (m_pPrevScene)
+	{
+		m_bFadeOutTransioning = true;
+		m_pPrevScene->getRoot()->setOpacity(1);
+	}
+	else
+	{
+		m_bFadeOutTransioning = false;
+		m_fTotalDuration = m_fFadeInDuration;
+	}
+	m_pNextScene->getRoot()->setOpacity(0);
+}
+
+void e2d::ETransitionFade::_reset()
+{
+	if (m_pPrevScene) m_pPrevScene->getRoot()->setOpacity(1);
+	m_pNextScene->getRoot()->setOpacity(1);
+}
diff --git a/Easy2D/Transition/ETransitionMove.cpp b/Easy2D/Transition/ETransitionMove.cpp
index 602b71b9..f890d361 100644
--- a/Easy2D/Transition/ETransitionMove.cpp
+++ b/Easy2D/Transition/ETransitionMove.cpp
@@ -1,64 +1,56 @@
 #include "..\etransitions.h"
-#include "..\eactions.h"
-#include "..\emanagers.h"
+#include "..\enodes.h"
 
-e2d::ETransitionMove::ETransitionMove(float moveDuration, MOVE_DIRECT direct)
-	: m_fMoveDuration(moveDuration)
+e2d::ETransitionMove::ETransitionMove(float duration, MOVE_DIRECT direct)
+	: ETransition(duration)
 	, m_Direct(direct)
 {
 }
 
-void e2d::ETransitionMove::_setTarget(EScene * prev, EScene * next, bool & transitional)
+void e2d::ETransitionMove::_update()
+{
+	if (_isDelayEnough())
+	{
+		if (m_pPrevScene) m_pPrevScene->getRoot()->setPos(m_Vec * m_fRateOfProgress);
+		m_pNextScene->getRoot()->setPos(m_NextPos + m_Vec * m_fRateOfProgress);
+
+		if (m_fDuration >= m_fTotalDuration)
+		{
+			this->_stop();
+		}
+	}
+}
+
+void e2d::ETransitionMove::_init()
 {
-	// 初始化动作属性
-	float distPosX;
-	float distPosY;
 	if (m_Direct == MOVE_DIRECT::UP)
 	{
-		distPosX = 0;
-		distPosY = -EApp::getHeight();
+		m_Vec = EVec(0, -EApp::getHeight());
+		m_NextPos = EPoint(0, EApp::getHeight());
 	}
 	else if (m_Direct == MOVE_DIRECT::DOWN)
 	{
-		distPosX = 0;
-		distPosY = EApp::getHeight();
+		m_Vec = EVec(0, EApp::getHeight());
+		m_NextPos = EPoint(0, -EApp::getHeight());
 	}
 	else if (m_Direct == MOVE_DIRECT::LEFT)
 	{
-		distPosX = -EApp::getWidth();
-		distPosY = 0;
+		m_Vec = EVec(-EApp::getWidth(), 0);
+		m_NextPos = EPoint(EApp::getWidth(), 0);
 	}
 	else if (m_Direct == MOVE_DIRECT::RIGHT)
 	{
-		distPosX = EApp::getWidth();
-		distPosY = 0;
+		m_Vec = EVec(EApp::getWidth(), 0);
+		m_NextPos = EPoint(-EApp::getWidth(), 0);
 	}
 
-	// 初始化场景属性
-	next->getRoot()->movePos(-distPosX, -distPosY);
-
-	// 第一个场景移出
-	auto action1 = new EActionMoveBy(m_fMoveDuration, EVec(distPosX, distPosY));
-	if (prev)
-	{
-		action1->setTarget(prev->getRoot());
-	}
-
-	// 第二个场景移入
-	auto action2 = new EActionMoveBy(m_fMoveDuration, EVec(distPosX, distPosY));
-	action2->setTarget(next->getRoot());
-
-	// 标志动画结束
-	auto action3 = new EActionCallback([&, prev, next] {
-		transitional = false;
-		// 还原场景状态
-		if (prev)
-		{
-			prev->getRoot()->setPos(EApp::getWidth() / 2, EApp::getHeight() / 2);
-		}
-		next->getRoot()->setPos(EApp::getWidth() / 2, EApp::getHeight() / 2);
-	});
-
-	// 添加顺序动作
-	EActionManager::addAction(new EActionSequence(2, new EActionTwoAtSameTime(action1, action2), action3));
+	if (m_pPrevScene) m_pPrevScene->getRoot()->setPos(0, 0);
+	m_pNextScene->getRoot()->setPos(m_NextPos);
 }
+
+void e2d::ETransitionMove::_reset()
+{
+	if (m_pPrevScene) m_pPrevScene->getRoot()->setPos(0, 0);
+	m_pNextScene->getRoot()->setPos(0, 0);
+}
+
diff --git a/Easy2D/Transition/ETransitionScale.cpp b/Easy2D/Transition/ETransitionScale.cpp
deleted file mode 100644
index 6dfb2515..00000000
--- a/Easy2D/Transition/ETransitionScale.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "..\etransitions.h"
-#include "..\eactions.h"
-#include "..\emanagers.h"
-
-e2d::ETransitionScale::ETransitionScale(float scaleOutDuration, float scaleInDuration)
-	: m_fScaleOutDuration(scaleOutDuration)
-	, m_fScaleInDuration(scaleInDuration)
-{
-}
-
-void e2d::ETransitionScale::_setTarget(EScene * prev, EScene * next, bool & transitional)
-{
-	// 初始化场景属性
-	next->getRoot()->setScale(0);
-
-	// 第一个场景缩放至消失
-	auto action1 = new EActionScaleTo(m_fScaleOutDuration, 0);
-	if (prev)
-	{
-		action1->setTarget(prev->getRoot());
-	}
-
-	// 第二个场景淡入
-	auto action2 = new EActionScaleTo(m_fScaleInDuration, 1);
-	action2->setTarget(next->getRoot());
-
-	// 标志动画结束
-	auto action3 = new EActionCallback([&, prev, next] {
-		transitional = false;
-		// 还原场景状态
-		if (prev)
-		{
-			prev->getRoot()->setScale(1);
-		}
-		next->getRoot()->setScale(1);
-	});
-
-	// 添加顺序动作
-	EActionManager::addAction(new EActionSequence(3, action1, action2, action3));
-}
diff --git a/Easy2D/Transition/ETransitionScaleEmerge.cpp b/Easy2D/Transition/ETransitionScaleEmerge.cpp
deleted file mode 100644
index f76aed3c..00000000
--- a/Easy2D/Transition/ETransitionScaleEmerge.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "..\etransitions.h"
-#include "..\eactions.h"
-#include "..\emanagers.h"
-
-e2d::ETransitionScaleEmerge::ETransitionScaleEmerge(float duration, SCALE_EMERGE_MODE mode)
-	: m_fDuration(duration)
-	, m_Mode(mode)
-{
-}
-
-void e2d::ETransitionScaleEmerge::_setTarget(EScene * prev, EScene * next, bool & transitional)
-{
-	float prevScaleBy;
-	float nextScaleBy;
-	if (m_Mode == SCALE_EMERGE_MODE::ENTER)
-	{
-		prevScaleBy = 0.2f;
-		nextScaleBy = -0.2f;
-	}
-	else
-	{
-		prevScaleBy = -0.2f;
-		nextScaleBy = 0.2f;
-	}
-
-	// 初始化场景属性
-	next->getRoot()->setScale(next->getRoot()->getScaleX() - nextScaleBy, next->getRoot()->getScaleY() - nextScaleBy);
-	next->getRoot()->setOpacity(0);
-
-	// 第一个场景淡出
-	auto prevActionFadeOut = new EActionFadeOut(m_fDuration);
-	auto prevActionScaleBy = new EActionScaleBy(m_fDuration, prevScaleBy);
-	auto action1 = new EActionTwoAtSameTime(
-		prevActionFadeOut,
-		prevActionScaleBy);
-	if (prev)
-	{
-		prevActionFadeOut->setTarget(prev->getRoot());
-		prevActionScaleBy->setTarget(prev->getRoot());
-	}
-
-	// 第二个场景淡入
-	auto nextActionFadeOut = new EActionFadeIn(m_fDuration);
-	auto nextActionScaleBy = new EActionScaleBy(m_fDuration, nextScaleBy);
-	auto action2 = new EActionTwoAtSameTime(
-		nextActionFadeOut,
-		nextActionScaleBy);
-
-	nextActionFadeOut->setTarget(next->getRoot());
-	nextActionScaleBy->setTarget(next->getRoot());
-
-	// 标志动画结束
-	auto action3 = new EActionCallback([&, prev, next] {
-		transitional = false;
-		// 还原场景状态
-		if (prev)
-		{
-			prev->getRoot()->setScale(1);
-			prev->getRoot()->setOpacity(1);
-		}
-		next->getRoot()->setScale(1);
-		next->getRoot()->setOpacity(1);
-	});
-
-	// 添加顺序动作
-	EActionManager::addAction(new EActionSequence(2, new EActionTwoAtSameTime(action1, action2), action3));
-}
diff --git a/Easy2D/ebase.h b/Easy2D/ebase.h
index b9a852e9..9097db9b 100644
--- a/Easy2D/ebase.h
+++ b/Easy2D/ebase.h
@@ -52,8 +52,8 @@ public:
 	// 切换场景
 	static void enterScene(
 		EScene * scene,						/* 下一个场景的指针 */
-		bool saveCurrentScene = true,		/* 是否保存当前场景 */
-		ETransition * transition = nullptr	/* 场景切换动画 */
+		ETransition * transition = nullptr,	/* 场景切换动画 */
+		bool saveCurrentScene = true		/* 是否保存当前场景 */
 	);
 
 	// 返回上一场景
@@ -175,7 +175,6 @@ private:
 	bool	m_bEnd;
 	bool	m_bPaused;
 	bool	m_bManualPaused;
-	bool	m_bTransitional;
 	bool	m_bTopMost;
 	bool	m_bShowConsole;
 	EString	m_sTitle;
@@ -184,6 +183,7 @@ private:
 	LONGLONG m_nAnimationInterval;
 	EScene * m_pCurrentScene;
 	EScene * m_pNextScene;
+	ETransition * m_pTransition;
 };
 
 
diff --git a/Easy2D/enodes.h b/Easy2D/enodes.h
index b592f841..b031dcd5 100644
--- a/Easy2D/enodes.h
+++ b/Easy2D/enodes.h
@@ -11,6 +11,7 @@ class EButton;
 class EButtonToggle;
 class EGeometry;
 class EMenu;
+class ETransition;
 
 class ENode :
 	public EObject
@@ -19,6 +20,7 @@ class ENode :
 	friend EButton;
 	friend EButtonToggle;
 	friend EGeometry;
+	friend ETransition;
 
 public:
 	ENode();
diff --git a/Easy2D/etransitions.h b/Easy2D/etransitions.h
index c05ae7b3..a36e3f8e 100644
--- a/Easy2D/etransitions.h
+++ b/Easy2D/etransitions.h
@@ -1,5 +1,6 @@
 #pragma once
 #include "ebase.h"
+#include 
 
 namespace e2d
 {
@@ -9,13 +10,38 @@ class ETransition :
 {
 	friend EApp;
 
+public:
+	ETransition(float duration);
+
+	// 场景切换动画是否结束
+	bool isEnding();
+
 protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
+	// 更新动画
+	virtual void _update() = 0;
+
+	virtual void _init() = 0;
+
+	virtual void _reset() = 0;
+
+	virtual bool _isDelayEnough();
+
+	virtual void _stop();
+
+	// 保存当前场景和下一场景的指针
+	void _setTarget(
 		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) = 0;
+		EScene * next
+	);
+
+protected:
+	bool m_bEnd;
+	float m_fTotalDuration;
+	float m_fDuration;
+	float m_fRateOfProgress;
+	EScene * m_pPrevScene;
+	EScene * m_pNextScene;
+	std::chrono::steady_clock::time_point m_tLast;
 };
 
 
@@ -30,16 +56,17 @@ public:
 	);
 
 protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
-		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) override;
+	// 更新动画
+	virtual void _update() override;
+
+	virtual void _init() override;
+
+	virtual void _reset() override;
 
 protected:
 	float m_fFadeOutDuration;
 	float m_fFadeInDuration;
+	bool m_bFadeOutTransioning;
 };
 
 
@@ -49,19 +76,16 @@ class ETransitionEmerge :
 public:
 	// 创建浮现式的场景切换动画
 	ETransitionEmerge(
-		float emergeDuration	/* 浮现动画持续时长 */
+		float duration	/* 浮现动画持续时长 */
 	);
 
 protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
-		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) override;
+	// 更新动画
+	virtual void _update() override;
 
-protected:
-	float m_fEmergeDuration;
+	virtual void _init() override;
+
+	virtual void _reset() override;
 };
 
 
@@ -79,75 +103,22 @@ public:
 
 	// 创建移动式的场景切换动画
 	ETransitionMove(
-		float moveDuration,	/* 场景移动动画持续时长 */
-		MOVE_DIRECT direct	/* 场景移动方向 */
+		float moveDuration,			/* 场景移动动画持续时长 */
+		MOVE_DIRECT direct = LEFT	/* 场景移动方向 */
 	);
 
 protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
-		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) override;
+	// 更新动画
+	virtual void _update() override;
+
+	virtual void _init() override;
+
+	virtual void _reset() override;
 
 protected:
-	float m_fMoveDuration;
 	MOVE_DIRECT m_Direct;
-};
-
-
-class ETransitionScale :
-	public ETransition
-{
-public:
-	// 创建缩放式的场景切换动画
-	ETransitionScale(
-		float scaleOutDuration,	/* 第一个场景缩放动画持续时长 */
-		float scaleInDuration	/* 第二个场景缩放动画持续时长 */
-	);
-
-protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
-		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) override;
-
-protected:
-	float m_fScaleOutDuration;
-	float m_fScaleInDuration;
-};
-
-
-class ETransitionScaleEmerge :
-	public ETransition
-{
-public:
-	enum SCALE_EMERGE_MODE
-	{
-		ENTER,
-		BACK
-	};
-
-	// 创建缩放浮现式的场景切换动画
-	ETransitionScaleEmerge(
-		float duration,			/* 场景动画持续时长 */
-		SCALE_EMERGE_MODE mode	/* 场景移动方向 */
-	);
-
-protected:
-	// 保存当前场景和下一场景的指针,和控制场景切换的变量
-	virtual void _setTarget(
-		EScene * prev,
-		EScene * next,
-		bool &transitional
-	) override;
-
-protected:
-	float m_fDuration;
-	SCALE_EMERGE_MODE m_Mode;
+	EVec m_Vec;
+	EPoint m_NextPos;
 };
 
 }
\ No newline at end of file
diff --git a/Easy2D/etypedef.h b/Easy2D/etypedef.h
index c32af2bc..1728a854 100644
--- a/Easy2D/etypedef.h
+++ b/Easy2D/etypedef.h
@@ -33,6 +33,16 @@ struct EPoint
 	{
 		return EPoint(x - p.x, y - p.y);
 	}
+
+	EPoint operator * (float const & value)
+	{
+		return EPoint(x * value, y * value);
+	}
+
+	EPoint operator / (float const & value)
+	{
+		return EPoint(x / value, y / value);
+	}
 };
 
 struct ESize
@@ -61,6 +71,16 @@ struct ESize
 	{
 		return ESize(width - size.width, height - size.height);
 	}
+
+	ESize operator * (float const & value)
+	{
+		return ESize(width * value, height * value);
+	}
+
+	ESize operator / (float const & value)
+	{
+		return ESize(width / value, height / value);
+	}
 };