How do I make attachable, detachable, locking drawers?

I want to make a functional server rack in game, wherein you pick up a server and attach it to a slot (like a drawer) then it locks into place in the rack when it’s pushed in. I also want to detach it and attach it to any other slot. Later, I want to be able to route wires and other things like components and drives, but first I want to get basic placement working. How do I do this?

I’m trying to build this for the Vive.

(I’ve tried using VRTK snapping for this but it was causing too many issues with what I want to do)

The drawer piece is pretty easy, the detach/re-attach will probably require some custom code.

For the drawer sliding I had a similar requirement and ended up using a ConfigurableJoint (with a Rigidbody) on the drawer connected to another Rigidbody on the cabinet. The ConfigurableJoint should have all angular motions Locked, as well as the Y and Z motion. Use Limited for X motion and specify a range in Linear Limit. You could do the detach part using the Break Force / Break Torque on that ConfigurableJoint.

You may need to set up some colliders as shelves and then trigger a re-attachment that will create and configure a new ConfigurableJoint for you when you have placed the drawer in the new slot since the Break Force / Break Torque will remove the original ConfigurableJoint. Hope that helps.

1 Like

I was trying this out and it may work if I can figure out how to configure the ConfigurableJoint through script. What I’ve done is place this script on an empty trigger collider and it sort of works. I don’t know how to set the linear Limit’s Limit variable number. How do I call that?

Code on trigger box:

void OnTriggerEnter(Collider colider)
{
if (colider.tag == (“1U Server”))

{
if (colider.GetComponent() == null)
{
ConfigurableJoint cj = colider.gameObject.AddComponent();

cj.axis = new Vector3(0, 0, 1);
cj.xMotion = ConfigurableJointMotion.Limited;
cj.yMotion = ConfigurableJointMotion.Locked;
cj.zMotion = ConfigurableJointMotion.Locked;
cj.angularXMotion = ConfigurableJointMotion.Locked;
cj.angularYMotion = ConfigurableJointMotion.Locked;
cj.angularZMotion = ConfigurableJointMotion.Locked;

//??
//cj.linearLimit.limit = 0.3f;
//?? Help?

cj.breakForce = 850;

Debug.Log(“CJ ADDED”);
}

/*else
{

}*/
}
}

I don’t think you can modify the linearLimit.limit property directly, so you would need to make a new one like this:

cj.linearLimit = new SoftJointLimit() { limit = 0.3f, bounciness = 0f, contactDistance = 0.01f };

1 Like

It works as a removable drawer now, Thank you!

Next I need the object to auto-orientate and slide itself into the slot once it touches the entry of the slot so the user isn’t fighting with the physics. Right now it’s a jittery mess trying to get it into a tight space. Any suggestions on how to achieve that?

There are several solutions for that problem. You could probably just detach it from the hand and lerp it into place once the drawer touches the slot.

1 Like

Ok, so I managed to be able to “snap” it into place, but I wanted it to smoothly lerp into place when the player lets go. I took the code from the Vector3.Lerp example and tried to apply it to a colider in the place of a slot:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;

public class TestLerpSlot : MonoBehaviour {

public Transform startMarker;
public Transform endMarker;
public float speed = 1.0F;
private float startTime;
private float journeyLength;
private VRTK_InteractableObject interactable;

private Rigidbody rb;

// Use this for initialization
void Start ()
{
startTime = Time.time;

}

// Update is called once per frame
void Update () {

}

void OnTriggerEnter(Collider colider)
{

if (colider.tag == (“1U Server”))
{
rb = colider.gameObject.GetComponent();

if (colider.gameObject.GetComponent<VRTK_InteractableObject>())
{
interactable = colider.gameObject.GetComponent<VRTK_InteractableObject>();

if (interactable.IsGrabbed())
{

Debug.Log(“It’s Grabbed”);
}

//if (interactable.IsGrabbed() == false )

if (!interactable.IsGrabbed())
{
rb.isKinematic = true;
//Transform startMarker = colider.transform;
journeyLength = Vector3.Distance(startMarker.position, endMarker.position);

float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
colider.transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney);
colider.transform.rotation = Quaternion.Lerp(startMarker.rotation, endMarker.rotation, Time.time * speed);

Debug.Log(“It’s not Grabbed”);
}

}
Debug.Log(“Hit Slot”);

}
}

void OnTriggerExit(Collider colider)
{
if (colider.tag == (“1U Server”))
{
rb = colider.gameObject.GetComponent();
rb.isKinematic = false;
Debug.LogError(“Kine false”);
}
}
}

There are several problems with this:

  1. It’s not lerping the object, just snapping it to the place
  2. If I use OnTriggerStay instead it won’t let go
  3. It’s not setting kinematic to false when I want to take it out of the slot
  4. I have to manually assign the transform of the slot position (“endMarker”) even though this script is attached to the slot object
  5. I’d like the startMarker to be the colliding object’s transform at the moment the player lets go (or where it hits if it’s thrown at it.)

I want it to be like this if you get it close enough to the rails: https://media.giphy.com/media/qTNIlLJNOwdNK/giphy.gif

The lerps should probably be on your server’s rigidbody and you probably need to update the lerps in Update(). Then your startmarker is always just the rigidbody’s current transform position/rotation and your endmarker is just the slot’s position/rotation. You might consider using GoKit’s GoTweens, which already implements quite a bit of the lerping you want.

When your 1U server hits the rack collider you should probably force the player hand to let it go (whether that’s by breaking a joint or changing the rigidbody’s parent is up to how you have the grab implemented), set to IsKinematic = true, capture the target position/rotation of the rack slot, every update you should update the rigidbody’s position/rotation lerps and when you are within a certain tolerance you can snap it to the final place and set IsKinematic = false.

1 Like

I want the player to decide when and where to let go of the server since I want to allow them to quickly rearrange the position of the servers in any slot on the rack, so I can’t force the player to drop it on-collision. It’s also the reason I have it on the slot object instead, applying the lerp to the object when the player “is not grabbing” it, that way I can clone the slot object for each slot and it will work with any item that I throw at it with the right tags. I was going to add an option to highlight the slot when the user is hovering a valid object near it, then disable the slot once the Configurable Joint is applied preventing more than one object to occupy the slot at a time, then only re-enable the highlight/lerping snap ability when the server moved from the slot. Does this make sense?

Basically, I’m trying to make a better looking/feeling version of this enterprise application: Imgur: The magic of the Internet

The reason I want the drawer ability as well is so that I can add an x-ray like ability to see the internal components and their status when it’s extended out from the rack as an inspection tool.

I’ll look into GoTweens after I have this basic interaction working, for now I’d like to just get this simple interaction going normally, which feels a little defeating to be spending this much time on, but I need it.