Selaa lähdekoodia

Merge pull request #287 from greenfire27/MoveToUpdate

Updated MoveTo
Peter Robinson 10 vuotta sitten
vanhempi
commit
8b5cf96b42

+ 0 - 1
engine/compilers/VisualStudio 2013/Torque 2D.vcxproj

@@ -707,7 +707,6 @@
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectList.h" />
-    <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectRotateToEvent.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectSet.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectSet_ScriptBinding.h" />

+ 0 - 3
engine/compilers/VisualStudio 2013/Torque 2D.vcxproj.filters

@@ -2471,9 +2471,6 @@
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject_ScriptBinding.h">
       <Filter>2d\sceneobject</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h">
-      <Filter>2d\sceneobject</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectRotateToEvent.h">
       <Filter>2d\sceneobject</Filter>
     </ClInclude>

+ 120 - 28
engine/source/2d/sceneobject/SceneObject.cc

@@ -52,10 +52,6 @@
 #include "component/behaviors/behaviorTemplate.h"
 #endif
 
-#ifndef _SCENE_OBJECT_MOVE_TO_EVENT_H_
-#include "2d/sceneobject/SceneObjectMoveToEvent.h"
-#endif
-
 #ifndef _SCENE_OBJECT_ROTATE_TO_EVENT_H_
 #include "2d/sceneobject/SceneObjectRotateToEvent.h"
 #endif
@@ -131,6 +127,14 @@ SceneObject::SceneObject() :
     mRenderPosition( 0.0f, 0.0f ),
     mRenderAngle( 0.0f ),
     mSpatialDirty( true ),
+    mTargetPosition( 0.0f, 0.0f ),
+    mLastCheckedPosition( 0.0f, 0.0f ),
+    mTargetPositionActive( false ),
+    mDistanceToTarget( 0.0f ),
+    mTargetPositionMargin( 0.1f ),
+    mTargetPositionFound( false ),
+    mSnapToTargetPosition( true ),
+    mStopAtTargetPosition( true ),
 
     /// Body.
     mpBody(NULL),
@@ -194,7 +198,6 @@ SceneObject::SceneObject() :
     mEditorTickAllowed(true),
     mPickingAllowed(true),
     mAlwaysInScope(false),
-    mMoveToEventId(0),
     mRotateToEventId(0),
     mSerialId(0),
     mRenderGroup( StringTable->EmptyString )
@@ -609,6 +612,12 @@ void SceneObject::integrateObject( const F32 totalTime, const F32 elapsedTime, D
             
         // Update world proxy.
         mpScene->getWorldQuery()->update( this, tickAABB, tickDisplacement );
+
+        //have we arrived at the target position?
+        if (mTargetPositionActive)
+        {
+           updateTargetPosition();
+        }
     }
 
     // Update Lifetime.
@@ -658,6 +667,15 @@ void SceneObject::postIntegrate(const F32 totalTime, const F32 elapsedTime, Debu
         Con::executef(this, 1, "onUpdate");
     }
 
+    // Check to see if we're done moving.
+    if (mTargetPositionActive && mTargetPositionFound)
+    {
+       mTargetPositionActive = false;
+
+       PROFILE_SCOPE(SceneObject_onMoveToComplete);
+       Con::executef(this, 1, "onMoveToComplete");
+    }
+
 	// Check to see if we're done fading.
 	if ( mFadeActive && mBlendColor == mTargetColor )
 	{
@@ -1616,7 +1634,7 @@ void SceneObject::onEndCollision( const TickContact& tickContact )
 
 //-----------------------------------------------------------------------------
 
-bool SceneObject::moveTo( const Vector2& targetWorldPoint, const F32 speed, const bool autoStop, const bool warpToTarget )
+bool SceneObject::moveTo( const Vector2& targetWorldPoint, const F32 speed, const bool autoStop, const bool snapToTarget, const F32 margin )
 {
     // Check in a scene.
     if ( !getScene() )
@@ -1639,27 +1657,23 @@ bool SceneObject::moveTo( const Vector2& targetWorldPoint, const F32 speed, cons
         return false;
     }
 
-    // Cancel any previous event.
-    if ( mMoveToEventId != 0 )
-    {
-        Sim::cancelEvent( mMoveToEventId );
-        mMoveToEventId = 0;
-    }
+    // Set the target position
+    mLastCheckedPosition = getPosition();
+    mTargetPosition = targetWorldPoint;
+    mTargetPositionMargin = margin;
+    mTargetPositionActive = true;
+    mTargetPositionFound = false;
+    mSnapToTargetPosition = snapToTarget;
+    mStopAtTargetPosition = autoStop;
+    mDistanceToTarget = (mLastCheckedPosition - mTargetPosition).Length();
 
     // Calculate the linear velocity for the specified speed.
     Vector2 linearVelocity = targetWorldPoint - getPosition();
-    const F32 distance = linearVelocity.Normalize( speed );
-
-    // Calculate the time it will take to reach the target.
-    const U32 time = (U32)((distance / speed) * 1000.0f);
+    linearVelocity.Normalize(speed);
 
     // Set the linear velocity.
     setLinearVelocity( linearVelocity );
 
-    // Create and post event.
-    SceneObjectMoveToEvent* pEvent = new SceneObjectMoveToEvent( targetWorldPoint, autoStop, warpToTarget );
-    mMoveToEventId = Sim::postEvent(this, pEvent, Sim::getCurrentTime() + time );
-
     return true;
 }
 
@@ -1773,10 +1787,9 @@ bool SceneObject::growTo(const Vector2& targetSize, const Vector2& deltaSize)
 void SceneObject::cancelMoveTo( const bool autoStop )
 {
     // Only cancel an active moveTo event
-    if ( mMoveToEventId != 0 )
+    if ( mTargetPositionActive )
     {
-        Sim::cancelEvent( mMoveToEventId );
-        mMoveToEventId = 0;
+       mTargetPositionActive = false;
 
         // Should we auto stop?
         if ( autoStop )
@@ -4210,11 +4223,90 @@ void SceneObject::updateBlendColor(const F32 elapsedTime)
 
 void SceneObject::updateSize(const F32 elapsedTime)
 {
-	// Apply the size deltas to the area to move it toward the targetSize.
-	mSize.x = processEffect(mSize.x, mTargetSize.x, mDeltaSize.x * elapsedTime);
-	mSize.y = processEffect(mSize.y, mTargetSize.y, mDeltaSize.y * elapsedTime);
-
-	setSize(mSize);
+   // Apply the size deltas to the area to move it toward the targetSize.
+   mSize.x = processEffect(mSize.x, mTargetSize.x, mDeltaSize.x * elapsedTime);
+   mSize.y = processEffect(mSize.y, mTargetSize.y, mDeltaSize.y * elapsedTime);
+
+   setSize(mSize);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneObject::updateTargetPosition()
+{
+   F32 distance = (getPosition() - mTargetPosition).Length();
+   bool hasArrived = false;
+
+   // Is the current position within the target?
+   if ( distance <= mTargetPositionMargin )
+   {
+      hasArrived = true;
+   }
+   else // Did we pass through the target?
+   {
+      // Moving vertically
+      if (mLastCheckedPosition.x == getPosition().x)
+      {
+         if (((mLastCheckedPosition.y < mTargetPosition.y && mTargetPosition.y < getPosition().y) || (mLastCheckedPosition.y > mTargetPosition.y && mTargetPosition.y > getPosition().y)) &&
+         mFabs(getPosition().x - mTargetPosition.x) <= mTargetPositionMargin)
+         {
+            hasArrived = true;
+         }
+      }// Or moving horizontally
+      else if (mLastCheckedPosition.y == getPosition().y)
+      {
+         if (((mLastCheckedPosition.x < mTargetPosition.x && mTargetPosition.x < getPosition().x) || (mLastCheckedPosition.x > mTargetPosition.x && mTargetPosition.x > getPosition().x)) &&
+            mFabs(getPosition().y - mTargetPosition.y) <= mTargetPositionMargin)
+         {
+            hasArrived = true;
+         }
+      }// Or moving diagonally
+      else
+      {
+         //slopes of the two lines
+         Vector2 slope = (mLastCheckedPosition - getPosition());
+         Vector2 perpSlope = slope.getPerp();
+         F32 m1 = slope.y / slope.x;
+         F32 m2 = perpSlope.y / perpSlope.x;
+
+         //y-intercepts
+         F32 b1 = mLastCheckedPosition.y - (m1 * mLastCheckedPosition.x);
+         F32 b2 = mTargetPosition.y - (m2 * mTargetPosition.x);
+
+         //point of interception
+         F32 x = (b1 - b2) / (m2 - m1);
+         F32 y = (m1 * x) + b1;
+         Vector2 intercept = Vector2(x, y);
+
+         //Is the intercept point between the other two points and is the distance less than the margin?
+         if (((mLastCheckedPosition.x < intercept.x && intercept.x < getPosition().x) || (mLastCheckedPosition.x > intercept.x && intercept.x > getPosition().x)) &&
+            (intercept - mTargetPosition).Length() <= mTargetPositionMargin)
+         {
+            hasArrived = true;
+         }
+      }
+   }
+
+   if (hasArrived)
+   {
+      if (mSnapToTargetPosition)
+      {
+         setPosition(mTargetPosition);
+      }
+      if (mStopAtTargetPosition)
+      {
+         setLinearVelocity(Vector2::getZero());
+      }
+      mTargetPositionFound = true;
+   }
+   // Are we moving away from the target?
+   else if (distance > mDistanceToTarget)
+   {
+      // Then turn off the target. No need to keep checking.
+      mTargetPositionActive = false;
+   }
+   mLastCheckedPosition = getPosition();
+   mDistanceToTarget = distance;
 }
 
 //-----------------------------------------------------------------------------

+ 11 - 4
engine/source/2d/sceneobject/SceneObject.h

@@ -109,7 +109,6 @@ public:
     friend class ContactFilter;
     friend class WorldQuery;
     friend class DebugDraw;
-    friend class SceneObjectMoveToEvent;
     friend class SceneObjectRotateToEvent;
 
 protected:
@@ -156,6 +155,14 @@ protected:
     Vector2                 mRenderPosition;
     F32                     mRenderAngle;
     bool                    mSpatialDirty;
+    Vector2                 mLastCheckedPosition;
+    Vector2                 mTargetPosition;
+    bool                    mTargetPositionActive;
+    F32                     mDistanceToTarget;
+    F32                     mTargetPositionMargin;
+    bool                    mTargetPositionFound;
+    bool                    mSnapToTargetPosition;
+    bool                    mStopAtTargetPosition;
 
     /// Body.
     b2Body*                 mpBody;
@@ -229,7 +236,6 @@ protected:
     bool                    mEditorTickAllowed;
     bool                    mPickingAllowed;
     bool                    mAlwaysInScope;
-    U32                     mMoveToEventId;
     U32                     mRotateToEventId;
     U32                     mSerialId;
     StringTableEntry        mRenderGroup;
@@ -407,12 +413,13 @@ public:
     inline F32              getAngularDamping(void) const               { if ( mpScene ) return mpBody->GetAngularDamping(); else return mBodyDefinition.angularDamping; }
 
     /// Move/Rotate to.
-    bool                    moveTo( const Vector2& targetWorldPoint, const F32 speed, const bool autoStop = true, const bool warpToTarget = true );
+    bool                    moveTo(const Vector2& targetWorldPoint, const F32 speed, const bool autoStop = true, const bool snapToTarget = true, const F32 margin = 0.1f);
     bool                    rotateTo( const F32 targetAngle, const F32 speed, const bool autoStop = true, const bool warpToTarget = true );
     void                    cancelMoveTo( const bool autoStop = true );
     void                    cancelRotateTo( const bool autoStop = true );
-    inline bool             isMoveToComplete( void ) const              { return mMoveToEventId == 0; }
+    inline bool             isMoveToComplete( void ) const              { return !mTargetPositionActive; }
     inline bool             isRotateToComplete( void ) const            { return mRotateToEventId == 0; }
+    void                    updateTargetPosition( void );
 
 	// Fade to
 	bool					fadeTo( const ColorF& targetColor, const F32 deltaRed, const F32 deltaGreen, const F32 deltaBlue, const F32 deltaAlpha );

+ 0 - 75
engine/source/2d/sceneobject/SceneObjectMoveToEvent.h

@@ -1,75 +0,0 @@
-//-----------------------------------------------------------------------------
-// Copyright (c) 2013 GarageGames, LLC
-//
-// 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.
-//-----------------------------------------------------------------------------
-
-#ifndef _SCENE_OBJECT_MOVE_TO_EVENT_H_
-#define _SCENE_OBJECT_MOVE_TO_EVENT_H_
-
-#ifndef _SCENE_OBJECT_H_
-#include "2d/sceneobject/SceneObject.h"
-#endif
-
-//-----------------------------------------------------------------------------
-
-class SceneObjectMoveToEvent : public SimEvent
-{
-public:
-    SceneObjectMoveToEvent( const Vector2& targetWorldPoint, const bool autoStop, const bool warpToTarget  ) :
-        mAutoStop( autoStop ),
-        mWarpToTarget( warpToTarget ),
-        mTargetWorldPoint( targetWorldPoint ) {}
-    virtual ~SceneObjectMoveToEvent() {}
-
-    virtual void process(SimObject *object)
-    {
-        // Fetch scene object.
-        SceneObject* pSceneObject = (dynamic_cast<SceneObject*>(object));
-        if (pSceneObject == NULL )
-            return;
-
-        // Are we auto stopping?
-        if ( mAutoStop )
-        {
-            // Yes, so reset linear velocity.
-            pSceneObject->setLinearVelocity( Vector2::getZero() );
-        }
-
-        // Are we warping to target?
-        if ( mWarpToTarget )
-        {
-            // Yes, so set position to the target.
-            pSceneObject->setPosition( mTargetWorldPoint );
-        }
-
-        // Reset event Id.
-        pSceneObject->mMoveToEventId = 0;
-
-        // Script callback.
-        Con::executef( object, 2, "onMoveToComplete", mTargetWorldPoint.scriptThis() );
-    }
-
-private:
-    Vector2     mTargetWorldPoint;
-    bool        mAutoStop;
-    bool        mWarpToTarget;
-};
-
-#endif // _SCENE_OBJECT_MOVE_TO_EVENT_H_

+ 19 - 9
engine/source/2d/sceneobject/SceneObject_ScriptBinding.h

@@ -1882,15 +1882,17 @@ ConsoleMethodWithDocs(SceneObject, getAngularDamping, ConsoleFloat, 2, 2, ())
 //-----------------------------------------------------------------------------
 
 /*! Moves the object to the specified world point.
-    The point is moved by calculating the initial linear velocity required and applies it.
-    The object may never reach the point if it has linear damping applied or collides with another object.
-    @param worldPoint/Y The world point to move the object to.
+    Linear velocity is applied to the object at the given speed in the direction of the target world point.
+    The object may never reach the point if other forces act on the target such as collisions.
+    If the object moves away from the target the object will stop checking to see if it has arrived at the target.
+    @param worldPointX/Y The world point to move the object to.
     @param speed The speed (in m/s) to use to move to the specified point.
-    @param autoStop? Whether to automatically set the linear velocity to zero when time has elapsed or not
-    @param warpToTarget? Whether to move instantly to the target point after the specified time or not in-case the target was not quite reached.
+    @param autoStop? Whether to automatically set the linear velocity to zero when the object arrives at the target.
+    @param snapToTarget? Whether to snap the object to the target point when it is within the margin.
+    @param margin? The distance from the target that qualifies as reaching the target.
     @return Whether the move could be started or not.
 */
-ConsoleMethodWithDocs(SceneObject, moveTo, ConsoleBool, 4, 7, (worldPoint X/Y, speed, [autoStop = true], [warpToTarget = true]))
+ConsoleMethodWithDocs(SceneObject, moveTo, ConsoleBool, 4, 7, (worldPoint X/Y, speed, [autoStop = true], [snapToTarget = true], [margin = 0.1]))
 {
     // World point.
     const U32 worldPointElementCount = Utility::mGetStringElementCount(argv[2]);
@@ -1930,10 +1932,18 @@ ConsoleMethodWithDocs(SceneObject, moveTo, ConsoleBool, 4, 7, (worldPoint X/Y, s
         return object->moveTo( worldPoint, speed, autoStop );
     }
 
-    // Warp to target?
-    const bool warpToTarget = dAtob(argv[nextArg++]);
+    // Snap to target?
+    const bool snapToTarget = dAtob(argv[nextArg++]);
 
-    return object->moveTo( worldPoint, speed, autoStop, warpToTarget );
+    if ( argc <= nextArg )
+    {
+       return object->moveTo(worldPoint, speed, autoStop, snapToTarget);
+    }
+
+    // Margin.
+    const F32 margin = dAtof(argv[nextArg++]);
+
+    return object->moveTo( worldPoint, speed, autoStop, snapToTarget, margin );
 }
 
 //-----------------------------------------------------------------------------