Browse Source

Add XAnimatedSprite2D class.[ci skip]

aster2013 11 years ago
parent
commit
587fca67f9

+ 1 - 1
Source/Engine/Urho2D/Drawable2D.h

@@ -55,7 +55,7 @@ public:
     virtual void OnSetEnabled();
 
     /// Set layer.
-    void SetLayer(int layer);
+    virtual void SetLayer(int layer);
     /// Set order in layer.
     void SetOrderInLayer(int orderInLayer);
     /// Set sprite.

+ 277 - 0
Source/Engine/Urho2D/XAnimatedSprite2D.cpp

@@ -0,0 +1,277 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// 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.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "Scene.h"
+#include "SceneEvents.h"
+#include "Sprite2D.h"
+#include "StaticSprite2D.h"
+#include "XAnimatedSprite2D.h"
+#include "XAnimation2D.h"
+#include "XAnimationSet2D.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const char* URHO2D_CATEGORY;
+
+XAnimatedSprite2D::XAnimatedSprite2D(Context* context) :
+    Drawable2D(context),
+    speed_(1.0f),
+    animationTime_(0.0f)
+{
+}
+
+XAnimatedSprite2D::~XAnimatedSprite2D()
+{
+}
+
+void XAnimatedSprite2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<XAnimatedSprite2D>(URHO2D_CATEGORY);
+    ACCESSOR_ATTRIBUTE(XAnimatedSprite2D, VAR_FLOAT, "Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
+}
+
+void XAnimatedSprite2D::OnSetEnabled()
+{
+    Drawable2D::OnSetEnabled();
+
+    Scene* scene = GetScene();
+    if (scene)
+    {
+        if (IsEnabledEffective())
+            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(XAnimatedSprite2D, HandleScenePostUpdate));
+        else
+            UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
+    }
+}
+
+void XAnimatedSprite2D::SetLayer(int layer)
+{
+    Drawable2D::SetLayer(layer);
+    for (unsigned i = 0; i < objectNodes_.Size(); ++i)
+    {
+        StaticSprite2D* objectSprite = objectNodes_[i]->GetComponent<StaticSprite2D>();
+        objectSprite->SetLayer(layer);
+    }
+}
+
+void XAnimatedSprite2D::SetSpeed(float speed)
+{
+    speed_ = speed;
+    MarkNetworkUpdate();
+}
+
+void XAnimatedSprite2D::SetAnimation(XAnimationSet2D* animationSet, const String& name)
+{
+    SetAnimation(animationSet->GetAnimation(name));
+}
+
+void XAnimatedSprite2D::SetAnimation(XAnimation2D* animation)
+{
+    if (animation == animation_)
+    {
+        // Reset time
+        animationTime_ = 0.0f;
+        return;
+    }
+
+    if (animation_)
+    {
+        // Remove all object nodes
+        for (unsigned i = 0; i < objectNodes_.Size(); ++i)
+            objectNodes_[i]->Remove();
+        objectNodes_.Clear();
+    }
+
+    animation_ = animation;
+    
+    if (!animation_)
+        return;
+
+    animationTime_ = 0.0f;
+    
+    for (unsigned i = 0; i < animation_->GetTimelines().Size(); ++i)
+    {
+        SharedPtr<Node> objectNode(GetNode()->CreateChild(animation_->GetTimelines()[i].name_));
+
+        StaticSprite2D* staticSprite = objectNode->CreateComponent<StaticSprite2D>();
+        staticSprite->SetLayer(GetLayer());
+        staticSprite->SetUseHotSpot(true);
+        staticSprite->SetBlendMode(BLEND_ALPHA);
+
+        objectNodes_.Push(objectNode);        
+    }
+
+    UpdateAnimation(0.0f);
+
+    UpdateDefaultMaterial();
+    MarkNetworkUpdate();
+}
+
+void XAnimatedSprite2D::SetAnimation(const String& name)
+{
+    if (!animation_)
+        return;
+
+    XAnimationSet2D* animationSet = animation_->GetAnimationSet();
+    if (!animationSet)
+        return;
+
+    SetAnimation(animationSet->GetAnimation(name));
+}
+
+XAnimation2D* XAnimatedSprite2D::GetAnimation() const
+{
+    return animation_;
+}
+
+void XAnimatedSprite2D::OnNodeSet(Node* node)
+{
+    Drawable2D::OnNodeSet(node);
+
+    if (node)
+    {
+        Scene* scene = GetScene();
+        if (scene && IsEnabledEffective())
+            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(XAnimatedSprite2D, HandleScenePostUpdate));
+    }
+}
+
+void XAnimatedSprite2D::OnWorldBoundingBoxUpdate()
+{
+    boundingBox_.Clear();
+    worldBoundingBox_.Clear();
+
+    for (unsigned i = 0; i < objectNodes_.Size(); ++i)
+    {
+        StaticSprite2D* ss = objectNodes_[i]->GetComponent<StaticSprite2D>();
+        worldBoundingBox_.Merge(ss->GetWorldBoundingBox());
+    }
+
+    boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
+}
+
+void XAnimatedSprite2D::UpdateVertices()
+{
+}
+
+void XAnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
+{
+    using namespace ScenePostUpdate;
+    float timeStep = eventData[P_TIMESTEP].GetFloat();
+    UpdateAnimation(timeStep);
+}
+
+void XAnimatedSprite2D::UpdateAnimation(float timeStep)
+{
+    if (!animation_)
+        return;
+    
+    animationTime_ += timeStep * speed_;
+
+    float animtationLength = animation_->GetLength();
+    float time;
+
+    if (animation_->IsLooped())
+    {
+        time = fmodf(animationTime_, animtationLength);
+        if (time < 0.0f)
+            time += animation_->GetLength();
+    }
+    else
+        time = Clamp(animationTime_, 0.0f, animtationLength);
+
+    const Vector<MainlineKey>& mainlineKeys = animation_->GetMainlineKeys();
+    const MainlineKey* mainlineKey = 0;
+    for (unsigned i = 1; i < mainlineKeys.Size(); ++i)
+    {
+        if (time < mainlineKeys[i].time_)
+        {
+            mainlineKey = &mainlineKeys[i - 1];
+            break;
+        }
+    }
+
+    if (!mainlineKey)
+        mainlineKey = &mainlineKeys.Back();
+
+    const Vector<Timeline>& timelines = animation_->GetTimelines();
+    for (unsigned i = 0; i < timelines.Size(); ++i)
+    {
+        Node* objectNode = objectNodes_[i];
+
+        const ObjectRef* objectRef = mainlineKey->GetObjectRef(i);
+        if (!objectRef)
+            objectNode->SetEnabled(false);
+        else
+        {
+            objectNode->SetEnabled(true);
+
+            StaticSprite2D* staticSprite = objectNode->GetComponent<StaticSprite2D>();
+            staticSprite->SetOrderInLayer(objectRef->zIndex_);
+
+            const Vector<ObjectKey>& objectKeys = timelines[i].objectKeys_;
+            for (unsigned j = 0; j < objectKeys.Size() - 1; ++j)
+            {
+                if (time <= objectKeys[j + 1].time_)
+                {
+                    const ObjectKey& currKey = objectKeys[j];
+                    const ObjectKey& nextKey = objectKeys[j + 1];
+
+                    float t = (time - currKey.time_)  / (nextKey.time_ - currKey.time_);
+                    if (t < 0.0f || t > 1.0f)
+                    {
+                        t = 0;
+                    }
+                    objectNode->SetPosition(currKey.position_.Lerp(nextKey.position_, t));
+
+                    float angle;
+                    if (currKey.spin_ > 0 && currKey.angle_ > nextKey.angle_)
+                        angle = Lerp(currKey.angle_, nextKey.angle_ + 360.0f, t);
+                    else if (currKey.spin_ < 0 && currKey.angle_ < nextKey.angle_)
+                        angle = Lerp(currKey.angle_, nextKey.angle_ - 360.0f, t);
+                    else
+                        angle = Lerp(currKey.angle_, nextKey.angle_, t);
+                    objectNode->SetRotation(angle);
+
+                    objectNode->SetScale(currKey.scale_.Lerp(nextKey.scale_, t));
+
+                    staticSprite->SetSprite(currKey.sprite_);
+                    staticSprite->SetHotSpot(currKey.pivot_.Lerp(nextKey.pivot_, t));
+                    float alpha_ = Lerp(currKey.alpha_, nextKey.alpha_, t);
+                    staticSprite->SetColor(Color(1.0f, 1.0f, 1.0f, alpha_));
+
+                    break;
+                }
+            }
+        }       
+    }
+
+    MarkForUpdate();
+}
+
+}
+

+ 88 - 0
Source/Engine/Urho2D/XAnimatedSprite2D.h

@@ -0,0 +1,88 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// 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 "Drawable2D.h"
+
+namespace Urho3D
+{
+
+class XAnimationSet2D;
+class XAnimation2D;
+
+/// Spriter animation component.
+class URHO3D_API XAnimatedSprite2D : public Drawable2D
+{
+    OBJECT(XAnimatedSprite2D);
+
+public:
+    /// Construct.
+    XAnimatedSprite2D(Context* context);
+    /// Destruct.
+    ~XAnimatedSprite2D();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled();
+    /// Set layer.
+    virtual void SetLayer(int layer);
+
+    /// Set speed.
+    void SetSpeed(float speed);
+
+    /// Set animation by animation set and name.
+    void SetAnimation(XAnimationSet2D* animationSet, const String& name);
+    /// Set animation.
+    void SetAnimation(XAnimation2D* animation);
+    /// Set animation by name.
+    void SetAnimation(const String& name);
+
+    /// Return speed.
+    float GetSpeed() const { return speed_; }
+    /// Return animation.
+    XAnimation2D* GetAnimation() const;
+
+protected:
+    /// Handle node being assigned.
+    virtual void OnNodeSet(Node* node);
+    /// Recalculate the world-space bounding box.
+    virtual void OnWorldBoundingBoxUpdate();
+    /// Update vertices.
+    virtual void UpdateVertices();
+    /// Handle scene post update.
+    void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
+    /// Update.
+    void UpdateAnimation(float timeStep);
+
+    /// Speed.
+    float speed_;
+    /// Animation.
+    SharedPtr<XAnimation2D> animation_;
+    /// Animation time.
+    float animationTime_;
+    /// Object nodes.
+    Vector<SharedPtr<Node> > objectNodes_;
+};
+
+}

