• Hi Guest!

    This is a notice regarding recent upgrades to the Hub. Over the last month, we have added several new features to improve your experience.
    You can check out the details in our official announcement!
Hello World - plugin basics pt2 - Trigger action with VR head collision

Guides Hello World - plugin basics pt2 - Trigger action with VR head collision

This guide builds upon part 1 which covers some basics of plugin building

In this guide we will touch on:
  • VR controller positions
  • Use script to change atom scale, position, alpha (and any other changeable property)
  • Collision triggers (to trigger an animation)
My aim with this plugin was to be able to trigger an animation by moving to an area of the scene - without relying on possession. I might want to turn on lights or trigger a lap dance just by moving my virtual head (or hands) into position.

I'm not an advanced VaM scripter so this might not be the best, most efficient way to achieve my goal but serves as a learning exercise anyway and works well enough. Nevertheless, comment if there is a better way for those people just looking for a solution.

If you're not interested in learning about plugins or this implementation, just grab the plug-in from the download button at the top. (remove the .txt extension, drop it in VaM/Custom/scripts. In your scene add a new cube and attach this plugin to it.)

My Implementation

In another guide, I explain how to use Collision Triggers.

Once I have my cube specified in the CollisionTrigger filter, to be the atom that will kick-off an animation, my idea for the plugin was to have it update said cube's position, each frame, to be the same as the VR head position.

Additionally, on-load of the plugin I'd like to set the containing-atom (said cube) to be small and/or transparent.


Side note: To figure out how to change an object property programmatically, you can;
  • Create an empty scene, add a cube, tweak knobs and dials and save.
  • In the saved scene files, you will find a json file with a reference to the properties that have been changed. Something like this:
    "id" : "Cube",
    "on" : "true",
    "type" : "Cube",
    "storables" : [
            "id" : "CubeMat",
            "Alpha Adjust" : "-0.998"
            "id" : "scale",
            "scale" : "0.03"
  • In your plugin, use these methods to get a handle on the storable and change it - observe the correlation with the JSON (CubeMat and Alpha Adjust):
JSONStorableFloat jsonAlpha = containingAtom.GetStorableByID("CubeMat")?.GetFloatJSONParam("Alpha Adjust");
if (jsonAlpha != null) jsonAlpha.val = -0.998f;
Credit to MacGruber for the pointers on this

containingAtom // The atom you applied the plugin to)
GetStorableByID() // Find a storable to change using an ID. e.g. CubeMat or scale
?. // if GetStorableByID() doesn't find anything, it will return a Null, and Null does not contain a method called GetFloatJSONParam(). The ?. prevents an error in this case.
GetFloatJSONParam() // gets handle on the parameter within the storable that you want to tweak with code.

Armed with this knowledge, here is the script complete with handy comments.
using System;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks; // VaM throws an error when this is left included. Not needed?

namespace NoButYeaNS
    class NBYControllerCollision2: MVRScript

        private float nextActionTime = 0.0f; // just for logging every 10 seconds or so - avoid logs every frame
        public float period = 10; // log interval - number of seconds

        public override void Init()
            pluginLabelJSON.val = "Controller Collision";

        // Runs once when plugin loads - after Init()
        protected void Start()
            // check we have applied to a cube or sphere only
            if(!(containingAtom?.type == "Cube" || containingAtom?.type == "Sphere"))
                SuperController.LogMessage("Add plugin to Cube or Sphere only");

            // show a message
            SuperController.LogMessage(pluginLabelJSON.val + " Loaded");

            // change scale
            JSONStorableFloat jsonScale = containingAtom.GetStorableByID("scale")?.GetFloatJSONParam("scale");
            if(jsonScale != null) jsonScale.val = 0.03f;          

            // turn phyisics off - prevents the atom getting stuck when walking through walls etc.
            JSONStorableBool jsonPhysicsEnabled = containingAtom.GetStorableByID("control")?.GetBoolJSONParam("physicsEnabled");
            if (jsonPhysicsEnabled != null) jsonPhysicsEnabled.val = false;

            // make semi transparrent here
            string matName = (containingAtom?.type == "Cube") ? "CubeMat" :"SphereMat"; // for a Sphere, the material name is different
            JSONStorableFloat jsonAlpha = containingAtom.GetStorableByID(matName)?.GetFloatJSONParam("Alpha Adjust");
            if (jsonAlpha != null) jsonAlpha.val = -0.998f;

            // SuperController.LogMessage("Atom name: " + containingAtom.name);
            // SuperController.LogMessage("Atom type: " + containingAtom.type);


        // A Unity thing - runs every physics cycle
        public void FixedUpdate()
            // put code here

        // Unity thing - runs every rendered frame
        public void Update()
            // each frame, copy the camera position and rotation accross to the containing atom
            containingAtom.mainController.transform.position = CameraTarget.centerTarget.transform.position + new Vector3(0f, 0.05f, 0f);
            containingAtom.mainController.transform.rotation = CameraTarget.centerTarget.transform.rotation;

            // debug info... just prints position data every 10 seconds - left in for reference.
            if(Time.time > nextActionTime)
                nextActionTime = Time.time + period;
                    "atom pos:" + containingAtom.mainController.transform.position.ToString() +
                    ":: cam pos:" + CameraTarget.centerTarget.transform.position.ToString() +
                    ":: type: " + containingAtom?.type


Maybe you could take this and extend it. Add another 2 cubes one for each VR hand. Maybe you need to name your atoms so you can identify them in the plugin script? So that you can update the position of the appropriate cube to be the same as your hands.
tip (thanks again MacGruber):
  • SuperController.singleton.leftHand
  • SuperController.singleton.rightHand

Comment if you find any issues or would like more guides.

First release
Last update
5.00 star(s) 2 ratings

More resources from nobutyea

Latest reviews

Very useful article... Didn't know how to find the proper storables, how to access the containing atom's transform or the main camera pos / rotation! Please add more tutorials... sorely needed! :)
Upvote 0
Thanks for your effort! Really helpful!
Upvote 0
Top Bottom