Beer Pong

I’ve built a VR Beer Pong game for Oculus Quest2.

203517388_175018134503405_6320933599518569931_n.jpg

VR Beer Pong Game

A Virtual Reality Beer pong game, also known as Beirut, is a game in which player throw a ping pong ball across a table with the intent of landing the ball in a cup of beer on the other end.


DEMO

ABOUT THE GAME

Beer pong, also known as Beirut, is a drinking game in which players throw a ping pong ball across a table with the intent of landing the ball in a cup of beer on the other end. The game typically consists of opposing teams of two or more players per side with 6 or 10 cups set up in a triangle formation on each side. Each team then takes turns attempting to throw ping pong balls into the opponent's cups. If a ball lands in a cup, the contents of that cup are consumed by the other team and the cup is removed from the table. The first team to eliminate all of the opponent's cups is the winner.


PACKAGES

For this project I’ve used listed packages;

  • XR Plugin in Management - Oculus

  • Open XR Plugin

  • XR Interaction Toolkit

PROCESS

Most important functionalities of this project are picking up things(grabbing objects) and moving around the space. 

In order to picking up the objects, I’ve added XR Grab intractable component to the pingpong balls. This component adds Rigidbody automatically to the objects that are related. Later, I’ve to play around with the velocity scale, smoothing and attach ease in order to create an illusion of a real pingpong ball physics. The balls also have their own Physic Materials that bounciness is fixed at around 0.5 to 0.8.

In my XR Rig I’ve created LeftHand and RightHand Controllers and attached Oculus hand models for each component. In order to set up the controllers, I’ve used XRRig which includes XR Interaction Manager - Input action manager Script(which is already default) and Locomotion System. The locomotion system by default presets it to be teleportation and snap turns, but for this project I’ve deselected it and I added continuous move provider. 

I’ve arranged the functionalities accordingly;

  • Snap turn to be on the right controller

  • Move to be on the left controller

The most difficult part for this project was to animate the hands.(Action: When you press the buttons, fingers move) I’ve used oculus’s hand models which is free on oculus’s website - link. It includes 2 mb files for right and left hands, in order to open it I used my Maya account, but I’ve realized some fbx. models are available online. 

After I’ve attached the models to controller objects, I’ve worked on positioning the hand models to controllers orientation. Orienting the hand’s pivot point for X,Y,Z axis of controller took me a whole day, but I still need to work on it, doesn’t really pivot around the wrist area.

To trigger the appropriate fingers to move, I’ve attached animator component for each model. In order to have an animator I’ve created the avatars and started to actually animate the hand. Inside of hand_world, there is the skeletal structure of the all bones, I’ve rotated all the fingers from related indexes in order to create a decent natural looking closed fist. 

Hand_Animation.gif
 

Later, I’ve programmatically cause the animation to happen when I pressed the buttons. In order to do that I’ve used avatar masked. So, there are to functionalities; 

  • Trigger (Thumb and index fingers)

  • Grip (middle, pinky and ring fingers)

Note for coding part while doing the parameters: They are float numbers. 

CODING

There are two scripts for hand movement: Hand(for: Gripping, animating etc.) and Hand Controller(for: trigger those actions). So, the hand controller is communicating the trigger press, understand it and than trigger the appropriate actions from the hand.

Here’s the scripts for hand and hand controller:

Trigger and Grip Layers

Trigger and Grip Layers

Hand Animation for each finger

Hand Animation for each finger

Hand.cs
HandController.cs

using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Animator))] public class Hand : MonoBehaviour { public float speed; Animator animator; SkinnedMeshRenderer mesh; private float gripTarget; private float triggerTarget; private float gripCurrent; private float triggerCurrent; private string animatorGripParam = "Grip"; private string animatorTriggerParam = "Trigger"; // Start is called before the first frame update void Start() { animator = GetComponent<Animator>(); mesh = GetComponentInChildren<SkinnedMeshRenderer>(); } // Update is called once per frame void Update() { AnimateHand(); } internal void SetGrip(float v) { gripTarget = v; } internal void SetTrigger(float v) { triggerTarget = v; } void AnimateHand() { if(gripCurrent != gripTarget) { gripCurrent = Mathf.MoveTowards(gripCurrent, gripTarget, Time.deltaTime * speed); animator.SetFloat(animatorGripParam, gripCurrent); } if(triggerCurrent != triggerTarget) { triggerCurrent = Mathf.MoveTowards(triggerCurrent, triggerTarget, Time.deltaTime * speed); animator.SetFloat(animatorTriggerParam, triggerCurrent); } } public void ToggleVisibility() { mesh.enabled = !mesh.enabled; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; [RequireComponent(typeof(ActionBasedController))] public class HandController : MonoBehaviour { ActionBasedController controller; public Hand hand; // Start is called before the first frame update void Start() { controller = GetComponent<ActionBasedController>(); } // Update is called once per frame void Update() { hand.SetGrip(controller.selectAction.action.ReadValue<float>()); hand.SetTrigger(controller.activateAction.action.ReadValue<float>()); } }

PROBLEMS

The issue was when I pick something up the object was snapping the pivot point of the hand. So, I’ve remedy that by hiding the hand when you pick an object(balls), so that the balls doesn’t look inside the hands. In order to do that, inside the hand class I’ve added SkinnedMeshRenderer and with ToggleVisibility method, I’ve disabled the visuals of the hand when the interaction is enabled. Putted it inside the interaction events/ on select Intractable (enter/exit).

Public void ToggleVisibility()
{
mesh.enabled = !mesh.enabled;
}