Skip to content

Instantly share code, notes, and snippets.

@nin-jat
Created January 10, 2017 12:00
Show Gist options
  • Select an option

  • Save nin-jat/af1f0ebc08b7b7509827fc8b5f8c1aab to your computer and use it in GitHub Desktop.

Select an option

Save nin-jat/af1f0ebc08b7b7509827fc8b5f8c1aab to your computer and use it in GitHub Desktop.
using UnityEngine;
using System.Collections.Generic;
using System;
public class HandheldItem : MonoBehaviour
{
internal SteamVR_TrackedController controller;
internal float pickupRadius;
public bool Highlighted = false;
public void PickUp(SteamVR_TrackedController controller)
{
this.controller = controller;
// The item was picked up.
}
public void Drop()
{
// The item is dropped.
}
}
using UnityEngine;
using System.Collections.Generic;
using System;
public class HandheldManager : MonoBehaviour {
#region singleton instance
// Other scripts cannot access this.
private static HandheldManager instance;
// Other scripts can only read from this variable.
public static HandheldManager Instance
{
get
{
// If the instance variable has not been set then find an object of this type.
// If it's still not set then just wedge about it. Sometimes however you might
// want to instantiate this script and this is where you would do it.
if (instance == null)
{
instance = FindObjectOfType<HandheldManager>();
if (instance == null)
Debug.LogError("There is no HandheldManager Scripts in this scene");
}
// Return instance.
return instance;
}
}
#endregion
public SteamVR_TrackedController leftController;
public SteamVR_TrackedController rightController;
public List<HandheldItem> items = new List<HandheldItem>();
public Hand leftHand;
public Hand rightHand;
// This class, this class is the most important class of all the classes (in this file).
// It does everything!
public class Hand
{
#region Variables
// The item the controller is currently holding. If the hand is holding nothing it will be NULL.
public HandheldItem heldItem;
// The controller that is linked to this hand.
public SteamVR_TrackedController controller;
// The item that is highlighted.
public HandheldItem highlightedItem;
// The name of the hand. E.g. 'middle hand'
public string name;
#endregion
// The constructor for this class.
public Hand(SteamVR_TrackedController controller, string name)
{
// Set the controller and the name to the ones provided and register a Gripped event.
// See 'ControllerGripped' for more info on the last bit.
this.controller = controller;
this.name = name;
controller.Gripped += ControllerGripped;
}
// This will find an object suitable for picking up.
public void ScanTick(ref List<HandheldItem> items)
{
// If the hand is holding an item then just return out.
if (heldItem != null)
return;
// Make a variable to store the nearest item.
HandheldItem nearest = null;
// === Find the nearest item to the controller only if the item is ===
// A. Not already picked up.
// B. It is the closest item.
// C. It is not 400 km away (closer than the item.radus)
{
Vector3 pos = controller.transform.position;
int count = items.Count;
//Set the distance to the largest number possible (for a float) and create a variable
// to keep track of what the nearest items is.
float smallestDistance = Mathf.Infinity;
int nearestItem = -1;
// Loop over <meme> ALL THE THINGS! </meme> (items).
for (int i = 0; i < count; i++)
{
// If the item is not already picked up [A] (the item keeps track of what controller is
// holding it) then get the itemDistance between this controller and the items[i]. Next,
// find out if the itemDistance is smaller than the smallestDistance [B] and.... if the
// itemDistance is within the item's pickup radius [C].
// [A]
if (items[i].controller == null)
{
float itemDistance = Vector3.Distance(pos, items[i].transform.position);
// [B] & [C]
if (itemDistance < smallestDistance && itemDistance < items[i].pickupRadius)
{
smallestDistance = itemDistance;
nearestItem = i;
}
}
}
// If an item was found, set the nearest item variable for the next part.
if (nearestItem >= 0)
nearest = items[nearestItem];
}
// === Update the highlighted statuses only if an item was found from the above code. ===
// The highlight only has to change if the highlighted item has changed.
if (nearest != highlightedItem)
{
// Sometimes these two variables can be null. So a null-check is required.
// Because the highlighted item is now different we can turn off the highlighted item
// before we change it.
if (highlightedItem != null)
highlightedItem.Highlighted = false;
// Turn on the nearest item highlight before we change it.
if (nearest != null)
nearest.Highlighted = true;
// Make the nearest item the highlighted item.
highlightedItem = nearest;
}
}
// ControllerGripped. This is called every time the Grip button on the controller is pressed.
// This is just a better (Shhhh. everyone has their own options ((that are 100% correct)) way
// to do stuff when a button is pressed. Notice, no Update().
private void ControllerGripped(object sender, ClickedEventArgs e)
{
// So the controller button was just pressed. If there is a highlighted item and if there
// is no held item then pick up the highlighted item.
if (highlightedItem != null && heldItem == null)
{
// How does one pick up an item? First, Pick it up, then make it 'in this hand,' next
// remove the highlight and finally make the highlighted item null.
highlightedItem.PickUp(controller);
heldItem = highlightedItem;
highlightedItem.Highlighted = false;
highlightedItem = null;
}
// If there is an item then just drop it, yep let that 3 million Jet engine hit the ground.
else if (heldItem != null)
{
// Drop it then make it 'not in this hand.'
heldItem.Drop();
heldItem = null;
}
}
}
void Awake()
{
// Once the script has loaded set-up the left and right hands using the controllers above.
leftHand = new Hand(leftController, "Left Hand");
rightHand = new Hand(rightController, "Right Hand");
}
void FixedUpdate()
{
// Run the scan tick on each hand.
leftHand.ScanTick(ref items);
rightHand.ScanTick(ref items);
// Notice the ref. I don't know if this is needed for a List<T> but this just makes the function
// receive a reference of the item instead of the item it's self (saves memory).
}
#region Item Registration
// Registration and Un-Registration of items. Instead of doing a FindObjectsOfType on start, I have
// made all items add (and remove) themselves to the list of items. Because you might want items to get created
// and destroyed at runtime.
public void RegisterItem(HandheldItem item)
{
if (!items.Contains(item))
items.Add(item);
}
public void UnRegisterItme(HandheldItem item)
{
if (items.Contains(item))
items.Remove(item);
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment