Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Hesketh committed May 13, 2020
1 parent 85d909d commit a268e02
Show file tree
Hide file tree
Showing 16 changed files with 895 additions and 1,438 deletions.
1,575 changes: 420 additions & 1,155 deletions Assets/[Project]/Scenes/Main.unity

Large diffs are not rendered by default.

106 changes: 62 additions & 44 deletions Assets/[Project]/Scripts/Assembly/InteractionItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,83 @@
using UnityEngine;
using Valve.VR.InteractionSystem;

[RequireComponent(typeof(Rigidbody), typeof(Throwable))]
public class InteractionItem : MonoBehaviour
namespace VRAssembly
{
[SerializeField] private InteractionType type = null;

public InteractionType Type => type;

private new Rigidbody rigidbody = null;
private Throwable throwable = null;
private Collider[] colliders = null;

protected virtual void Awake()
/// <summary>
/// An interaction item is an item that is held by the VR player and should be used to complete a Slot
/// </summary>
[RequireComponent(typeof(Rigidbody), typeof(Throwable))]
public class InteractionItem : MonoBehaviour
{
TryGetComponent(out rigidbody);
TryGetComponent(out throwable);
[SerializeField] private InteractionType type = null;

colliders = GetComponentsInChildren<Collider>();
}
public InteractionType Type => type;

public void Consume(Transform position)
{
if (type.Consumable)
{
Debug.Log("Consuming: " + gameObject.name);
private new Rigidbody rigidbody = null;
private Throwable throwable = null;
private Collider[] colliders = null;

throwable?.interactable?.attachedToHand?.DetachObject(gameObject);
/// <summary>
/// Retrieve relevant components that are attached to the gameObject
/// </summary>
protected virtual void Awake()
{
TryGetComponent(out rigidbody);
TryGetComponent(out throwable);

foreach (Collider collider in colliders)
colliders = GetComponentsInChildren<Collider>();
}

/// <summary>
/// If we are instructed to be consumed, we must start the routine to move towards the target consumption point and detach ourselves from the VR Player
/// After calling this we don't expect any further User interaction with the item as it is due to no longer be used
/// </summary>
/// <param name="position">The target transform</param>
public void Consume(Transform position)
{
if (type.Consumable)
{
collider.enabled = false;
}
Debug.Log("Consuming: " + gameObject.name);

rigidbody.isKinematic = true;
throwable?.interactable?.attachedToHand?.DetachObject(gameObject);

StartCoroutine(LerpToPosition(position));
}
}
foreach (Collider collider in colliders)
{
collider.enabled = false;
}

private IEnumerator LerpToPosition(Transform target)
{
const float duration = 0.2f;
float time = 0.0f;
rigidbody.isKinematic = true;

Vector3 initialPosition = transform.position;
Quaternion initialRotation = transform.rotation;
StartCoroutine(LerpToPosition(position));
}
}

while(time < duration)
/// <summary>
/// Simple routine to move towards the target position ready to be consumed
/// </summary>
/// <param name="target">The target transform we will be consumed at</param>
private IEnumerator LerpToPosition(Transform target)
{
float progress = time / duration;
const float duration = 0.2f;
float time = 0.0f;

transform.position = Vector3.Lerp(initialPosition, target.position, progress);
transform.rotation = Quaternion.Slerp(initialRotation, target.rotation, progress);
Vector3 initialPosition = transform.position;
Quaternion initialRotation = transform.rotation;

yield return new WaitForEndOfFrame();
while (time < duration)
{
float progress = time / duration;

time += Time.deltaTime;
}
transform.position = Vector3.Lerp(initialPosition, target.position, progress);
transform.rotation = Quaternion.Slerp(initialRotation, target.rotation, progress);

transform.position = target.position;
transform.rotation = target.rotation;
yield return new WaitForEndOfFrame();

time += Time.deltaTime;
}

transform.position = target.position;
transform.rotation = target.rotation;
}
}
}
}
22 changes: 17 additions & 5 deletions Assets/[Project]/Scripts/Assembly/InteractionType.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
using UnityEngine;

[CreateAssetMenu(fileName = "Part", menuName = "Assembly/PartType", order = -100)]
public class InteractionType : ScriptableObject
namespace VRAssembly
{
[SerializeField] private bool consumable = true;
/// <summary>
/// Simple class to indicate the type of part (determined by the actual asset and asset name)
/// Also indicates whether this object is consumed
/// </summary>
[CreateAssetMenu(fileName = "Part", menuName = "Assembly/PartType", order = -100)]
public class InteractionType : ScriptableObject
{
[SerializeField] private bool consumable = true;

public bool Consumable => consumable;
}
/// <summary>
/// Whether the part is consumable
/// Consumable is whether it is safe to destroy the part after it has been used to complete a step
/// For example, a nail is consumable but a hammer is not. A hammer can be used an infinite amount of time, a nail is lost once inserted
/// </summary>
public bool Consumable => consumable;
}
}
191 changes: 115 additions & 76 deletions Assets/[Project]/Scripts/Assembly/Slot.cs
Original file line number Diff line number Diff line change
@@ -1,102 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class Slot : Step
namespace VRAssembly
{
[Header("Type")]
[SerializeField] private InteractionType partType = null;

[Header("Time")]
[SerializeField] private float timeToComplete = 0f;
[SerializeField] private bool progressResets = false;

[Header("Rotation Check")]
[SerializeField] private float tolerance = 0.05f;
[Space(8)]
[SerializeField] private bool up = false;
[SerializeField] private bool right = false;
[SerializeField] private bool forward = false;
[Space(8)]
[SerializeField] private bool upSymmetrical = false;
[SerializeField] private bool rightSymmetrical = false;
[SerializeField] private bool forwardSymmetrical = false;

[Header("Position Check")]
[SerializeField] private float maxDistance = 0.025f;

public Action<float> OnProgressChanged;

private List<InteractionItem> trackedParts = new List<InteractionItem>();
private float currentTimeToComplete = 0.0f;

protected void OnTriggerEnter(Collider other)
/// <summary>
/// An extension of a Step that must be completed that makes up the project
/// A Slot is a visual Step where an InteractionItem must be placed at the correct angle and position to complete
/// </summary>
[RequireComponent(typeof(Rigidbody))]
public class Slot : Step
{
InteractionItem part = other.gameObject.GetComponentInParent<InteractionItem>();
if (part && part.Type == partType)
[Header("Type")]
[SerializeField] private InteractionType partType = null;

[Header("Time")]
[SerializeField] private float timeToComplete = 0f;
[SerializeField] private bool progressResets = false;

[Header("Rotation Check")]
[SerializeField] private float tolerance = 0.05f;

[Space(8)]
[SerializeField] private bool up = false;
[SerializeField] private bool right = false;
[SerializeField] private bool forward = false;
[Space(8)]
[SerializeField] private bool upSymmetrical = false;
[SerializeField] private bool rightSymmetrical = false;
[SerializeField] private bool forwardSymmetrical = false;

[Header("Position Check")] [SerializeField]
private float maxDistance = 0.025f;

private List<InteractionItem> trackedParts = new List<InteractionItem>();
private float currentTimeToComplete = 0.0f;

/// <summary>
/// When anything moves into the trigger for this slot, we need to add it from our collection of InteractionItems that we maintain
/// That we process in the update if need be
/// </summary>
/// <param name="other">The Collider that is intersecting this slot</param>
protected void OnTriggerEnter(Collider other)
{
trackedParts.Add(part);
InteractionItem part = other.gameObject.GetComponentInParent<InteractionItem>();
if (part && part.Type == partType)
{
trackedParts.Add(part);
}
}
}

protected void OnTriggerExit(Collider other)
{
InteractionItem part = other.gameObject.GetComponentInParent<InteractionItem>();
if (part && part.Type == partType)
/// <summary>
/// When anything moves out of the trigger for this slot, we need to remove it from our collection of InteractionItems that we maintain
/// </summary>
/// <param name="other">The Collider that was intersecting this slot</param>
protected void OnTriggerExit(Collider other)
{
trackedParts.Remove(part);
InteractionItem part = other.gameObject.GetComponentInParent<InteractionItem>();
if (part && part.Type == partType)
{
trackedParts.Remove(part);
}
}
}

protected void Update()
{
if (Available)
/// <summary>
/// Each update if we are available to be completed we want to perform comparisons with all parts
/// that are currently intersecting this slot
/// </summary>
protected void Update()
{
foreach (InteractionItem part in trackedParts)
if (Available)
{
PerformComparison(part);
foreach (InteractionItem part in trackedParts)
{
PerformComparison(part);
}
}
}
}

protected virtual void OnValidate()
{
GetComponent<Rigidbody>().isKinematic = true;

foreach (Collider collider in GetComponentsInChildren<Collider>())
/// <summary>
/// Perform some validation checks on components attached to the same gameobject
/// We have certain assumptions about these components that must be met for things to work as intended
/// </summary>
protected virtual void OnValidate()
{
collider.isTrigger = true;
}
}
// Just for sanity, ensure that the rigidbody is kinematic as this is what the Slot expects
// Slots should not be items that move around or do anything with real physic interactions
GetComponent<Rigidbody>().isKinematic = true;

private void PerformComparison(InteractionItem part)
{
Transform other = part.transform;

Debug.Log(Vector3.Dot(other.forward, transform.forward));
// We also expect all Slots to be triggers
// So for sanity, ensure they all are
foreach (Collider collider in GetComponentsInChildren<Collider>())
{
collider.isTrigger = true;
}
}

// If the alignment isnt correct
if (((Vector3.Distance(other.position, transform.position) > maxDistance)
|| ((up) && 1.0f - (upSymmetrical ? Mathf.Abs(Vector3.Dot(other.up, transform.up)) : Vector3.Dot(other.up, transform.up)) > tolerance))
|| ((right) && 1.0f - (rightSymmetrical ? Mathf.Abs(Vector3.Dot(other.right, transform.right)) : Vector3.Dot(other.right, transform.right)) > tolerance)
|| ((forward) && 1.0f - (forwardSymmetrical ? Mathf.Abs(Vector3.Dot(other.forward, transform.forward)) : Vector3.Dot(other.forward, transform.forward)) > tolerance))
/// <summary>
/// Compares the position and rotation of a part with this slot
/// If they are close enough together, and close enough in terms of matching rotation
/// Then if they are held in that position for long enough
/// We can mark the slot as filled / complete
/// </summary>
/// <param name="part">The part that we are performing our comparison with</param>
private void PerformComparison(InteractionItem part)
{
if (progressResets)
Transform other = part.transform;

Debug.Log(Vector3.Dot(other.forward, transform.forward));

// If the alignment isnt correct
if (((Vector3.Distance(other.position, transform.position) > maxDistance)
|| ((up) && 1.0f - (upSymmetrical
? Mathf.Abs(Vector3.Dot(other.up, transform.up))
: Vector3.Dot(other.up, transform.up)) > tolerance))
|| ((right) && 1.0f - (rightSymmetrical
? Mathf.Abs(Vector3.Dot(other.right, transform.right))
: Vector3.Dot(other.right, transform.right)) > tolerance)
|| ((forward) &&
1.0f - (forwardSymmetrical
? Mathf.Abs(Vector3.Dot(other.forward, transform.forward))
: Vector3.Dot(other.forward, transform.forward)) > tolerance))
{
currentTimeToComplete = 0.0f;
if (progressResets)
{
currentTimeToComplete = 0.0f;
}

return;
}

return;
}
if (currentTimeToComplete >= timeToComplete)
{
Complete = true;
part.Consume(transform);
}

if (currentTimeToComplete >= timeToComplete)
{
Complete = true;
part.Consume(transform);
currentTimeToComplete += Time.deltaTime;
}

currentTimeToComplete += Time.deltaTime;
OnProgressChanged?.Invoke(currentTimeToComplete);
}
}
Loading

0 comments on commit a268e02

Please sign in to comment.