[WILLING TO EVEN PAY $] Working Dragging objects/doors like in Amnesia, But Need Simple FIX

Hey!

I have this script and it is working however what I need is simple, but can’t figure it out.

I have a door which is a rigidbody and the player can open and close the door with the script. HOWEVER when the player walks backwards while still holding the mouse keythen you can still control the door even if you are 10000 miles away from the door. I want it as soon as the player is away then then you cannot control it anymore… springJoint.connectedBody = null;? It’s important :frowning:

 var normalCollisionCount = 1;
 var spring = 50.0;
 var damper = 5.0;
 var drag = 10.0;
 var angularDrag = 5.0;
 var distance = 0.2;
 var throwForce = 500;
 var throwRange = 1000;
 var attachToCenterOfMass = false;
  
 private var springJoint : SpringJoint;
  
 function Update ()
 {
     // Make sure the user pressed the mouse down
     if (!Input.GetMouseButtonDown (0))
         return;
  
     var mainCamera = FindCamera();
  
     // We need to actually hit an object
     var hit : RaycastHit;
     if (!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition),  hit, 100))
         return;
     // We need to hit a rigidbody that is not kinematic
     if (!hit.rigidbody || hit.rigidbody.isKinematic)
         return;
  
     if (!springJoint)
     {
         var go = new GameObject("Rigidbody dragger");
         var body : Rigidbody = go.AddComponent ("Rigidbody") as Rigidbody;
         springJoint = go.AddComponent ("SpringJoint");
         body.isKinematic = true;
     }
  
     springJoint.transform.position = hit.point;
     if (attachToCenterOfMass)
     {
         var anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
         anchor = springJoint.transform.InverseTransformPoint(anchor);
         springJoint.anchor = anchor;
     }
     else
     {
         springJoint.anchor = Vector3.zero;
     }
  
     springJoint.spring = spring;
     springJoint.damper = damper;
     springJoint.maxDistance = distance;
     springJoint.connectedBody = hit.rigidbody;
  
     StartCoroutine ("DragObject", hit.distance);
 }
  
 function DragObject (distance : float)
 {
     var oldDrag = springJoint.connectedBody.drag;
     var oldAngularDrag = springJoint.connectedBody.angularDrag;
     springJoint.connectedBody.drag = drag;
     springJoint.connectedBody.angularDrag = angularDrag;
     var mainCamera = FindCamera();
     while (Input.GetMouseButton (0))
     {
         var ray = mainCamera.ScreenPointToRay (Input.mousePosition);
         springJoint.transform.position = ray.GetPoint(distance);
         yield;
  
         if (Input.GetMouseButton (1)){
             springJoint.connectedBody.AddExplosionForce(throwForce,mainCamera.transform.position,throwRange);
             springJoint.connectedBody.drag = oldDrag;
             springJoint.connectedBody.angularDrag = oldAngularDrag;
             springJoint.connectedBody = null;
         }
     }
     if (springJoint.connectedBody)
     {
         springJoint.connectedBody.drag = oldDrag;
         springJoint.connectedBody.angularDrag = oldAngularDrag;
         springJoint.connectedBody = null;
     }
 }
  
 function FindCamera ()
 {
     if (camera)
         return camera;
     else
         return Camera.main;
 }

This is a strange approach, but kinda interesting ^^. Am i right that the player is supposed to “drag” the door open “manually”?

Currently you only “check” the player distance from the door / object when you click down. This script seems more like it’s designed for “carrying” objects around. So currently it doesn’t actually differentiate if you carry a “normal” object or if you push / pull a door. So that’s the main problem you have.

You should check if the object you’re dragging is a door (maybe add a tag “door”) and check it when you get the object using your raycast. Just remembering that the dragged object is a door (with a boolean for example). Inside your coroutine you can simply do a distance check if it’s a door. If the dragged object is too far away, just cancel the dragging.

To cancel the dragging your want:

  • revert the drag / angular drag values
  • set the connectedBody to null.
  • and use yield break; to terminate your coroutine

Actually you don’t necessarily need to check if it’s a door as this restriction may apply to any object. If the object is stuck somewhere and you continue walking, you should cancel the dragging anyways.

The distance you have to check is the distance between your “springJoint” object position and the connectedBody position.

edit

To be a bit more specific this is how you could implement the distance check:

// inside your coroutine

// relative anchor point on the dragged object.
var objAnchor = springJoint.connectedBody.transform.InverseTransformPoint(springJoint.transform.position);
while (Input.GetMouseButton (0))
{
    var ray = mainCamera.ScreenPointToRay (Input.mousePosition);
    springJoint.transform.position = ray.GetPoint(distance);
    
    // current anchor pos of the spring in worldspace
    var springPos = springJoint.transform.TransformPoint(springJoint.anchor);
    // current anchor pos of the dragged object.
    var objPos = springJoint.connectedBody.transform.TransformPoint(objAnchor);
    var currentDist = Vector3.Distance( springPos, objPos );
    if (currentDist > maxThreshold)
    {
        springJoint.connectedBody.drag = oldDrag;
        springJoint.connectedBody.angularDrag = oldAngularDrag;
        springJoint.connectedBody = null;
        yield break;
    }
    
    yield;

Where “maxThreshold” is simply the distance which basically “breaks” the connection. Note that this is untested. I barely worked with spring joints so i might have gotten some relative references wrong but it should work (theoretically ^^).

“objAnchor” is basically the point where the joint is attached to in local space of the dragged object. This is turned back into worldspace ( “objPos” ) every frame. “springPos” is basically the opposite. It’s the anchor point on the spring object transformed into worldspace. So if everything is right, those two positions should be “more or less” equal. Of course the spring nature leaves some space, so don’t make your threshold too small.

ps: You might want to put that “detaching” code in a seperate method since you would have the same three lines at three different places.

Well the most simple way is the do a check every update if the player is still within the distance, Not saying that it’s the best, but the easiest.

if(Vector3.Distance(playerObject.transform.position, doorObject.transform.position) < 3)

Thank you all for your responses, still trying to get it to work but no luck yet. :frowning: