Browse Source

Add LoopMode2D to control animation loop mode, make spriter animation sample in force loop mode.

Aster@中国上海 11 years ago
parent
commit
318e388777

+ 1 - 1
Bin/Data/LuaScripts/33_Urho2DSpriterAnimation.lua

@@ -140,7 +140,7 @@ end
 function HandleMouseButtonDown(eventType, eventData)
     local animatedSprite = spriteNode:GetComponent("AnimatedSprite2D")
     animationIndex = (animationIndex + 1) % 7
-    animatedSprite.animation = animationNames[animationIndex + 1]
+    animatedSprite:SetAnimation(animationNames[animationIndex + 1], LM_FORCE_LOOPED)
 end
 
 -- Create XML patch instructions for screen joystick layout specific to this sample app

+ 1 - 1
Bin/Data/Scripts/33_Urho2DSpriterAnimation.as

@@ -146,7 +146,7 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
 {
     AnimatedSprite2D@ animatedSprite = spriteNode.GetComponent("AnimatedSprite2D");
     animationIndex = (animationIndex + 1) % 7;
-    animatedSprite.animation = animationNames[animationIndex];
+    animatedSprite.SetAnimation(animationNames[animationIndex], LM_FORCE_LOOPED);
 }
 
 // Create XML patch instructions for screen joystick layout specific to this sample app

+ 14 - 4
Source/Engine/LuaScript/pkgs/Urho2D/AnimatedSprite2D.pkg

@@ -1,5 +1,12 @@
 $#include "AnimatedSprite2D.h"
 
+enum LoopMode2D
+{
+    LM_DEFAULT = 0,
+    LM_FORCE_LOOPED,
+    LM_FORCE_CLAMPED
+};
+
 class AnimatedSprite2D : Drawable
 {
     void SetLayer(int layer);
@@ -10,9 +17,10 @@ class AnimatedSprite2D : Drawable
     void SetFlipY(bool flipY);
     void SetColor(const Color& color);
     void SetSpeed(float speed);
-    void SetAnimation(const String name);
-    void SetAnimation(AnimationSet2D* animationSet, const String name);
+    void SetAnimation(AnimationSet2D* animationSet, const String name, LoopMode2D loopMode = LM_DEFAULT);
+    void SetAnimation(const String name, LoopMode2D loopMode = LM_DEFAULT);
     void SetAnimationSet(AnimationSet2D* animationSet);
+    void SetLoopMode(LoopMode2D loopMode);
 
     int GetLayer() const;
     int GetOrderInLayer() const;
@@ -21,8 +29,9 @@ class AnimatedSprite2D : Drawable
     bool GetFlipY() const;
     const Color& GetColor() const;
     float GetSpeed() const;
-    AnimationSet2D* GetAnimationSet() const;
     const String GetAnimation() const;
+    AnimationSet2D* GetAnimationSet() const;
+    LoopMode2D GetLoopMode() const;
 
     tolua_property__get_set int layer;
     tolua_property__get_set int orderInLayer;
@@ -31,6 +40,7 @@ class AnimatedSprite2D : Drawable
     tolua_property__get_set bool flipY;
     tolua_property__get_set Color& color;
     tolua_property__get_set float speed;
-    tolua_property__get_set AnimationSet2D* animationSet;
     tolua_property__get_set String animation;
+    tolua_property__get_set AnimationSet2D* animationSet;
+    tolua_property__get_set LoopMode2D loopMode;
 };

+ 11 - 3
Source/Engine/Script/Urho2DAPI.cpp