+ 11 - 4
Source/Engine/Urho2D/XAnimation2D.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "Sprite2D.h"
 #include "XAnimation2D.h"
+#include "XAnimationSet2D.h"
 
 #include "DebugNew.h"
 
@@ -64,9 +65,10 @@ Timeline::Timeline()
 {
 }
 
-XAnimation2D::XAnimation2D() : 
+XAnimation2D::XAnimation2D(XAnimationSet2D* animationSet) : 
+    animationSet_(animationSet),
     length_(0.0f), 
-    loop_(true)
+    looped_(true)
 {
 }
 
@@ -84,9 +86,9 @@ void XAnimation2D::SetLength(float length)
     length_ = Max(0.0f, length);
 }
 
-void XAnimation2D::SetLoop(bool loop)
+void XAnimation2D::SetLooped(bool looped)
 {
-    loop_ = loop;
+    looped_ = looped;
 }
 
 void XAnimation2D::AddMainlineKey(const MainlineKey& mainlineKey)
@@ -99,4 +101,9 @@ void XAnimation2D::AddTimeline(const Timeline& timeline)
     timelines_.Push(timeline);
 }
 
+XAnimationSet2D* XAnimation2D::GetAnimationSet() const
+{
+    return animationSet_;
+}
+
 }

+ 10 - 5
Source/Engine/Urho2D/XAnimation2D.h

@@ -30,6 +30,7 @@ namespace Urho3D
 {
 
 class Sprite2D;
+class XAnimationSet2D;
 
 /// Object reference.
 struct ObjectRef
@@ -102,7 +103,7 @@ class URHO3D_API XAnimation2D : public RefCounted
 {
 public:
     /// Construct.
-    XAnimation2D();
+    XAnimation2D(XAnimationSet2D* animationSet);
     /// Destruct
     virtual ~XAnimation2D();
 
@@ -111,30 +112,34 @@ public:
     /// Set length.
     void SetLength(float length);
     /// Set loop.
-    void SetLoop(bool loop);
+    void SetLooped(bool looped);
     /// Add mainline key.
     void AddMainlineKey(const MainlineKey& mainlineKey);
     /// Add timeline.
     void AddTimeline(const Timeline& timeline);
 
+    /// Return animation set.
+    XAnimationSet2D* GetAnimationSet() const;
     /// Return name.
     const String& GetName() const { return name_; }
     /// Return length.
     float GetLength() const { return length_; }
     /// Return looping.
-    bool GetLoop() const { return loop_; }
+    bool IsLooped() const { return looped_; }
     /// Return all mainline keys.
     const Vector<MainlineKey>& GetMainlineKeys() const { return mainlineKeys_; }
     /// Return all timelines.
     const Vector<Timeline>& GetTimelines() const { return timelines_; }
 
 private:
+    /// Animation set.
+    WeakPtr<XAnimationSet2D> animationSet_;
     /// Name.
     String name_;
     /// Length.
     float length_;
-    /// Loop.
-    bool loop_;
+    /// Looped.
+    bool looped_;
     /// All mainline Keys.
     Vector<MainlineKey> mainlineKeys_;
     /// All timelines.

+ 5 - 5
Source/Engine/Urho2D/XAnimationSet2D.cpp

@@ -147,7 +147,7 @@ bool XAnimationSet2D::LoadFolders(const XMLElement &rootElem)
 
 bool XAnimationSet2D::LoadAnimation(const XMLElement& animationElem)
 {
-    SharedPtr<XAnimation2D> animation(new XAnimation2D());
+    SharedPtr<XAnimation2D> animation(new XAnimation2D(this));
     
     String name = animationElem.GetAttribute("name");
     animation->SetName(name);
@@ -155,10 +155,10 @@ bool XAnimationSet2D::LoadAnimation(const XMLElement& animationElem)
     float length = animationElem.GetFloat("length") * 0.001f;
     animation->SetLength(length);
 
-    bool looping = true;
+    bool looped = true;
     if (animationElem.HasAttribute("looping"))
-        looping = animationElem.GetBool("looping");
-    animation->SetLoop(looping);
+        looped = animationElem.GetBool("looping");
+    animation->SetLooped(looped);
 
     // Load main line
     XMLElement mainlineElem = animationElem.GetChild("mainline");
@@ -230,7 +230,7 @@ bool XAnimationSet2D::LoadAnimation(const XMLElement& animationElem)
         }
 
         // Add end key for looped animation
-        if (looping && timeline.objectKeys_.Back().time_ != length)
+        if (looped && timeline.objectKeys_.Back().time_ != length)
         {
             ObjectKey objectKey = timeline.objectKeys_.Front();
             objectKey.time_ = length;