Create Custom Grab Mechanics
Grabbing in VR can have a vast meaning and mechanics. The grabbing in massive loop allows the developer to create their custom grab mechanics that fits their purpose.
Here, we discuss on how to create a custom grab mechanics using the MLGrab Component and using the MLGrab API.
The component
To create a custom grab mechanics, we need the MLGrab component attached to our grabbable object. This component creates the necessary interfaces for players hand to recognize the object as grabbable and perform the grabbing actions, as well as detecting the trigger actions.
To begin, we need to set the Grab Mechanics
property of the MLGrab to Custom
. When this property set to custom, the MLGrab will still makes the object grabbable and detects and send the event related to grabbing the event, but it will not move (apply grab mechanics) to the object. This is where the developers can define their custom mechanics.
The API
To define the custom mechanics, we need to use Lua script.
- Add a new (Lua/C#) script to the same object.
- Create a serialized field called
GrabComponent
with type of MLGrab.
- C#
- Lua
using UnityEngine;
using ML.SDK;
class CustomGrab : MonoBehaviour
{
[SerializedField]
private MLGrab grab;
}
do
local customGrab = LUA.script;
local grabComponent = SerializedField("GrabComponent", MLGrab);
end
- Drag and drop the MLGrab component to the field in the Lua script.
Now that we have the access to the MLGrab Component, we can use the MLGrab api to create our custom grab mechanics.
Grab Mechanics
First, we need to know when an object is grabbed by player. On the start function,
-
Create a local variable which we set to true when player grabs the object.
-
Attach event handlers to the grab component to know when the object is grabbed or released by the player.
- C#
- Lua
using UnityEngine;
using ML.SDK;
class CustomGrab : MonoBehaviour
{
[SerializedField]
private MLGrab grab;
private bool isGrabbed = false;
void PrimaryGrabBegin()
{
isGrabbed = true;
}
void PrimateGrabEnd()
{
isGrabbed = false;
}
void Start()
{
if(grab != null)
{
grab.OnPrimaryGrabBegin.AddListener(PrimaryGrabBegin);
grab.OnPrimaryGrabEnd.AddListener(PrimateGrabEnd);
}
}
}
do
local customGrab = LUA.script;
local grabComponent = SerializedField("GrabComponent", MLGrab);
local isGrabbed = false;
local function primaryGrabBegin()
isGrabbed = true;
end
local function primaryGrabEnd()
isGrabbed = false;
end
function customGrab.Start()
if grabComponent ~= nil then
grabComponent.OnPrimaryGrabBegin.Add(primaryGrabBegin);
grabComponent.OnPrimaryGrabEnd.Add(primaryGrabEnd);
end
end
end
now that we registered the events for when the player grabs or releases the object, we can work on the actual mechanics of the grabbing.
What is grab mechanics?
The grab mechanics mentioned a lot here, but what does it mean?
The grab mechanics means moving, applying force or apply other necessary modifications in order to grabbing have an actual effect on the object.
What in the object needs to be changes for the grab mechanics?
There is no limit on what effect on object can be constitutes a grab mechanics and it is purely depending on the outcome, but here are few examples:
- Moving the object. The Most common thing is to move the object. For most grabs, the objects position and rotation will be affected by the players hand position. This is how the default grab mechanics works.
- Applying force to the object.
- Changing animations on object.
- Combination of few things, again there is no limit.
The MLGrab component API provides different information which will may needed to perform any required calculations.
grab.PrimaryHand
Transform of the primary1 hand. You can get the players primary hands position and rotation from this.grab.SecondaryHand
Transform of the secondary2 hand. You can get the players secondary hands position and rotation from this.grab.PrimaryGrabPoint
Transform of the Primary Grab Point. You can get both global and local position or rotation of the grab point which is used to grab object.grab.SecondaryGrabPoint
Transform of the Secondary Grab point. You can get both global and local position or rotation of the grab point which is used to grab object by second hand.grab.ExpectedObjectPosition
This is the pre-calculated position where the object should be if the object was using Default grab mode. The calculations factor the hand position and rotations and which hand is currently grabbed the object.grab.ExpectedObjectRotation
This is the pre-calculated rotation where the object should be if the object was using Default grab mode. The calculations factor the hand position and rotations and which hand is currently grabbed the object.
We can re-create the default grab mechanics by setting the object position to ExpectedObjectPosition
and rotation to ExpectedObjectRotation
in the **LateUpdate
** while the object is grabbed.
- C#
- Lua
using UnityEngine;
using ML.SDK;
class CustomGrab : MonoBehaviour
{
[SerializedField]
private MLGrab grab;
private bool isGrabbed = false;
void PrimaryGrabBegin()
{
isGrabbed = true;
}
void PrimateGrabEnd()
{
isGrabbed = false;
}
void Start()
{
if(grab != null)
{
grab.OnPrimaryGrabBegin.AddListener(PrimaryGrabBegin);
grab.OnPrimaryGrabEnd.AddListener(PrimateGrabEnd);
}
}
void LateUpdate()
{
if(isGrabbed)
{
grab.gameObject.transform.position = grab.ExpectedObjectPosition;
grab.gameObject.transform.rotation = grab.ExpectedObjectRotation;
}
}
}
do
local customGrab = LUA.script;
local grabComponent = SerializedField("GrabComponent", MLGrab);
local isGrabbed = false;
local function primaryGrabBegin()
isGrabbed = true;
end
local function primaryGrabEnd()
isGrabbed = false;
end
function customGrab.Start()
if grabComponent ~= nil then
grabComponent.OnPrimaryGrabBegin.Add(primaryGrabBegin);
grabComponent.OnPrimaryGrabEnd.Add(primaryGrabEnd);
end
end
function customGrab.LateUpdate()
if isGrabbed then
customGrab.gameObject.transform.position = grabComponent.ExpectedObjectPosition;
customGrab.gameObject.transform.rotation = grabComponent.ExpectedObjectRotation;
end
end
end
Again, there is no limit on what the grab mechanics can or should do.
Footnotes
-
The primary hand in a dual grabbing context is the first hand that grabs the object. ↩
-
The Secondary hand in dual grabbing context is the second hand which grabs the object. Note that the secondary hand will not always engaged with the object. Or even, an object might not define secondary grab point or a player may not chose to grab an object by two hand. ↩