@@ -142,6 +142,11 @@ static void RegisterAnimationSet2D(asIScriptEngine* engine)
 
 static void RegisterAnimatedSprite2D(asIScriptEngine* engine)
 {
+    engine->RegisterEnum("LoopMode2D");
+    engine->RegisterEnumValue("LoopMode2D", "LM_DEFAULT", LM_DEFAULT);
+    engine->RegisterEnumValue("LoopMode2D", "LM_FORCE_LOOPED", LM_FORCE_LOOPED);
+    engine->RegisterEnumValue("LoopMode2D", "LM_FORCE_CLAMPED", LM_FORCE_CLAMPED);
+
     RegisterDrawable<AnimatedSprite2D>(engine, "AnimatedSprite2D");
     engine->RegisterObjectMethod("AnimatedSprite2D", "void set_layer(int)", asMETHOD(AnimatedSprite2D, SetLayer), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedSprite2D", "int get_layer() const", asMETHOD(AnimatedSprite2D, GetLayer), asCALL_THISCALL);
@@ -158,11 +163,14 @@ static void RegisterAnimatedSprite2D(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimatedSprite2D", "const Color& get_color() const", asMETHOD(AnimatedSprite2D, GetColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedSprite2D", "void set_speed(float)", asMETHOD(AnimatedSprite2D, SetSpeed), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedSprite2D", "float get_speed() const", asMETHOD(AnimatedSprite2D, GetSpeed), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedSprite2D", "void SetAnimation(AnimationSet2D@+, const String&)", asMETHODPR(AnimatedSprite2D, SetAnimation, (AnimationSet2D*, const String&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "void SetAnimation(AnimationSet2D@+, const String&, LoopMode2D loopMode=LM_DEFAULT)", asMETHODPR(AnimatedSprite2D, SetAnimation, (AnimationSet2D*, const String&, LoopMode2D), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "void SetAnimation(const String&, LoopMode2D loopMode=LM_DEFAULT)", asMETHODPR(AnimatedSprite2D, SetAnimation, (const String&, LoopMode2D), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "void set_animation(const String&)", asMETHODPR(AnimatedSprite2D, SetAnimationAttr, (const String&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "const String& get_animation() const", asMETHOD(AnimatedSprite2D, GetAnimation), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedSprite2D", "void set_animationSet(AnimationSet2D@+)", asMETHOD(AnimatedSprite2D, SetAnimationSet), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedSprite2D", "AnimationSet2D@+ get_animationSet() const", asMETHOD(AnimatedSprite2D, GetAnimationSet), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedSprite2D", "void set_animation(const String&)", asMETHODPR(AnimatedSprite2D, SetAnimation, (const String&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedSprite2D", "const String& get_animation() const", asMETHOD(AnimatedSprite2D, GetAnimation), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "void set_loopMode(LoopMode2D)", asMETHOD(AnimatedSprite2D, SetLoopMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedSprite2D", "LoopMode2D get_loopMode() const", asMETHOD(AnimatedSprite2D, GetLoopMode), asCALL_THISCALL);
 }
 
 static void RegisterParticleEffect2D(asIScriptEngine* engine)

+ 100 - 42
Source/Engine/Urho2D/AnimatedSprite2D.cpp

@@ -40,6 +40,19 @@ namespace Urho3D
 extern const char* URHO2D_CATEGORY;
 extern const char* blendModeNames[];
 
+const char* loopModeNames[] = 
+{
+    "Default",
+    "ForceLooped",
+    "ForceClamped",
+    0
+};
+
+template<> LoopMode2D Variant::Get<LoopMode2D>() const
+{
+    return (LoopMode2D)GetInt();
+}
+
 AnimatedSprite2D::AnimatedSprite2D(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY),
     layer_(0),
@@ -49,6 +62,8 @@ AnimatedSprite2D::AnimatedSprite2D(Context* context) :
     flipY_(false),
     color_(Color::WHITE),
     speed_(1.0f),
+    loopMode_(LM_DEFAULT),
+    looped_(false),
     currentTime_(0.0f)
 {
 }
@@ -68,7 +83,8 @@ void AnimatedSprite2D::RegisterObject(Context* context)
     REF_ACCESSOR_ATTRIBUTE(AnimatedSprite2D, VAR_COLOR, "Color", GetColor, SetColor, Color, Color::WHITE, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedSprite2D, VAR_FLOAT, "Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedSprite2D, VAR_RESOURCEREF, "Animation Set", GetAnimationSetAttr, SetAnimationSetAttr, ResourceRef, ResourceRef(AnimatedSprite2D::GetTypeStatic()), AM_DEFAULT);
-    REF_ACCESSOR_ATTRIBUTE(AnimatedSprite2D, VAR_STRING, "Animation", GetAnimation, SetAnimation, String, String::EMPTY, AM_DEFAULT);
+    REF_ACCESSOR_ATTRIBUTE(AnimatedSprite2D, VAR_STRING, "Animation", GetAnimation, SetAnimationAttr, String, String::EMPTY, AM_DEFAULT);
+    ENUM_ACCESSOR_ATTRIBUTE(AnimatedSprite2D, "Loop Mode", GetLoopMode, SetLoopMode, LoopMode2D, loopModeNames, LM_DEFAULT, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(AnimatedSprite2D, Drawable);
 }
 
@@ -170,15 +186,19 @@ void AnimatedSprite2D::SetSpeed(float speed)
     MarkNetworkUpdate();
 }
 
-void AnimatedSprite2D::SetAnimation(AnimationSet2D* animationSet, const String& name)
+void AnimatedSprite2D::SetAnimation(AnimationSet2D* animationSet, const String& name, LoopMode2D loopMode)
 {
     animationSet_ = animationSet;
+
+    SetAnimation(name, loopMode);
+}
+
+void AnimatedSprite2D::SetAnimation(const String& name, LoopMode2D loopMode)
+{
     animationName_ = name;
-    
-    if (animationSet)
-        SetAnimation(animationSet->GetAnimation(name));
-    else
-        SetAnimation(0);
+
+    if (animationSet_)
+        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode);
 }
 
 void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
@@ -188,18 +208,30 @@ void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
 
     animationSet_ = animationSet;
 
-    if (animationSet_)
-        SetAnimation(animationSet_->GetAnimation(animationName_));
-    else
-        SetAnimation(0);
-
+    SetAnimation(animationName_, loopMode_);
 }
-void AnimatedSprite2D::SetAnimation(const String& name)
+
+void AnimatedSprite2D::SetLoopMode(LoopMode2D loopMode)
 {
-    animationName_ = name;
+    if (!animation_)
+        return;
 
-    if (animationSet_)
-        SetAnimation(animationSet_->GetAnimation(animationName_));
+    loopMode_ = loopMode;
+
+    switch (loopMode_)
+    {
+    case LM_FORCE_LOOPED:
+        looped_ = true;
+        break;
+
+    case LM_FORCE_CLAMPED:
+        looped_ = false;
+        break;
+
+    default:
+        looped_ = animation_->IsLooped();
+        break;
+    }
 }
 
 AnimationSet2D* AnimatedSprite2D::GetAnimationSet() const
@@ -243,6 +275,14 @@ void AnimatedSprite2D::OnNodeSet(Node* node)
     }
 }
 
+void AnimatedSprite2D::SetAnimationAttr(const String& name)
+{
+    animationName_ = name;
+
+    if (animationSet_)
+        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode_);
+}
+
 void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
 {
     boundingBox_.Clear();
@@ -260,23 +300,23 @@ void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
     boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
 }
 
-void AnimatedSprite2D::SetAnimation(Animation2D* animation)
+void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
 {
     if (animation == animation_)
     {
-        // Reset time
+        SetLoopMode(loopMode_);
+        
         currentTime_ = 0.0f;
+        UpdateAnimation(0.0f);
         return;
     }
 
     if (animation_)
     {
-        for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
-        {
-            if (timelineNodes_[i])
-                timelineNodes_[i]->Remove();
-        }
+        if (rootNode_)
+            rootNode_->Remove();
 
+        rootNode_ = 0;
         timelineNodes_.Clear();
     }
 
@@ -313,6 +353,7 @@ void AnimatedSprite2D::SetAnimation(Animation2D* animation)
         timelineTransformInfos_[i].parent_ = timeline.parent_;
     }
 
+    SetLoopMode(loopMode);
     UpdateAnimation(0.0f);
 
     MarkNetworkUpdate();
@@ -328,7 +369,7 @@ void AnimatedSprite2D::UpdateAnimation(float timeStep)
     float time;
     float animtationLength = animation_->GetLength();
 
-    if (animation_->IsLooped())
+    if (looped_)
     {
         time = fmodf(currentTime_, animtationLength);
         if (time < 0.0f)
@@ -343,31 +384,48 @@ void AnimatedSprite2D::UpdateAnimation(float timeStep)
         const Timeline2D& timeline = animation_->GetTimeline(i);
         
         const Vector<TimelineKey2D>& objectKeys = timeline.timelineKeys_;
+        unsigned index = objectKeys.Size() - 1;
         for (unsigned j = 0; j < objectKeys.Size() - 1; ++j)
         {
             if (time <= objectKeys[j + 1].time_)
             {
-                const TimelineKey2D& currKey = objectKeys[j];
-                const TimelineKey2D& nextKey = objectKeys[j + 1];
-                float t = (time - currKey.time_)  / (nextKey.time_ - currKey.time_);
-
-                timelineTransformInfos_[i].worldSpace_ = false;
-                timelineTransformInfos_[i].transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);
-
-                // Update sprite's sprite and hot spot and color
-                Node* timelineNode = timelineNodes_[i];
-                if (timelineNode)
-                {
-                    StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
-                    staticSprite->SetSprite(currKey.sprite_);
-                    staticSprite->SetHotSpot(currKey.hotSpot_.Lerp(nextKey.hotSpot_, t));
-                    float alpha = Lerp(currKey.alpha_, nextKey.alpha_, t);
-                    staticSprite->SetColor(Color(color_.r_, color_.g_, color_.b_, color_.a_ * alpha));
-                }
-
+                index = j;
                 break;
             }
         }
+
+        const TimelineKey2D& currKey = objectKeys[index];
+        if (index < objectKeys.Size() - 1)
+        {   
+            const TimelineKey2D& nextKey = objectKeys[index + 1];
+            float t = (time - currKey.time_)  / (nextKey.time_ - currKey.time_);
+            timelineTransformInfos_[i].worldSpace_ = false;
+            timelineTransformInfos_[i].transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);
+            // Update sprite's sprite and hot spot and color
+            Node* timelineNode = timelineNodes_[i];
+            if (timelineNode)
+            {
+                StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
+                staticSprite->SetSprite(currKey.sprite_);
+                staticSprite->SetHotSpot(currKey.hotSpot_.Lerp(nextKey.hotSpot_, t));
+                float alpha = Lerp(currKey.alpha_, nextKey.alpha_, t);
+                staticSprite->SetColor(Color(color_.r_, color_.g_, color_.b_, color_.a_ * alpha));
+            }
+        }
+        else
+        {
+            timelineTransformInfos_[i].worldSpace_ = false;
+            timelineTransformInfos_[i].transform_ = currKey.transform_;
+            // Update sprite's sprite and hot spot and color
+            Node* timelineNode = timelineNodes_[i];
+            if (timelineNode)
+            {
+                StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
+                staticSprite->SetSprite(currKey.sprite_);
+                staticSprite->SetHotSpot(currKey.hotSpot_);
+                staticSprite->SetColor(Color(color_.r_, color_.g_, color_.b_, color_.a_ * currKey.alpha_));
+            }
+        }        
     }
 
     // Calculate timeline world transform.

+ 28 - 7
Source/Engine/Urho2D/AnimatedSprite2D.h

@@ -25,6 +25,17 @@
 #include "Animation2D.h"
 #include "Drawable.h"
 
+/// Loop mode.
+enum LoopMode2D
+{
+    /// Default, use animation's value.
+    LM_DEFAULT = 0,
+    /// Force looped.
+    LM_FORCE_LOOPED,
+    /// Force clamped.
+    LM_FORCE_CLAMPED
+};
+
 namespace Urho3D
 {
 
@@ -62,12 +73,14 @@ public:
     void SetColor(const Color& color);
     /// Set speed.
     void SetSpeed(float speed);
-    /// Set animation by animation set and name.
-    void SetAnimation(AnimationSet2D* animationSet, const String& name);
+    /// Set animation by animation set, name and loop mode.
+    void SetAnimation(AnimationSet2D* animationSet, const String& name, LoopMode2D loopMode = LM_DEFAULT);
+    /// Set animation by name and loop mode.
+    void SetAnimation(const String& name, LoopMode2D loopMode = LM_DEFAULT);
     /// Set animation set.
     void SetAnimationSet(AnimationSet2D* animationSet);
-    /// Set animation by name.
-    void SetAnimation(const String& name);
+    /// Set loop mode.
+    void SetLoopMode(LoopMode2D loopMode);
 
     /// Return layer.
     int GetLayer() const { return layer_; }
@@ -83,10 +96,12 @@ public:
     const Color& GetColor() const { return color_; }
     /// Return speed.
     float GetSpeed() const { return speed_; }
-    /// Return animation.
-    AnimationSet2D* GetAnimationSet() const;
     /// Return animation name.
     const String& GetAnimation() const { return animationName_; }
+    /// Return animation.
+    AnimationSet2D* GetAnimationSet() const;
+    /// Return loop mode.
+    LoopMode2D GetLoopMode() const { return loopMode_; }
     /// Return root node.
     Node* GetRootNode() const;
 
@@ -94,6 +109,8 @@ public:
     void SetAnimationSetAttr(ResourceRef value);
     /// Return animation set attribute.
     ResourceRef GetAnimationSetAttr() const;
+    /// Set anmiation by name.
+    void SetAnimationAttr(const String& name);
 
 protected:
     /// Handle node being assigned.
@@ -101,7 +118,7 @@ protected:
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     /// Set animation.
-    void SetAnimation(Animation2D* animation);
+    void SetAnimation(Animation2D* animation, LoopMode2D loopMode);
     /// Update animation.
     void UpdateAnimation(float timeStep);
     /// Calculate timeline world world transform.
@@ -129,6 +146,10 @@ protected:
     String animationName_;
     /// Animation.
     SharedPtr<Animation2D> animation_;
+    /// Loop mode.
+    LoopMode2D loopMode_;
+    /// Looped.
+    bool looped_;
     /// Current time.
     float currentTime_;
     /// Root node.

+ 1 - 1
Source/Samples/33_Urho2DSpriterAnimation/Urho2DSpriterAnimation.cpp

@@ -189,5 +189,5 @@ void Urho2DSpriterAnimation::HandleMouseButtonDown(StringHash eventType, Variant
 {
     AnimatedSprite2D* animatedSprite = spriteNode_->GetComponent<AnimatedSprite2D>();
     animationIndex_ = (animationIndex_ + 1) % 7;
-    animatedSprite->SetAnimation(animationNames[animationIndex_]);
+    animatedSprite->SetAnimation(animationNames[animationIndex_], LM_FORCE_LOOPED);
 }