Bowling Game VR

This Section is dedicated to document my work on this mini bowling Game

1°)Introduction:

For this lab, I adapted the tutorial provided by Wen-Jie Tseng to a bowling game in VR. This section consists of two parts. First, I am going to go through the scene and its elements. Secondly, I am going to explain the scripts that I used for the game.

2°)Scene elements:

a)3d Objects:

I created a scene using unity’s basic 3d objects. I also used a free asset from unity’s store for the ball and the kegels. Down below you can find the final scene and the full hierarchy of 3D objects:

Final Scene
hierarchy of 3D objects

b)The ball:

I attached to the ball a sphere collider and a rigid body component. I adjusted the sphere collider to the ball’s size and kept the rigid body component with default parameters.

Ball's components

b)The Kegel:

I basically did the same thing for the kegel. Instead of a sphere collider, I fitted a capsule collider along the Y-Axis. I also reduced the mass of the kegel in order to empower the impact of the ball when thrown.

Kegels's components

c)Left/Right hand anchor:

I only attached a sphere collider to the left and right hand anchor.

Left hand anchor's components

d)The score:

I created a simple Text-Text Mesh pro 3d object and made it the child of the scoreboard 3d object.

Left hand anchor's components

e)Collision Matrix and layers of collisions:

For this scene, I used two layers of collisions: walls and selection. All the static elements like the walls and the table belong to the walls layer. The ball, kegels and the right/hand anchor belong to the selection layer. Here is a snippet of the collision matrix that I used

Left hand anchor's components

3°)Scripts and game mechanism:

1°) The selection:

For this part, I mainly followed Wen-Jie Tseng’s tutorial on how to handle the selection.

I did one minor modification, I had to flip some of the coordinates when I transmit the controller velocity to the ball’s one. And also I boosted the value of the speed on the X-Axis. The value of boost is set to 3.0f by default.


triggerValue=OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, controller);
if (isInCollider)
{
	if (!isSelected && triggerValue > 0.95f)
	{
		isSelected = true;
		selectedObj.transform.parent = this.transform;
		Rigidbody rb = selectedObj.GetComponent();
		rb.isKinematic = true;
		rb.useGravity = false;
		rb.velocity = Vector3.zero;
		//rb.angularVelocity = Vector3.zero;
	}
	else if(isSelected && triggerValue < 0.95f)
	{
		isSelected = false;
		selectedObj.transform.parent=null;
		Rigidbody rb = selectedObj.GetComponent();
		rb.useGravity = true;
		rb.isKinematic = false;
		rb.velocity = new Vector3(-OVRInput.GetLocalControllerVelocity(controller).z*speedBoost, OVRInput.GetLocalControllerVelocity(controller).y, OVRInput.GetLocalControllerVelocity(controller).x);
	}
}
								

2°) Calculating Score:

In order to calculate the score, I had to fetch the flipped kegels in the scene. In the Awake method of MySelect class I used this method to do so:

listOfKegels = kegelParent.GetComponentsInChildren();
With listOfKegels being a private attribute of type Kegel[].

Then for each child of the kegelParent in the update method, I check if it is already flipped or not and whether its euler angles surpass a certain angle threshold. For my case I used 50 degrees.

Here is the code that loops on the kegels:


foreach (Kegel child in listOfKegels)
{
if (((Mathf.Abs(child.transform.localEulerAngles.x) > 50) ||(Mathf.Abs(child.transform.localEulerAngles.z) >50)) && (child.gameObject.activeSelf) && (child.transform.childCount==1) && (!(child.isFlipped())))
	{
							
	child.flip();
	score = score + 1;
	display.text ="Your score is : "+ score.ToString();
												
	}
}
								

I added the condition child.transform.childCount==1 because the prefab that I downloaded had a parent and one child and the “GetComponentsInChildren” method fetches every child of the initial parent. I had to make sure that I fetched the same number of existing kegels in order to calculate the score correctly.

3°) The "Kegel" & "ResetBall" classes:

These two classes will be used for resetting the game. The player can reset only the ball by pressing on the X button of the oculus’ right controller. And if he also wants to reset the kegels, he has to simultaneously press both of the X buttons of the two controllers. Here is a usefull link on how to use the buttons in the script: link

Here is the full code of the two classes: Kegel.cs:

 
public class Kegel : MonoBehaviour
{
    // Start is called before the first frame update
    private Vector3 initialPosition;
    private Quaternion rotation;
    private bool flipped;
    void Start()
    {
        initialPosition = transform.position;
        rotation = transform.rotation;
    }

    // Update is called once per frame
    void Update()
    {
        if ((OVRInput.GetDown(OVRInput.Button.One)) && (OVRInput.GetDown(OVRInput.Button.Three)))
        {
            transform.position = initialPosition;
            transform.rotation = rotation;
            Rigidbody rb = GetComponent();
            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            flipped = false;
        }
    }

    public void flip()
    {
        flipped = true;
    }

    public bool isFlipped()
    {
        return flipped;
    }

}
									
ResetBall.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResetBall : MonoBehaviour
{
	// Start is called before the first frame update
	private Vector3 initialPosition;
	private Rigidbody rb;

	void Start()
	{
		initialPosition = transform.position;
		rb =GetComponent < Rigidbody>();
	}

	// Update is called once per frame
	void Update()
	{
		if(OVRInput.GetDown(OVRInput.Button.One) && (rb.velocity.magnitude < 0.2)){
			transform.position = initialPosition;
			rb.velocity = Vector3.zero;
		}
		if (transform.position.y < 0)
		{
			
			rb.velocity = Vector3.zero;
			rb.angularVelocity = Vector3.zero;
			transform.position = initialPosition;
		}
	}

}
									
								

3°)Final Demo :

I will leave here a final demo of my mini game: