diff --git a/project/Easy2D/Easy2D.vcxproj b/project/Easy2D/Easy2D.vcxproj
index b41ebb48..442d4eea 100644
--- a/project/Easy2D/Easy2D.vcxproj
+++ b/project/Easy2D/Easy2D.vcxproj
@@ -1,7 +1,7 @@
 
 
   
-    
+    
     
     
     
@@ -15,7 +15,6 @@
     
     
     
-    
     
     
     
@@ -73,6 +72,7 @@
     
   
   
+    
     
     
     
@@ -81,7 +81,6 @@
     
     
     
-    
     
     
     
diff --git a/project/Easy2D/Easy2D.vcxproj.filters b/project/Easy2D/Easy2D.vcxproj.filters
index 4b16cae8..b46a74cb 100644
--- a/project/Easy2D/Easy2D.vcxproj.filters
+++ b/project/Easy2D/Easy2D.vcxproj.filters
@@ -115,9 +115,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -151,9 +148,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -223,6 +217,9 @@
     
       core
     
+    
+      core
+    
   
   
     
@@ -327,9 +324,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -360,5 +354,8 @@
     
       math
     
+    
+      core
+    
   
 
\ No newline at end of file
diff --git a/project/Samples/Demo1.h b/project/Samples/Demo1.h
index 4c24c549..c13668bb 100644
--- a/project/Samples/Demo1.h
+++ b/project/Samples/Demo1.h
@@ -30,7 +30,7 @@ public:
 					Tween::FadeOut(500),				// Action2: 500毫秒淡出动画
 					Tween::FadeIn(500)					// Action3: 500毫秒淡入动画
 				})
-			}).SetLoopCount(-1)
+			}).SetLoops(-1)
 		);
 	}
 };
