DEV Community 👩‍💻👨‍💻

Bennett Upfield
Bennett Upfield

Posted on

Official GameDev Post; Nameless: 1

SteamVr

This dev post will be about the controller aspect of a Unity VR game I am programming. I am of course using the unity VR system but I am also using the Valve.Vr unity add on, which you can reference Here if need be. The steam plugin adds the interesting feature of finger placements to the VR controller, the depth of complexity that this post will focus on.

Flashy Hands

The current "thing" that I am programming is wizard hands for the game. This is basically a set of different finger placements and other things that say which magic spells you will be using. Here is the code for accessing the finger positioning.

SteamVR_Action_Skeleton skeleton = whatever SteamVR_Action_Skeleton;
float[] curlindex = new float[5];
curlIndex = skeleton.fingerCurls;
Enter fullscreen mode Exit fullscreen mode

The curlIndex is a float array that contains the curl amount of the fingers around the controller with a value of 0 being completely off the controller and 1 being fully wrapped around. CurlIndex[0] is the thumb and the rest follow in order. Steam Vr also has the function of finger splay which measures the width between each finger, but because of differing hand sizes and the problem that when you lift a finger of the controller it gets very confused it is not really usable. Now currently I have three modes for finger positioning with three submodes for each of those modes.

float thumbJoySide = 0.65f;
float thumbButtonSide = 0.76f;
float indexWrapped = 0.25f;
float m_rWrapped = .35f;
if(curlIndex[0] >= thumbJoySide && curlIndex[0] <= thumbButtonSide && curlIndex[1] >= indexWrapped && curlIndex[2] >= m_rWrapped && curlIndex[3] <= m_rWrapped && curlIndex[4] <= m_rWrapped){
            mode1(); 
        }
else if(curlIndex[0] >= thumbButtonSide && curlIndex[1] <= indexWrapped && curlIndex[2] <= m_rWrapped && curlIndex[3] >= m_rWrapped && curlIndex[4] >= m_rWrapped){
            mode2();
        }
else if(curlIndex[0] <= thumbJoySide && curlIndex[1] >= indexWrapped && curlIndex[2] <= m_rWrapped && curlIndex[3] <= m_rWrapped && curlIndex[4] >= m_rWrapped){
            mode3();
        }
else if(curlIndex[0] > thumbJoySide && curlIndex[1] >= indexWrapped && curlIndex[2] >= m_rWrapped && curlIndex[3] >= m_rWrapped && curlIndex[4] >= m_rWrapped){
            closedFist();
        }
else if(curlIndex[0] < thumbJoySide && curlIndex[1] <= indexWrapped && curlIndex[2] <= m_rWrapped && curlIndex[3] <= m_rWrapped && curlIndex[4] <= m_rWrapped){
            openPalm();
        }
else
        {
            notAny();
        }
Enter fullscreen mode Exit fullscreen mode

As you can see above there are a few defined curl input sizes like ThumbJoySide. These are the values that I tested that seem reasonably accurate in telling if a finger is wrapped around or not. Now to set the value type and subtype in each of the function call that is a mode I set a string array of length 2 to the name of the mode.

handPosition[0] = "Fire";
handPosition[1] = "Fire";
Enter fullscreen mode Exit fullscreen mode

(Of course there are better ways to store it but this is an easy way to remember which is which right now)
The three submodes are set from the modes closedFist, openPalm and staying in the original mode position. As you've probably deduced by now the first part of the array is the main mode and the second value of the array is the submode. Now to reset which hand position you are in final else statement of notAny() initiates a timer that resets the "handPosition" array to the value "NoValue". Here is the simply switch statement for this.

notAny(){
     switch(handPosition[0]){
            case "Fire":
                if(releaseTimer <= 3) {
                    releaseTimer += Time.deltaTime;
                }
                else{
                    handPosition[0] = "NoValue";
                    handPosition[1] = "NoValue";
                    releaseTimer = 0; 
                }
                break;
            case "Ice":
                if(releaseTimer <= 3) {
                    releaseTimer += Time.deltaTime;
                }
                else{
                    handPosition[0] = "NoValue";
                    handPosition[1] = "NoValue";
                    releaseTimer = 0;
                }
                break;
            case "Lightning":
                if(releaseTimer <= 3) {
                    releaseTimer += Time.deltaTime;
                }
                else{
                    handPosition[0] = "NoValue";
                    handPosition[1] = "NoValue";
                    releaseTimer = 0;
                }
                break;
            case "NoValue":
                handPosition[1] = "NoValue";
                releaseTimer = 0;
                break;
      }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

I do admit that for these positions mode3 might be a bit to close to other modes, as when playtesting switching between mode one to two sometimes switches to mode three, so for three modes more specific finger positions might be required. But anyway, taking these values you can then have the player choose an attack style, grant special powers, maybe have some sort of movement adjustment signifier tied to hand position, or really anything you are creative enough to think of. A small demonstration of this is in an unrelated post by me "here" where both of the gifs utilize this function to do different things. If you have any thoughts or comments plz leave them down below as anything is helpful for improving this code.

Top comments (0)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.