-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
895 additions
and
1,438 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
Oops, something went wrong.