diff --git a/src/core/Delay.cpp b/src/core/Action.cpp
similarity index 51%
rename from src/core/Delay.cpp
rename to src/core/Action.cpp
index 4f3f3143..2055c6b5 100644
--- a/src/core/Delay.cpp
+++ b/src/core/Action.cpp
@@ -18,47 +18,85 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include "Delay.h"
+#include "Action.h"
+#include "Node.h"
 
 namespace easy2d
 {
-	Delay::Delay(Duration duration)
-		: delta_()
-		, delay_(duration)
+	Action::Action()
+		: running_(true)
+		, detach_target_(false)
+		, loops_done_(0)
+		, loops_(0)
+		, status_(Status::NotStarted)
 	{
 	}
 
-	void Delay::Reset()
+	Action::~Action()
 	{
-		Action::Reset();
-		delta_ = Duration{};
 	}
 
-	void Delay::Init(Node* target)
+	void Action::UpdateStep(NodePtr const& target, Duration dt)
 	{
-		Action::Init(target);
-	}
+		elapsed_ += dt;
 
-	void Delay::Update(Node* target, Duration dt)
-	{
-		Action::Update(target, dt);
-
-		delta_ += dt;
-
-		if (delta_ >= delay_)
+		if (status_ == Status::NotStarted)
 		{
-			this->Stop();
+			Init(target);
+			status_ = delay_.IsZero() ? Status::Started : Status::Delayed;
+		}
+
+		switch (status_)
+		{
+		case Status::Delayed:
+			if (elapsed_ >= delay_)
+			{
+				status_ = Status::Started;
+			}
+			break;
+
+		case Status::Started:
+			Update(target, dt);
+			break;
+		}
+
+		if (status_ == Status::Done)
+		{
+			if (cb_done_)
+				cb_done_();
+
+			if (detach_target_)
+				target->RemoveFromParent();
+
+			status_ = Status::Removeable;
 		}
 	}
 
-	ActionPtr Delay::Clone() const
+	void Action::Complete(NodePtr const& target)
 	{
-		return new (std::nothrow) Delay(delay_);
+		if (cb_loop_done_)
+			cb_loop_done_();
+
+		if (loops_ >= 0
+			&& loops_done_ >= loops_)
+		{
+			Done();
+		}
+		else
+		{
+			Init(target);	// reinit when a loop is done
+		}
+
+		++loops_done_;
 	}
 
-	ActionPtr Delay::Reverse() const
+	void Action::Restart(NodePtr const & target)
 	{
-		return new (std::nothrow) Delay(delay_);
+		status_ = Status::NotStarted;
+		elapsed_ = 0;
+		loops_done_ = 0;
+
+		Init(target);
 	}
 
-}
\ No newline at end of file
+}
diff --git a/src/core/Action.h b/src/core/Action.h
new file mode 100644
index 00000000..3d06f8e6
--- /dev/null
+++ b/src/core/Action.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2016-2018 Easy2D - Nomango
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#pragma once
+#include "include-forwards.h"
+#include "time.h"
+#include "IntrusiveList.hpp"
+
+namespace easy2d
+{
+	using ActionCallback = std::function;
+
+	class ActionManager;
+
+	class Action
+		: public virtual Object
+		, protected IntrusiveListItem
+	{
+		friend class ActionManager;
+		friend class Loop;
+		friend class Sequence;
+		friend class Spawn;
+		friend class IntrusiveList;
+
+	public:
+		enum class Status
+		{
+			NotStarted,
+			Delayed,
+			Started,
+			Done,
+			Removeable
+		};
+
+		Action();
+
+		virtual ~Action();
+
+		// 继续动作
+		inline void Resume()										{ running_ = true; }
+
+		// 暂停动作
+		inline void Pause()											{ running_ = false; }
+
+		// 停止动作
+		inline void Stop()											{ status_ = Status::Removeable; }
+
+		// 设置动作延时
+		inline void SetDelay(Duration delay)						{ delay_ = delay; }
+
+		// 设置循环次数 (-1 为永久循环)
+		inline void SetLoops(int loops)								{ loops_ = loops; }
+
+		// 动作结束时移除目标节点
+		inline void RemoveTargetWhenDone()							{ detach_target_ = true; }
+
+		// 设置动作结束时的回调函数
+		inline void SetDoneCallback(ActionCallback const& cb)		{ cb_done_ = cb; }
+
+		// 设置动作循环结束时的回调函数
+		inline void SetLoopDoneCallback(ActionCallback const& cb)	{ cb_loop_done_ = cb; }
+
+		// 获取动作的拷贝
+		virtual ActionPtr Clone() const = 0;
+
+		// 获取动作的倒转
+		virtual ActionPtr Reverse() const = 0;
+
+		inline void Done()											{ status_ = Status::Done; }
+
+		inline Status GetStatus() const								{ return status_; }
+
+		inline bool IsRunning() const								{ return running_; }
+
+		inline bool IsDone() const									{ return status_ == Status::Done || status_ == Status::Removeable; }
+
+		inline bool IsRemoveable() const							{ return status_ == Status::Removeable; }
+
+		inline int GetLoops() const									{ return loops_; }
+
+		inline Duration GetDelay() const							{ return delay_; }
+
+		inline Duration GetElapsed() const							{ return elapsed_; }
+
+		inline ActionCallback const& GetDoneCallback() const		{ return cb_done_; }
+
+		inline ActionCallback const& GetLoopDoneCallback() const	{ return cb_loop_done_; }
+
+	protected:
+		virtual void Init(NodePtr const& target) {}
+
+		virtual void Update(NodePtr const& target, Duration dt) {}
+
+		void UpdateStep(NodePtr const& target, Duration dt);
+
+		void Complete(NodePtr const& target);
+
+		void Restart(NodePtr const& target);
+
+	protected:
+		Status			status_;
+		bool			running_;
+		bool			detach_target_;
+		int				loops_;
+		int				loops_done_;
+		Duration		delay_;
+		Duration		elapsed_;
+		ActionCallback	cb_done_;
+		ActionCallback	cb_loop_done_;
+	};
+}
diff --git a/src/core/Action.hpp b/src/core/Action.hpp
deleted file mode 100644
index cc66e7a8..00000000
--- a/src/core/Action.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2016-2018 Easy2D - Nomango
-// 
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#pragma once
-#include "include-forwards.h"
-#include "time.h"
-#include "noncopyable.hpp"
-#include "IntrusiveList.hpp"
-
-namespace easy2d
-{
-	class ActionManager;
-
-	class E2D_API Action
-		: public virtual Object
-		, protected IntrusiveListItem
-	{
-		friend class ActionManager;
-		friend class Loop;
-		friend class Sequence;
-		friend class Spawn;
-		friend class IntrusiveList;
-
-	public:
-		Action() : running_(false), done_(false), initialized_(false) {}
-
-		virtual ~Action() {}
-
-		// 继续动作
-		void Resume() { running_ = true; }
-
-		// 暂停动作
-		void Pause() { running_ = false; }
-
-		// 停止动作
-		void Stop() { if (!done_) { done_ = true; if (cb_) cb_(); } }
-
-		// 获取动作的拷贝
-		virtual ActionPtr Clone() const = 0;
-
-		// 获取动作的倒转
-		virtual ActionPtr Reverse() const = 0;
-
-		// 设置动作结束时的回调函数
-		void SetCallback(std::function cb) { cb_ = cb; }
-
-		// 重置动作
-		virtual void Reset()
-		{
-			initialized_ = false;
-			done_ = false;
-		}
-
-		virtual bool IsDone() const { return done_; }
-
-		virtual bool IsRunning() { return running_; }
-
-	protected:
-		void Start()
-		{
-			running_ = true;
-			this->Reset();
-		}
-
-		virtual void Init(Node* target) { E2D_NOT_USED(target); initialized_ = true; }
-
-		virtual void Update(Node* target, Duration dt)
-		{
-			E2D_NOT_USED(dt);
-			if (!initialized_)
-			{
-				Init(target);
-			}
-		}
-
-	protected:
-		bool running_;
-		bool done_;
-		bool initialized_;
-		std::function cb_;
-	};
-}
diff --git a/src/core/ActionGroup.cpp b/src/core/ActionGroup.cpp
index 44fd0ee8..e3ed65ef 100644
--- a/src/core/ActionGroup.cpp
+++ b/src/core/ActionGroup.cpp
@@ -23,110 +23,15 @@
 
 namespace easy2d
 {
-	//-------------------------------------------------------
-	// Loop
-	//-------------------------------------------------------
-
-	Loop::Loop(ActionPtr const& action, int times)
-		: action_(action)
-		, times_(0)
-		, total_times_(times)
-	{
-		E2D_ASSERT(action && "Loop action contains a null action");
-
-		action_ = action;
-	}
-
-	Loop::~Loop()
-	{
-	}
-
-	ActionPtr Loop::Clone() const
-	{
-		if (action_)
-		{
-			return new (std::nothrow) Loop(action_->Clone());
-		}
-		else
-		{
-			return nullptr;
-		}
-	}
-
-	ActionPtr Loop::Reverse() const
-	{
-		if (action_)
-		{
-			return new (std::nothrow) Loop(action_->Clone());
-		}
-		else
-		{
-			return nullptr;
-		}
-	}
-
-	void Loop::Init(Node* target)
-	{
-		Action::Init(target);
-
-		if (action_)
-		{
-			action_->Init(target);
-		}
-	}
-
-	void Loop::Update(Node* target, Duration dt)
-	{
-		Action::Update(target, dt);
-
-		if (action_)
-		{
-			action_->Update(target, dt);
-
-			if (action_->IsDone())
-			{
-				++times_;
-
-				Action::Reset();
-				action_->Reset();
-			}
-
-			if (times_ == total_times_)
-			{
-				this->Stop();
-			}
-		}
-		else
-		{
-			this->Stop();
-		}
-	}
-
-	void Loop::Reset()
-	{
-		Action::Reset();
-
-		if (action_) action_->Reset();
-		times_ = 0;
-	}
-
-	bool Loop::IsRunning()
-	{
-		return Action::IsRunning() && times_ != total_times_;
-	}
-
-
 	//-------------------------------------------------------
 	// Sequence
 	//-------------------------------------------------------
 
 	Sequence::Sequence()
-		: action_index_(0)
 	{
 	}
 
 	Sequence::Sequence(Array const& actions)
-		: action_index_(0)
 	{
 		this->Add(actions);
 	}
@@ -135,61 +40,49 @@ namespace easy2d
 	{
 	}
 
-	void Sequence::Init(Node* target)
+	void Sequence::Init(NodePtr const& target)
 	{
-		Action::Init(target);
-		actions_[0]->Init(target);
-	}
-
-	void Sequence::Update(Node* target, Duration dt)
-	{
-		Action::Update(target, dt);
-
-		auto& action = actions_[action_index_];
-		action->Update(target, dt);
-
-		if (action->IsDone())
+		if (actions_.IsEmpty())
+			Done();
+		else
 		{
-			++action_index_;
-			if (action_index_ == actions_.size())
-			{
-				this->Stop();
-			}
-			else
-			{
-				actions_[action_index_]->Init(target);
-			}
+			current_ = actions_.First();
+			current_->Restart(target);	// init
 		}
 	}
 
-	void Sequence::Reset()
+	void Sequence::Update(NodePtr const& target, Duration dt)
 	{
-		Action::Reset();
-		for (const auto& action : actions_)
+		if (current_)
 		{
-			action->Reset();
+			current_->UpdateStep(target, dt);
+
+			if (current_->IsDone())
+			{
+				current_ = current_->NextItem();
+				if (current_)
+					current_->Restart(target);
+			}
+		}
+
+		if (!current_)
+		{
+			Complete(target);
 		}
-		action_index_ = 0;
 	}
 
 	void Sequence::Add(ActionPtr const& action)
 	{
 		if (action)
 		{
-			actions_.push_back(action);
+			actions_.PushBack(action);
 		}
 	}
 
 	void Sequence::Add(Array const& actions)
 	{
-		if (actions_.empty())
-			actions_ = actions;
-		else
-		{
-			actions_.reserve(actions_.size() + actions.size());
-			for (const auto& action : actions)
-				Add(action);
-		}
+		for (const auto& action : actions)
+			Add(action);
 	}
 
 	ActionPtr Sequence::Clone() const
@@ -197,7 +90,7 @@ namespace easy2d
 		auto sequence = new (std::nothrow) Sequence();
 		if (sequence)
 		{
-			for (const auto& action : actions_)
+			for (auto action = actions_.First(); action; action = action->NextItem())
 			{
 				if (action)
 				{
@@ -211,12 +104,11 @@ namespace easy2d
 	ActionPtr Sequence::Reverse() const
 	{
 		auto sequence = new (std::nothrow) Sequence();
-		if (sequence && !actions_.empty())
+		if (sequence && !actions_.IsEmpty())
 		{
-			for (auto iter = actions_.crbegin(), crend = actions_.crend(); iter != crend; ++iter)
+			for (auto action = actions_.Last(); action; action = action->PrevItem())
 			{
-				if (*iter)
-					sequence->Add((*iter)->Reverse());
+				sequence->Add(action->Reverse());
 			}
 		}
 		return sequence;
@@ -228,10 +120,12 @@ namespace easy2d
 	//-------------------------------------------------------
 
 	Spawn::Spawn()
+		: size_(0)
 	{
 	}
 
 	Spawn::Spawn(Array const& actions)
+		: size_(0)
 	{
 		this->Add(actions);
 	}
@@ -240,25 +134,23 @@ namespace easy2d
 	{
 	}
 
-	void Spawn::Init(Node* target)
+	void Spawn::Init(NodePtr const& target)
 	{
-		Action::Init(target);
-
-		if (target)
+		if (actions_.IsEmpty())
+			Done();
+		else
 		{
-			for (const auto& action : actions_)
+			for (auto action = actions_.First(); action; action = action->NextItem())
 			{
-				action->Init(target);
+				action->Restart(target);	// init
 			}
 		}
 	}
 
-	void Spawn::Update(Node* target, Duration dt)
+	void Spawn::Update(NodePtr const& target, Duration dt)
 	{
-		Action::Update(target, dt);
-
 		int done_num = 0;
-		for (const auto& action : actions_)
+		for (auto action = actions_.First(); action; action = action->NextItem())
 		{
 			if (action->IsDone())
 			{
@@ -266,22 +158,13 @@ namespace easy2d
 			}
 			else
 			{
-				action->Update(target, dt);
+				action->UpdateStep(target, dt);
 			}
 		}
 
-		if (done_num == actions_.size())
+		if (done_num == size_)
 		{
-			this->Stop();
-		}
-	}
-
-	void Spawn::Reset()
-	{
-		Action::Reset();
-		for (const auto& action : actions_)
-		{
-			action->Reset();
+			Complete(target);
 		}
 	}
 
@@ -289,20 +172,15 @@ namespace easy2d
 	{
 		if (action)
 		{
-			actions_.push_back(action);
+			actions_.PushBack(action);
+			++size_;
 		}
 	}
 
 	void Spawn::Add(Array const& actions)
 	{
-		if (actions_.empty())
-			actions_ = actions;
-		else
-		{
-			actions_.reserve(actions_.size() + actions.size());
-			for (const auto& action : actions)
-				Add(action);
-		}
+		for (const auto& action : actions)
+			Add(action);
 	}
 
 	ActionPtr Spawn::Clone() const
@@ -310,12 +188,9 @@ namespace easy2d
 		auto spawn = new (std::nothrow) Spawn();
 		if (spawn)
 		{
-			for (const auto& action : actions_)
+			for (auto action = actions_.First(); action; action = action->NextItem())
 			{
-				if (action)
-				{
-					spawn->Add(action->Clone());
-				}
+				spawn->Add(action->Clone());
 			}
 		}
 		return spawn;
@@ -324,12 +199,11 @@ namespace easy2d
 	ActionPtr Spawn::Reverse() const
 	{
 		auto spawn = new (std::nothrow) Spawn();
-		if (spawn && !actions_.empty())
+		if (spawn && !actions_.IsEmpty())
 		{
-			for (auto iter = actions_.crbegin(), crend = actions_.crend(); iter != crend; ++iter)
+			for (auto action = actions_.Last(); action; action = action->PrevItem())
 			{
-				if (*iter)
-					spawn->Add((*iter)->Reverse());
+				spawn->Add(action->Reverse());
 			}
 		}
 		return spawn;
diff --git a/src/core/ActionGroup.h b/src/core/ActionGroup.h
index f3891681..fcd0c822 100644
--- a/src/core/ActionGroup.h
+++ b/src/core/ActionGroup.h
@@ -19,47 +19,10 @@
 // THE SOFTWARE.
 
 #pragma once
-#include "Action.hpp"
+#include "Action.h"
 
 namespace easy2d
 {
-    // 循环动作
-	class E2D_API Loop
-		: public Action
-	{
-	public:
-		explicit Loop(
-			ActionPtr const& action,	/* 执行循环的动作 */
-			int times = -1				/* 循环次数 */
-		);
-
-		virtual ~Loop();
-
-		// 获取该动作的拷贝对象
-		ActionPtr Clone() const override;
-
-		// 获取该动作的倒转
-		ActionPtr Reverse() const override;
-
-		// 重置动作
-		void Reset() override;
-
-		bool IsRunning() override;
-
-	protected:
-		// 初始化动作
-		void Init(Node* target) override;
-
-		// 更新动作
-		void Update(Node* target, Duration dt) override;
-
-	protected:
-		ActionPtr	action_;
-		int			times_;
-		int			total_times_;
-	};
-
-
 	// 顺序动作
 	class E2D_API Sequence
 		: public Action
@@ -89,19 +52,16 @@ namespace easy2d
 		// 获取该动作的倒转
 		ActionPtr Reverse() const override;
 
-		// 重置动作
-		void Reset() override;
-
 	protected:
 		// 初始化动作
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 		// 更新动作
-		void Update(Node* target, Duration dt) override;
+		void Update(NodePtr const& target, Duration dt) override;
 
 	protected:
-		UINT action_index_;
-		Array actions_;
+		ActionPtr current_;
+		IntrusiveList actions_;
 	};
 
 
@@ -134,17 +94,15 @@ namespace easy2d
 		// 获取该动作的倒转
 		virtual ActionPtr Reverse() const;
 
-		// 重置动作
-		void Reset() override;
-
 	protected:
 		// 初始化动作
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 		// 更新动作
-		void Update(Node* target, Duration dt) override;
+		void Update(NodePtr const& target, Duration dt) override;
 
 	protected:
-		Array actions_;
+		int size_;
+		IntrusiveList actions_;
 	};
 }
diff --git a/src/core/ActionHelper.h b/src/core/ActionHelper.h
index 9db79a77..032f749e 100644
--- a/src/core/ActionHelper.h
+++ b/src/core/ActionHelper.h
@@ -22,171 +22,179 @@
 #include "ActionGroup.h"
 #include "ActionTween.h"
 #include "Animation.h"
-#include "Delay.h"
 
 namespace easy2d
 {
-	struct E2D_API ActionHelper
+	struct ActionHelper
 	{
-		ActionHelper& SetLoopCount(int loop) { this->loop = loop; return (*this); }
+		// 设置循环次数
+		inline ActionHelper& SetLoops(int loops)							{ base->SetLoops(loops); return (*this); }
 
-		ActionHelper(ActionPtr const& base) : base(base), loop(0) {}
+		// 设置动作延迟
+		inline ActionHelper& SetDelay(Duration delay)						{ base->SetDelay(delay); return (*this); }
 
-		operator ActionPtr() const
-		{
-			if (loop)
-				return ActionPtr(new (std::nothrow) Loop(base));
-			return base;
-		}
+		// 设置动作结束回调函数
+		inline ActionHelper& SetDoneCallback(ActionCallback const& cb)		{ base->SetDoneCallback(cb); return (*this); }
 
-	private:
-		ActionPtr	base;
-		int			loop;
+		// 设置动作循环结束时的回调函数
+		inline ActionHelper& SetLoopDoneCallback(ActionCallback const& cb)	{ base->SetLoopDoneCallback(cb); return (*this); }
+
+		// 动作结束时移除目标节点
+		inline ActionHelper& RemoveTargetWhenDone()							{ base->RemoveTargetWhenDone(); return (*this); }
+
+		// 获取指针
+		inline ActionPtr const& Get() const									{ return base; }
+
+		inline ActionHelper(ActionPtr const& base)							: base(base) {}
+
+		inline operator ActionPtr() const									{ return base; }
+
+	protected:
+		ActionPtr base;
 	};
 
-	struct E2D_API TweenActionHelper
+	struct TweenHelper
 	{
-		TweenActionHelper& SetDuration(Duration dur) { this->dur = dur; return (*this); }
+		// 设置动画持续时长
+		inline TweenHelper& SetDuration(Duration dur)						{ base->SetDuration(dur); return (*this); }
 
-		TweenActionHelper& SetLoopCount(int loop) { this->loop = loop; return (*this); }
+		// 设置循环次数
+		inline TweenHelper& SetLoops(int loops)								{ base->SetLoops(loops); return (*this); }
 
-		TweenActionHelper& SetEaseFunc(EaseFunc ease) { this->ease = ease; return (*this); }
+		// 设置缓动函数
+		inline TweenHelper& SetEaseFunc(EaseFunc ease)						{ base->SetEaseFunc(ease); return (*this); }
 
-		TweenActionHelper(ActionTweenPtr const& base) : base(base), dur(), loop(0), ease(nullptr)
-		{
-			dur = base->GetDuration();
-		}
+		// 设置动作延迟
+		inline TweenHelper& SetDelay(Duration delay)						{ base->SetDelay(delay); return (*this); }
 
-		operator ActionPtr() const
-		{
-			base->SetEaseFunc(ease);
-			base->SetDuration(dur);
+		// 设置动作结束回调函数
+		inline TweenHelper& SetDoneCallback(ActionCallback const& cb)		{ base->SetDoneCallback(cb); return (*this); }
 
-			if (loop)
-				return ActionPtr(new (std::nothrow) Loop(base));
-			return base;
-		}
+		// 设置动作循环结束时的回调函数
+		inline TweenHelper& SetLoopDoneCallback(ActionCallback const& cb)	{ base->SetLoopDoneCallback(cb); return (*this); }
 
-	private:
-		ActionTweenPtr	base;
-		Duration		dur;
-		int				loop;
-		EaseFunc		ease;
+		// 动作结束时移除目标节点
+		inline TweenHelper& RemoveTargetWhenDone()							{ base->RemoveTargetWhenDone(); return (*this); }
+
+		// 获取指针
+		inline ActionTweenPtr const& Get() const							{ return base; }
+		
+		inline TweenHelper(ActionTweenPtr const& base)						: base(base) {}
+
+		inline operator ActionPtr() const									{ return base; }
+
+	protected:
+		ActionTweenPtr base;
 	};
 
+	// Tween actions helper
 	struct Tween
 	{
 	public:
-		static inline TweenActionHelper
+		static inline TweenHelper
 			MoveBy(Point const& vector)
 		{
-			return TweenActionHelper(new easy2d::MoveBy(0, vector));
+			return TweenHelper(new easy2d::MoveBy(0, vector));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			MoveTo(Point const& pos)
 		{
-			return TweenActionHelper(new easy2d::MoveTo(0, pos));
+			return TweenHelper(new easy2d::MoveTo(0, pos));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 		JumpBy(
 			Point const& pos,	/* 目的坐标 */
 			float height,		/* 跳跃高度 */
 			int jumps = 1)		/* 跳跃次数 */
 		{
-			return TweenActionHelper(new easy2d::JumpBy(0, pos, height, jumps));
+			return TweenHelper(new easy2d::JumpBy(0, pos, height, jumps));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 		JumpTo(
 			Point const& pos,	/* 目的坐标 */
 			float height,		/* 跳跃高度 */
 			int jumps = 1)		/* 跳跃次数 */
 		{
-			return TweenActionHelper(new easy2d::JumpTo(0, pos, height, jumps));
+			return TweenHelper(new easy2d::JumpTo(0, pos, height, jumps));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			ScaleBy(float scale)
 		{
-			return TweenActionHelper(new easy2d::ScaleBy(0, scale));
+			return TweenHelper(new easy2d::ScaleBy(0, scale));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			ScaleBy(float scale_x, float scale_y)
 		{
-			return TweenActionHelper(new easy2d::ScaleBy(0, scale_x, scale_y));
+			return TweenHelper(new easy2d::ScaleBy(0, scale_x, scale_y));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			ScaleTo(float scale)
 		{
-			return TweenActionHelper(new easy2d::ScaleTo(0, scale));
+			return TweenHelper(new easy2d::ScaleTo(0, scale));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			ScaleTo(float scale_x, float scale_y)
 		{
-			return TweenActionHelper(new easy2d::ScaleTo(0, scale_x, scale_y));
+			return TweenHelper(new easy2d::ScaleTo(0, scale_x, scale_y));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			OpacityBy(float opacity)
 		{
-			return TweenActionHelper(new easy2d::OpacityBy(0, opacity));
+			return TweenHelper(new easy2d::OpacityBy(0, opacity));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			OpacityTo(float opacity)
 		{
-			return TweenActionHelper(new easy2d::OpacityTo(0, opacity));
+			return TweenHelper(new easy2d::OpacityTo(0, opacity));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			FadeIn(Duration dur)
 		{
-			return TweenActionHelper(new easy2d::FadeIn(dur));
+			return TweenHelper(new easy2d::FadeIn(dur));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			FadeOut(Duration dur)
 		{
-			return TweenActionHelper(new easy2d::FadeOut(dur));
+			return TweenHelper(new easy2d::FadeOut(dur));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			RotateBy(float rotation)
 		{
-			return TweenActionHelper(new easy2d::RotateBy(0, rotation));
+			return TweenHelper(new easy2d::RotateBy(0, rotation));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			RotateTo(float rotation)
 		{
-			return TweenActionHelper(new easy2d::RotateTo(0, rotation));
+			return TweenHelper(new easy2d::RotateTo(0, rotation));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 		Path(
 			GeometryPtr const& geo,		/* 几何图形 */
 			bool rotating = false,		/* 沿路径切线方向旋转 */
 			float start = 0.f,			/* 起点 */
 			float end = 1.f)			/* 终点 */
 		{
-			return TweenActionHelper(new easy2d::PathAction(0, geo, rotating, start, end));
+			return TweenHelper(new easy2d::PathAction(0, geo, rotating, start, end));
 		}
 
-		static inline TweenActionHelper
+		static inline TweenHelper
 			Animation(FramesPtr const& frames)
 		{
-			return TweenActionHelper(new easy2d::Animation(0, frames));
-		}
-
-		static inline ActionHelper
-			Delay(Duration dur)
-		{
-			return ActionHelper(new easy2d::Delay(dur));
+			return TweenHelper(new easy2d::Animation(0, frames));
 		}
 
 		static inline ActionHelper
diff --git a/src/core/ActionManager.cpp b/src/core/ActionManager.cpp
index bd1a3cad..4bf130f1 100644
--- a/src/core/ActionManager.cpp
+++ b/src/core/ActionManager.cpp
@@ -23,7 +23,7 @@
 
 namespace easy2d
 {
-	void ActionManager::UpdateActions(Node* target, Duration dt)
+	void ActionManager::UpdateActions(NodePtr const& target, Duration dt)
 	{
 		if (actions_.IsEmpty() || !target)
 			return;
@@ -34,9 +34,9 @@ namespace easy2d
 			next = action->NextItem();
 
 			if (action->IsRunning())
-				action->Update(target, dt);
+				action->UpdateStep(target, dt);
 
-			if (action->IsDone())
+			if (action->IsRemoveable())
 				actions_.Remove(action);
 		}
 	}
@@ -47,7 +47,6 @@ namespace easy2d
 
 		if (action)
 		{
-			action->Start();
 			actions_.PushBack(action);
 		}
 	}
diff --git a/src/core/ActionManager.h b/src/core/ActionManager.h
index a6e60f05..d1ff8cee 100644
--- a/src/core/ActionManager.h
+++ b/src/core/ActionManager.h
@@ -19,7 +19,7 @@
 // THE SOFTWARE.
 
 #pragma once
-#include "Action.hpp"
+#include "Action.h"
 
 namespace easy2d
 {
@@ -51,7 +51,7 @@ namespace easy2d
 		Actions const& GetAllActions() const;
 
 	protected:
-		void UpdateActions(Node* target, Duration dt);
+		void UpdateActions(NodePtr const& target, Duration dt);
 
 	protected:
 		Actions actions_;
diff --git a/src/core/ActionTween.cpp b/src/core/ActionTween.cpp
index 8cd0d90e..28814458 100644
--- a/src/core/ActionTween.cpp
+++ b/src/core/ActionTween.cpp
@@ -21,7 +21,6 @@
 #include "ActionTween.h"
 #include "include-forwards.h"
 #include "Node.h"
-#include 
 
 namespace easy2d
 {
@@ -66,14 +65,12 @@ namespace easy2d
 	//-------------------------------------------------------
 
 	ActionTween::ActionTween()
-		: elapsed_()
-		, duration_()
+		: dur_()
 		, ease_func_(nullptr)
 	{
 	}
 
 	ActionTween::ActionTween(Duration duration, EaseFunc func)
-		: elapsed_()
 	{
 		SetDuration(duration);
 		SetEaseFunc(func);
@@ -89,54 +86,42 @@ namespace easy2d
 		return ease_func_;
 	}
 
-	void ActionTween::Reset()
-	{
-		Action::Reset();
-		elapsed_ = Duration{};
-	}
-
 	Duration ActionTween::GetDuration() const
 	{
-		return duration_;
+		return dur_;
 	}
 
-	void ActionTween::Init(Node* target)
+	void ActionTween::Update(NodePtr const& target, Duration dt)
 	{
-		Action::Init(target);
-	}
+		float percent;
 
-	void ActionTween::Update(Node* target, Duration dt)
-	{
-		Action::Update(target, dt);
-
-		float step;
-
-		if (duration_.IsZero())
+		if (dur_.IsZero())
 		{
-			step = 1.f;
-			this->Stop();
+			percent = 1.f;
+			Complete(target);
 		}
 		else
 		{
-			elapsed_ += dt;
-			step = elapsed_ / duration_;
+			Duration elapsed = elapsed_ - delay_;
+			float loops_done = elapsed / dur_;
 
-			if (1.f <= step)
+			while (loops_done_ < static_cast(loops_done))
 			{
-				step = 1.f;
-				this->Stop();
+				Complete(target);	// loops_done_++
 			}
+
+			percent = (status_ == Status::Done) ? 1.f : (loops_done - static_cast(loops_done_));
 		}
 
 		if (ease_func_)
-			step = ease_func_(step);
+			percent = ease_func_(percent);
 
-		UpdateStep(target, step);
+		UpdateTween(target, percent);
 	}
 
 	void ActionTween::SetDuration(Duration duration)
 	{
-		duration_ = duration;
+		dur_ = duration;
 	}
 
 
@@ -150,22 +135,20 @@ namespace easy2d
 		delta_pos_ = vector;
 	}
 
-	void MoveBy::Init(Node* target)
+	void MoveBy::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (target)
 		{
 			prev_pos_ = start_pos_ = target->GetPosition();
 		}
 	}
 
-	void MoveBy::UpdateStep(Node* target, float step)
+	void MoveBy::UpdateTween(NodePtr const& target, float percent)
 	{
 		Point diff = target->GetPosition() - prev_pos_;
 		start_pos_ = start_pos_ + diff;
 
-		Point new_pos = start_pos_ + (delta_pos_ * step);
+		Point new_pos = start_pos_ + (delta_pos_ * percent);
 		target->SetPosition(new_pos);
 
 		prev_pos_ = new_pos;
@@ -173,12 +156,12 @@ namespace easy2d
 
 	ActionPtr MoveBy::Clone() const
 	{
-		return new (std::nothrow) MoveBy(duration_, delta_pos_, ease_func_);
+		return new (std::nothrow) MoveBy(dur_, delta_pos_, ease_func_);
 	}
 
 	ActionPtr MoveBy::Reverse() const
 	{
-		return new (std::nothrow) MoveBy(duration_, -delta_pos_, ease_func_);
+		return new (std::nothrow) MoveBy(dur_, -delta_pos_, ease_func_);
 	}
 
 	MoveTo::MoveTo(Duration duration, Point const& pos, EaseFunc func)
@@ -189,10 +172,10 @@ namespace easy2d
 
 	ActionPtr MoveTo::Clone() const
 	{
-		return new (std::nothrow) MoveTo(duration_, end_pos_, ease_func_);
+		return new (std::nothrow) MoveTo(dur_, end_pos_, ease_func_);
 	}
 
-	void MoveTo::Init(Node* target)
+	void MoveTo::Init(NodePtr const& target)
 	{
 		MoveBy::Init(target);
 		delta_pos_ = end_pos_ - start_pos_;
@@ -213,30 +196,28 @@ namespace easy2d
 
 	ActionPtr JumpBy::Clone() const
 	{
-		return new (std::nothrow) JumpBy(duration_, delta_pos_, height_, jumps_, ease_func_);
+		return new (std::nothrow) JumpBy(dur_, delta_pos_, height_, jumps_, ease_func_);
 	}
 
 	ActionPtr JumpBy::Reverse() const
 	{
-		return new (std::nothrow) JumpBy(duration_, -delta_pos_, height_, jumps_, ease_func_);
+		return new (std::nothrow) JumpBy(dur_, -delta_pos_, height_, jumps_, ease_func_);
 	}
 
-	void JumpBy::Init(Node* target)
+	void JumpBy::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (target)
 		{
 			prev_pos_ = start_pos_ = target->GetPosition();
 		}
 	}
 
-	void JumpBy::UpdateStep(Node* target, float step)
+	void JumpBy::UpdateTween(NodePtr const& target, float percent)
 	{
-		float frac = fmod(step * jumps_, 1.f);
-		float x = delta_pos_.x * step;
+		float frac = fmod(percent * jumps_, 1.f);
+		float x = delta_pos_.x * percent;
 		float y = height_ * 4 * frac * (1 - frac);
-		y += delta_pos_.y * step;
+		y += delta_pos_.y * percent;
 
 		Point diff = target->GetPosition() - prev_pos_;
 		start_pos_ = diff + start_pos_;
@@ -255,10 +236,10 @@ namespace easy2d
 
 	ActionPtr JumpTo::Clone() const
 	{
-		return new (std::nothrow) JumpTo(duration_, end_pos_, height_, jumps_, ease_func_);
+		return new (std::nothrow) JumpTo(dur_, end_pos_, height_, jumps_, ease_func_);
 	}
 
-	void JumpTo::Init(Node* target)
+	void JumpTo::Init(NodePtr const& target)
 	{
 		JumpBy::Init(target);
 		delta_pos_ = end_pos_ - start_pos_;
@@ -283,10 +264,8 @@ namespace easy2d
 		delta_y_ = scale_y;
 	}
 
-	void ScaleBy::Init(Node* target)
+	void ScaleBy::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (target)
 		{
 			start_scale_x_ = target->GetScaleX();
@@ -294,19 +273,19 @@ namespace easy2d
 		}
 	}
 
-	void ScaleBy::UpdateStep(Node* target, float step)
+	void ScaleBy::UpdateTween(NodePtr const& target, float percent)
 	{
-		target->SetScale(start_scale_x_ + delta_x_ * step, start_scale_y_ + delta_y_ * step);
+		target->SetScale(start_scale_x_ + delta_x_ * percent, start_scale_y_ + delta_y_ * percent);
 	}
 
 	ActionPtr ScaleBy::Clone() const
 	{
-		return new (std::nothrow) ScaleBy(duration_, delta_x_, delta_y_, ease_func_);
+		return new (std::nothrow) ScaleBy(dur_, delta_x_, delta_y_, ease_func_);
 	}
 
 	ActionPtr ScaleBy::Reverse() const
 	{
-		return new (std::nothrow) ScaleBy(duration_, -delta_x_, -delta_y_, ease_func_);
+		return new (std::nothrow) ScaleBy(dur_, -delta_x_, -delta_y_, ease_func_);
 	}
 
 	ScaleTo::ScaleTo(Duration duration, float scale, EaseFunc func)
@@ -325,10 +304,10 @@ namespace easy2d
 
 	ActionPtr ScaleTo::Clone() const
 	{
-		return new (std::nothrow) ScaleTo(duration_, end_scale_x_, end_scale_y_, ease_func_);
+		return new (std::nothrow) ScaleTo(dur_, end_scale_x_, end_scale_y_, ease_func_);
 	}
 
-	void ScaleTo::Init(Node* target)
+	void ScaleTo::Init(NodePtr const& target)
 	{
 		ScaleBy::Init(target);
 		delta_x_ = end_scale_x_ - start_scale_x_;
@@ -346,29 +325,27 @@ namespace easy2d
 		delta_val_ = opacity;
 	}
 
-	void OpacityBy::Init(Node* target)
+	void OpacityBy::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (target)
 		{
 			start_val_ = target->GetOpacity();
 		}
 	}
 
-	void OpacityBy::UpdateStep(Node* target, float step)
+	void OpacityBy::UpdateTween(NodePtr const& target, float percent)
 	{
-		target->SetOpacity(start_val_ + delta_val_ * step);
+		target->SetOpacity(start_val_ + delta_val_ * percent);
 	}
 
 	ActionPtr OpacityBy::Clone() const
 	{
-		return new (std::nothrow) OpacityBy(duration_, delta_val_, ease_func_);
+		return new (std::nothrow) OpacityBy(dur_, delta_val_, ease_func_);
 	}
 
 	ActionPtr OpacityBy::Reverse() const
 	{
-		return new (std::nothrow) OpacityBy(duration_, -delta_val_, ease_func_);
+		return new (std::nothrow) OpacityBy(dur_, -delta_val_, ease_func_);
 	}
 
 	OpacityTo::OpacityTo(Duration duration, float opacity, EaseFunc func)
@@ -379,10 +356,10 @@ namespace easy2d
 
 	ActionPtr OpacityTo::Clone() const
 	{
-		return new (std::nothrow) OpacityTo(duration_, end_val_, ease_func_);
+		return new (std::nothrow) OpacityTo(dur_, end_val_, ease_func_);
 	}
 
-	void OpacityTo::Init(Node* target)
+	void OpacityTo::Init(NodePtr const& target)
 	{
 		OpacityBy::Init(target);
 		delta_val_ = end_val_ - start_val_;
@@ -409,19 +386,17 @@ namespace easy2d
 	{
 	}
 
-	void RotateBy::Init(Node* target)
+	void RotateBy::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (target)
 		{
 			start_val_ = target->GetRotation();
 		}
 	}
 
-	void RotateBy::UpdateStep(Node* target, float step)
+	void RotateBy::UpdateTween(NodePtr const& target, float percent)
 	{
-		float rotation = start_val_ + delta_val_ * step;
+		float rotation = start_val_ + delta_val_ * percent;
 		if (rotation > 360.f)
 			rotation -= 360.f;
 
@@ -430,12 +405,12 @@ namespace easy2d
 
 	ActionPtr RotateBy::Clone() const
 	{
-		return new (std::nothrow) RotateBy(duration_, delta_val_, ease_func_);
+		return new (std::nothrow) RotateBy(dur_, delta_val_, ease_func_);
 	}
 
 	ActionPtr RotateBy::Reverse() const
 	{
-		return new (std::nothrow) RotateBy(duration_, -delta_val_, ease_func_);
+		return new (std::nothrow) RotateBy(dur_, -delta_val_, ease_func_);
 	}
 
 	RotateTo::RotateTo(Duration duration, float rotation, EaseFunc func)
@@ -446,10 +421,10 @@ namespace easy2d
 
 	ActionPtr RotateTo::Clone() const
 	{
-		return new (std::nothrow) RotateTo(duration_, end_val_, ease_func_);
+		return new (std::nothrow) RotateTo(dur_, end_val_, ease_func_);
 	}
 
-	void RotateTo::Init(Node* target)
+	void RotateTo::Init(NodePtr const& target)
 	{
 		RotateBy::Init(target);
 		delta_val_ = end_val_ - start_val_;
@@ -471,27 +446,22 @@ namespace easy2d
 
 	ActionPtr PathAction::Clone() const
 	{
-		return new PathAction(duration_, geo_, rotating_, start_, end_, ease_func_);
+		return new PathAction(dur_, geo_, rotating_, start_, end_, ease_func_);
 	}
 
 	ActionPtr PathAction::Reverse() const
 	{
-		return new PathAction(duration_, geo_, rotating_, end_, start_, ease_func_);
+		return new PathAction(dur_, geo_, rotating_, end_, start_, ease_func_);
 	}
 
-	void PathAction::Init(Node * target)
+	void PathAction::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
-		if (target)
-		{
-			start_pos_ = target->GetPosition();
-		}
+		start_pos_ = target->GetPosition();
 	}
 
-	void PathAction::UpdateStep(Node* target, float step)
+	void PathAction::UpdateTween(NodePtr const& target, float percent)
 	{
-		float length = geo_->GetLength() * std::min(std::max((end_ - start_) * step + start_, 0.f), 1.f);
+		float length = geo_->GetLength() * std::min(std::max((end_ - start_) * percent + start_, 0.f), 1.f);
 
 		Point point, tangent;
 		if (geo_->ComputePointAt(length, &point, &tangent))
diff --git a/src/core/ActionTween.h b/src/core/ActionTween.h
index 0ef790b2..b4935588 100644
--- a/src/core/ActionTween.h
+++ b/src/core/ActionTween.h
@@ -19,7 +19,7 @@
 // THE SOFTWARE.
 
 #pragma once
-#include "Action.hpp"
+#include "Action.h"
 #include "logs.h"
 #include "Geometry.h"  // PathAction
 #include "../math/ease.hpp"
@@ -93,22 +93,17 @@ namespace easy2d
 
 		EaseFunc const& GetEaseFunc() const;
 
-		void Reset() override;
-
 		Duration GetDuration() const;
 
 		void SetDuration(Duration duration);
 
 	protected:
-		void Init(Node* target) override;
+		void Update(NodePtr const& target, Duration dt) override;
 
-		void Update(Node* target, Duration dt) override;
-
-		virtual void UpdateStep(Node* target, float step) = 0;
+		virtual void UpdateTween(NodePtr const& target, float percent) = 0;
 
 	protected:
-		Duration duration_;
-		Duration elapsed_;
+		Duration dur_;
 		EaseFunc ease_func_;
 	};
 
@@ -131,9 +126,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		Point	start_pos_;
@@ -164,7 +159,7 @@ namespace easy2d
 		}
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 	protected:
 		Point end_pos_;
@@ -191,9 +186,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		Point	start_pos_;
@@ -228,7 +223,7 @@ namespace easy2d
 		}
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 	protected:
 		Point end_pos_;
@@ -260,9 +255,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		float	start_scale_x_;
@@ -301,7 +296,7 @@ namespace easy2d
 		}
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 	protected:
 		float	end_scale_x_;
@@ -327,9 +322,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		float start_val_;
@@ -359,7 +354,7 @@ namespace easy2d
 		}
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 	protected:
 		float end_val_;
@@ -410,9 +405,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		float start_val_;
@@ -442,7 +437,7 @@ namespace easy2d
 		}
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
 	protected:
 		float end_val_;
@@ -470,9 +465,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		bool		rotating_;
diff --git a/src/core/Animation.cpp b/src/core/Animation.cpp
index cb052fca..a0ed981f 100644
--- a/src/core/Animation.cpp
+++ b/src/core/Animation.cpp
@@ -34,59 +34,56 @@ namespace easy2d
 		: ActionTween(duration, func)
 		, frames_(nullptr)
 	{
-		this->SetAnimation(animation);
+		this->SetFrames(animation);
 	}
 
 	Animation::~Animation()
 	{
 	}
 
-	FramesPtr Animation::GetAnimation() const
+	FramesPtr Animation::GetFrames() const
 	{
 		return frames_;
 	}
 
-	void Animation::SetAnimation(FramesPtr const& animation)
+	void Animation::SetFrames(FramesPtr const& frames)
 	{
-		if (animation && animation != frames_)
-		{
-			frames_ = animation;
-		}
+		frames_ = frames;
 	}
 
-	void Animation::Init(Node* target)
+	void Animation::Init(NodePtr const& target)
 	{
-		ActionTween::Init(target);
-
 		if (!frames_ || frames_->GetFrames().empty())
 		{
-			this->Stop();
+			Done();
 			return;
 		}
 
-		auto sprite_target = dynamic_cast(target);
+		auto sprite_target = dynamic_cast(target.Get());
 		if (sprite_target && frames_)
 		{
 			sprite_target->Load(frames_->GetFrames()[0]);
 		}
 	}
 
-	void Animation::UpdateStep(Node * target, float step)
+	void Animation::UpdateTween(NodePtr const& target, float percent)
 	{
-		E2D_ASSERT(dynamic_cast(target) && "Animation only supports Sprites");
+		auto sprite_target = dynamic_cast(target.Get());
+
+		E2D_ASSERT(sprite_target && "Animation only supports Sprites");
 
 		const auto& frames = frames_->GetFrames();
 		int size = frames.size();
-		int index = std::min(static_cast(math::Floor(size * step)), size - 1);
+		int index = std::min(static_cast(math::Floor(size * percent)), size - 1);
 
-		static_cast(target)->Load(frames[index]);
+		sprite_target->Load(frames[index]);
 	}
 
 	ActionPtr Animation::Clone() const
 	{
 		if (frames_)
 		{
-			return new (std::nothrow) Animation(duration_, frames_, ease_func_);
+			return new (std::nothrow) Animation(dur_, frames_, ease_func_);
 		}
 		return nullptr;
 	}
@@ -98,7 +95,7 @@ namespace easy2d
 			FramesPtr frames = frames_->Reverse();
 			if (frames)
 			{
-				return new (std::nothrow) Animation(duration_, frames, ease_func_);
+				return new (std::nothrow) Animation(dur_, frames, ease_func_);
 			}
 		}
 		return nullptr;
diff --git a/src/core/Animation.h b/src/core/Animation.h
index 1a944c76..878f4e7d 100644
--- a/src/core/Animation.h
+++ b/src/core/Animation.h
@@ -39,11 +39,11 @@ namespace easy2d
 		virtual ~Animation();
 
 		// 获取动画
-		FramesPtr GetAnimation() const;
+		FramesPtr GetFrames() const;
 
 		// 设置动画
-		void SetAnimation(
-			FramesPtr const& animation
+		void SetFrames(
+			FramesPtr const& frames
 		);
 
 		// 获取该动作的拷贝对象
@@ -53,9 +53,9 @@ namespace easy2d
 		ActionPtr Reverse() const override;
 
 	protected:
-		void Init(Node* target) override;
+		void Init(NodePtr const& target) override;
 
-		void UpdateStep(Node* target, float step) override;
+		void UpdateTween(NodePtr const& target, float percent) override;
 
 	protected:
 		FramesPtr frames_;
diff --git a/src/core/Array.h b/src/core/Array.h
index 8081fffd..a0bd2a3d 100644
--- a/src/core/Array.h
+++ b/src/core/Array.h
@@ -96,7 +96,7 @@ namespace easy2d
 
 	private:
 		int size_;
-		int	capacity_;
+		int capacity_;
 		_Ty* data_;
 	};
 }
diff --git a/src/core/Delay.h b/src/core/Delay.h
deleted file mode 100644
index 9a15a557..00000000
--- a/src/core/Delay.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2016-2018 Easy2D - Nomango
-// 
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#pragma once
-#include "Action.hpp"
-
-namespace easy2d
-{
-	// 延时动作
-	class E2D_API Delay
-		: public Action
-	{
-	public:
-		explicit Delay(
-			Duration duration	/* 延迟时长(秒) */
-		);
-
-		// 获取该动作的拷贝对象
-		ActionPtr Clone() const override;
-
-		// 获取该动作的倒转
-		ActionPtr Reverse() const override;
-
-		// 重置动作
-		void Reset() override;
-
-	protected:
-		void Init(Node* target) override;
-
-		void Update(Node* target, Duration dt) override;
-
-	protected:
-		Duration delay_;
-		Duration delta_;
-	};
-}
diff --git a/src/core/Node.cpp b/src/core/Node.cpp
index 51796872..31b19018 100644
--- a/src/core/Node.cpp
+++ b/src/core/Node.cpp
@@ -19,7 +19,7 @@
 // THE SOFTWARE.
 
 #include "Node.h"
-#include "Action.hpp"
+#include "Action.h"
 #include "Factory.h"
 #include "Scene.h"
 #include "Task.h"
diff --git a/src/core/helper.hpp b/src/core/helper.hpp
index f8828b12..a75be238 100644
--- a/src/core/helper.hpp
+++ b/src/core/helper.hpp
@@ -112,9 +112,7 @@ namespace easy2d
 	E2D_DECLARE_SMART_PTR(RotateBy);
 	E2D_DECLARE_SMART_PTR(RotateTo);
 	E2D_DECLARE_SMART_PTR(PathAction);
-	E2D_DECLARE_SMART_PTR(Delay);
 	E2D_DECLARE_SMART_PTR(Animation);
-	E2D_DECLARE_SMART_PTR(Loop);
 	E2D_DECLARE_SMART_PTR(Sequence);
 	E2D_DECLARE_SMART_PTR(Spawn);
 
diff --git a/src/easy2d.h b/src/easy2d.h
index 769e825b..2b9752ed 100644
--- a/src/easy2d.h
+++ b/src/easy2d.h
@@ -57,12 +57,11 @@
 #include "core/Geometry.h"
 #include "core/Task.h"
 #include "core/TaskManager.h"
-#include "core/Action.hpp"
+#include "core/Action.h"
 #include "core/ActionGroup.h"
 #include "core/ActionTween.h"
 #include "core/ActionHelper.h"
 #include "core/Animation.h"
-#include "core/Delay.h"
 #include "core/ActionManager.h"
 #include "core/Transition.h"