In this guide, I’ll walk you through creating grabbable rigidbody objects with Normcore.
Before we get started, you’ll want to download this project we put together for this guide. It includes a basic environment with some grabbable cubes, and single player VR support.
Go ahead and open the project - at the time of writing this guide, we’re using 2019.1.14, so you’ll need that version or later.
A quick overview of the project
Go ahead and open the main scene under Main.unity in your project inspector. The scene contain a basic environment with a floor and skybox, as well as some colored cubes resting on a table. The cubes may not look like much, but they are our grabbable rigidbodies!
If you look at the inspector for any of the coloured cubes by selecting one in the Hierarchy under Grabbable Cubes > Cube, you’ll notice each one contains Cube component–the first half of our logic.
Our scene also contains two Cube Grabber objects - one nested under each player hand. You can see them for yourself by selecting one under Player > Left/Right Hand > Cube Grabber in the Hierarchy. You’ll see each one has a matching Cube Grabber component added to it – this is where the second half of our logic lives. This Cube Grabber component interacts with the Cube component living on each Cube, and vice-versa.
Now that we’ve taken a look at the project hierarchy, let’s dive into how the Cube Grabber and Cube components interact with each other.
Below is the script you’ll have in your project under
CubeGrabber.cs. Feel free to skim through it, and we’ll break it down step-by-step after the excerpt. If you’re following along in the editor, open the file in Visual Studio to reference.
So firstly, our
CubeGrabber implementation defines some static members, used to create a single registry of grabbable cubes across both grabbers. These members are:
HashSet<Cube>property for holding the references to each registered cube
UnregisterCube(Cube cube), functions called by each Cube to register or unregister itself from the grabbers
After our class members are the instance members, for holding state related to each independent grabber.
- an internal
Handenum with types
RightHandfor representing either the left or right hand
_handfor setting which
Handthe grabber belongs to
_triggerPressedfor denoting whether the appropriate trigger is currently being pressed
_activeCubefor storing the currently grabbed
Cube, if one is being held
_grabRotationOffsetfor storing the position and rotation offset of the
_activeCubeif there is one
Finally, our instance methods make up the rest of the file, defining the logic for checking to see if we need to start grabbing cubes, as well as position the currently grabbed Cube each frame (if there is one).
UpdatePosemethod: used to grab the current velocity & angular velocity of the appropriate controller with the XRNodeState APIs
GetClosestGrabbableCube(): returns the closest valid grabbable cube relative to the respective grabber position
PositionActiveCube(): used to position the cube being actively grabbed, if there is one
Updateloop: determine on each frame if we should start, continue, or stop grabbing a cube. Uses our
That about sums up the
CubeGrabber implementation. Now, let’s take a quick look at the Cube implementation.
Below is our Cube script - like before, feel free to follow along in Visual Studio for reference when reading the member descriptions.
Our Cube class has a few key pieces of functionality. Firstly, you’ll see there’s a
_grabRadius that you can configure for determining an appropriate radius for your grabbable objects. Feel free to adjust this if you’d like, but we’ll keep it at
Cube registers with the
CubeGrabbers in our scene, by calling the static method
CubeGrabber.RegisterCube and passing itself. It also caches a reference to its own Rigidbody as
_rigidbody, so it can disable or enable gravity when grabbing begins or ends.
That sums up the Cube implementation - it’s much more straightforward than the Cube Grabber, but equally as important! Feel free to hit Play and put on your VR headset to pick up some cubes and try it out.
Check out that sweet cube-grabbing action. Nice.
To get this working with Normcore, we’ll only need a few additions. First, of course, be sure to download the latest version of Normcore from the Dashboard, and go ahead and import it into your project.
Import the latest version of Normcore into your project.
With Normcore imported, head to the Normal > Examples > VR Player folder in your project Hierarchy and drag a Realtime + VR Player prefab into your scene. Paste in an app key from the Dashboard, and set a room name. While we’re here, we can hook up our local player avatar to Realtime Avatar Manager, by dragging in the root Player, Head, Left Hand, and Right Hand objects into the appropriate fields.
Add a Realtime + VR Player prefab into your scene, and hook up your local Player avatar to the Realtime Avatar Manager.
With Normcore set up with our player, we’ll need to do one last thing and network our cubes. We can do this by simply adding a Realtime Transform component to each
Cube. This will add both the Realtime Transform and Realtime View components to the Cube, and Normcore will automatically synchronize the transform of the cubes for all players.
Add a Realtime Transform component to each of your grabbable cubes.
Now, we need to make one last modification before we can call the project complete. With a Realtime Transform component on each
Cube, we need to be sure to request ownership of the transform when grabbing it. Let’s do so now with a few additions to
Cube.cs: caching a reference of our
RealtimeTransform, as well as calling
Awesome. With that settled, our cubes should be properly networked. Our implementation works the same as it does without Normcore: when we grab a cube, our
CubeGrabber will set the
Cube rigidbody to kinematic, allowing our user to position the cube freely. Then, when the user lets go of the
Cube, the rigidbody is marked as non-kinematic again, allowing the
Cube to fall and come to rest. The only Normcore changes necessary were adding
RealtimeTransform to each
Cube, and requesting ownership of the appropriate
RealtimeTransform on grab.
Feel free to build & run the project and send it to a friend - you should both be able to grab the cubes in VR and toss them around to one another. It’s pretty basic in its current form, but does a great job at illustrating how to handle user interaction with networked objects in Normcore!