From d594622b191f0674a4e4e2fc02657a49d720b1ae Mon Sep 17 00:00:00 2001 From: rubic Date: Wed, 19 Feb 2020 15:37:30 -0800 Subject: [PATCH 1/7] started to make changes to yarn again, planning big design changes --- Assets/Scripts/Interactables/Yarn.cs | 4 ++-- Assets/Scripts/YarnContacting/Contact.cs | 6 ++--- Assets/Scripts/YarnContacting/Contactable.cs | 23 +++++++++++++++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index 1b0a67f..4c3fecc 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -21,11 +21,11 @@ public enum State { */ private List contacts; - public void AddContact(GameObject obj) { + public void AddContact(Contactable obj) { contacts.Add(new Contact(this, obj, levelManager, 0)); } - public void InsertContact(GameObject obj, int index, float initialAngle) { + public void InsertContact(Contactable obj, int index, float initialAngle) { contacts.Insert(index, new Contact(this, obj, levelManager, initialAngle)); } diff --git a/Assets/Scripts/YarnContacting/Contact.cs b/Assets/Scripts/YarnContacting/Contact.cs index 73765f6..5b28bdc 100644 --- a/Assets/Scripts/YarnContacting/Contact.cs +++ b/Assets/Scripts/YarnContacting/Contact.cs @@ -7,8 +7,8 @@ public class Contact { // this Contact is in this Yarn's contacts list public Yarn yarn; - // this Contact's GameObject - public GameObject source; + // the Contactable that this Contact points to + public Contactable source; private LevelManager levelManager; @@ -31,7 +31,7 @@ public class Contact { // a list of candidates that this Contact might turn into a proceeding contact public Dictionary candidates; - public Contact(Yarn yarn, GameObject source, LevelManager levelManager, float initialAngle) { + public Contact(Yarn yarn, Contactable source, LevelManager levelManager, float initialAngle) { this.yarn = yarn; this.source = source; this.levelManager = levelManager; diff --git a/Assets/Scripts/YarnContacting/Contactable.cs b/Assets/Scripts/YarnContacting/Contactable.cs index 24f9a2b..d1cddda 100644 --- a/Assets/Scripts/YarnContacting/Contactable.cs +++ b/Assets/Scripts/YarnContacting/Contactable.cs @@ -8,6 +8,27 @@ * A Contactable is responsible for containing the sort of information that a Contact would * need if this GameObject became a Contact. */ -public class Contactable : MonoBehaviour { +public abstract class Contactable : MonoBehaviour { + /** + * Returns a new Contact object that represents this Contactable. + */ + public Contact GetContact() { + return new Contact(); + } +} + +/** + * If a Yarn object wrapping around this Contactable should send a Contact to that Yarn, + * put this Behaviour on that GameObject. + */ +public class WrapContactable : Contactable { } + +/** + * If the player interacting with this Contactable should send a Contact to the player, + * put this Behaviour on that GameObject. + */ +public class InteractContactable : Contactable { + +} \ No newline at end of file From 388d4a63804bd039a9511c252e12c3dd7a6b9000 Mon Sep 17 00:00:00 2001 From: rubic Date: Mon, 2 Mar 2020 19:28:26 -0800 Subject: [PATCH 2/7] third larger attempt to split up files and design the yarn properly split up files accordingly into the YarnLine on its own, Contactables as Behaviours that attach to each type of object, and Contacts which are created and destroyed to maintain the line. code is not working yet. need to fix pushpin errors and YarnLine does not yet appropriately update its Contacts --- Assets/Scenes/Template.unity | 2 +- Assets/Scripts/Interactables/Pushpin.cs | 78 +++--- Assets/Scripts/Interactables/Yarn.cs | 131 ++-------- Assets/Scripts/YarnContacting/Contact.cs | 227 +++++++----------- Assets/Scripts/YarnContacting/Contact.cs.meta | 4 +- Assets/Scripts/YarnContacting/Contact_Old.cs | 165 +++++++++++++ .../YarnContacting/Contact_Old.cs.meta | 3 + Assets/Scripts/YarnContacting/Contactable.cs | 79 +++++- Assets/Scripts/YarnContacting/YarnLine.cs | 109 +++++++++ .../Scripts/YarnContacting/YarnLine.cs.meta | 3 + ProjectSettings/ProjectSettings.asset | 60 +++-- 11 files changed, 544 insertions(+), 317 deletions(-) create mode 100644 Assets/Scripts/YarnContacting/Contact_Old.cs create mode 100644 Assets/Scripts/YarnContacting/Contact_Old.cs.meta create mode 100644 Assets/Scripts/YarnContacting/YarnLine.cs create mode 100644 Assets/Scripts/YarnContacting/YarnLine.cs.meta diff --git a/Assets/Scenes/Template.unity b/Assets/Scenes/Template.unity index 08531c0..bcd9b90 100644 --- a/Assets/Scenes/Template.unity +++ b/Assets/Scenes/Template.unity @@ -1415,7 +1415,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 50, y: 0, z: 0} --- !u!114 &963194229 MonoBehaviour: diff --git a/Assets/Scripts/Interactables/Pushpin.cs b/Assets/Scripts/Interactables/Pushpin.cs index 747a70e..b679e1a 100644 --- a/Assets/Scripts/Interactables/Pushpin.cs +++ b/Assets/Scripts/Interactables/Pushpin.cs @@ -27,58 +27,60 @@ public override void Interact() { */ private void YarnUpdate() { Yarn playerYarn = playerManager.YarnHeld; - - /* - * Yarn can be attached to this Pushpin if: - * - This Pushpin is Untied to anything - * - The player is holding onto yarn, in which case the player wants to start a line of yarn - * - The player is pulling yarn, in which case the player wants to finish a line of yarn - */ - if (state == State.Untied) { - if (playerManager.CheckState(PlayerManager.State.Holding)) { + + switch (state) { + /* + * Yarn can be attached to this Pushpin if: + * - This Pushpin is Untied to anything + * - The player is holding onto yarn, in which case the player wants to start a line of yarn + * - The player is pulling yarn, in which case the player wants to finish a line of yarn + */ + case State.Untied when playerManager.CheckState(PlayerManager.State.Holding): // start a line of yarn state = State.Tied; playerManager.SetState(PlayerManager.State.Pulling); connectedYarn = playerYarn; - connectedYarn.AddContact(gameObject); + //connectedYarn.AddContact(gameObject); print("Yarn was just tied to a Pushpin, starting a line."); - - } else if (playerManager.CheckState(PlayerManager.State.Pulling)) { + break; + case State.Untied when playerManager.CheckState(PlayerManager.State.Pulling): { // finish a line of yarn state = State.Tied; connectedYarn = playerYarn; connectedYarn.TieTo(this); print("Yarn was just tied to a Pushpin, ending a line."); + break; } - } - - /* - * Yarn can be detached from this Pushpin if: - * - This Pushpin is Tied OR Done already - * - The player is pulling yarn, which case they want to return to just holding yarn - * - This Pushpin must be part of this line of yarn AND be the only thing other than the player - * - The player is normal, in which case they want to change an existing line of yarn - * - This Pushpin must be either the first or last in the line of yarn AND there are at least two contacts - */ - else if (state == State.Tied || state == State.Done) { - if (playerManager.CheckState(PlayerManager.State.Pulling) + /* + * Yarn can be detached from this Pushpin if: + * - This Pushpin is Tied OR Done already + * - The player is pulling yarn, which case they want to return to just holding yarn + * - This Pushpin must be part of this line of yarn AND be the only thing other than the player + * - The player is normal, in which case they want to change an existing line of yarn + * - This Pushpin must be either the first or last in the line of yarn AND there are at least two contacts + */ + case State.Tied: + case State.Done: { + if (playerManager.CheckState(PlayerManager.State.Pulling) && connectedYarn.ContactCount() == 2 && connectedYarn == playerYarn) { - // return to holding yarn - state = State.Untied; - playerManager.SetState(PlayerManager.State.Holding); - connectedYarn.RemoveContactAll(gameObject); - connectedYarn = null; - print("Yarn was just untied from a Pushpin, undoing a line."); + // return to holding yarn + state = State.Untied; + playerManager.SetState(PlayerManager.State.Holding); + connectedYarn.RemoveContactAll(gameObject); + connectedYarn = null; + print("Yarn was just untied from a Pushpin, undoing a line."); - } else if (playerManager.CheckState(PlayerManager.State.Normal) - && connectedYarn.ContactCount() >= 2 - && connectedYarn.IsContactAtEnd(gameObject)) { - // start changing a line of yarn again - state = State.Untied; - connectedYarn.UntieFrom(this); - connectedYarn = null; - print("Yarn was just untied from a Pushpin, to edit a line."); + } else if (playerManager.CheckState(PlayerManager.State.Normal) + && connectedYarn.ContactCount() >= 2 + && connectedYarn.IsContactAtEnd(gameObject)) { + // start changing a line of yarn again + state = State.Untied; + connectedYarn.UntieFrom(this); + connectedYarn = null; + print("Yarn was just untied from a Pushpin, to edit a line."); + } + break; } } } diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index 4c3fecc..3bdae3e 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -5,8 +5,10 @@ public class Yarn : Interactable { public Vector3 positionYarnInPlayersArms; public LineRenderer lineRenderer; + public GameObject mesh; private LevelManager levelManager; + private YarnLine yarnLine; public enum State { Normal, @@ -16,90 +18,26 @@ public enum State { public bool IsDestroyed() { return state == State.Destroyed; } - /** - * The Yarn object maintains a list of Contacts to know what it has been wrapped around - */ - private List contacts; - - public void AddContact(Contactable obj) { - contacts.Add(new Contact(this, obj, levelManager, 0)); - } - - public void InsertContact(Contactable obj, int index, float initialAngle) { - contacts.Insert(index, new Contact(this, obj, levelManager, initialAngle)); - } - - /* Remove all Contacts with obj as its source. */ - public void RemoveContactAll(GameObject obj) { - foreach(Contact c in contacts.FindAll(c => c.source == obj)) - contacts.Remove(c); - } - - public void RemoveContact(Contact c) { contacts.Remove(c); } - - /* - * Remove a Contacts with obj as its source, but only at the beginning or end of the contacts list. - * - * Additionally causes the contacts list to reverse order if trying to remove the contact from the front. - * This is done in the event that the player tries to remove the yarn from the opposite end, so that - * the yarn's contacts are always added from the end of the list. - */ - public void RemoveContactFromEnd(GameObject obj) { - if(contacts[0].source == obj) contacts.Reverse(); - if(contacts[contacts.Count - 1].source == obj) contacts.RemoveAt(contacts.Count - 1); - } - - /* Does the contacts list contain any Contact with obj as a source? */ - public bool ContainsContact(GameObject obj) { - return contacts.Exists(c => c.source == obj); - } - - /* Is obj a Contact at the beginning or end of the contacts list? */ - public bool IsContactAtEnd(GameObject obj) { - return contacts[0].source == obj || contacts[contacts.Count - 1].source == obj; - } - - public int ContactCount() { return contacts.Count; } - - public GameObject mesh; - protected override void Awake() { base.Awake(); state = State.Normal; - contacts = new List(); + yarnLine = null; levelManager = FindObjectOfType(); } private void Update() { + // update the visuals of the yarn line + yarnLine?.Update(); + // update the points the LineRenderer is rendering - if (lineRenderer) { + if (lineRenderer && yarnLine != null) { var linePoints = new List(); - foreach (var c in contacts) linePoints.AddRange(c.renderPoints); + foreach (var c in yarnLine.contacts) linePoints.AddRange(c.renderPoints); lineRenderer.positionCount = linePoints.Count; lineRenderer.SetPositions(linePoints.ToArray()); } } - private void FixedUpdate() { UpdateAllContacts(); } - - private void UpdateAllContacts() { - // first, update the render points for all contacts. - foreach(Contact c in contacts) - c.UpdateRenderPoints(); - - // next, update the angles that all contacts have to their next contact. - for(var i = 0; i < contacts.Count - 1; i++) - contacts[i].UpdateLine(contacts[i + 1]); - - // contacts remove themselves if they've been unraveled - /*for(var i = 1; i < contacts.Count - 1; i++) - contacts[i].UpdateUnraveled(contacts[i - 1]);*/ - - // update the potential contacts list, adding new proceeding contacts if necessary. - for(var i = 0; i < contacts.Count - 1; i++) - contacts[i].UpdateCandidates(contacts[i + 1], i); - } - public override void Interact() { // the player picks up the yarn if they have their arms free if (playerManager.CheckState(PlayerManager.State.Normal)) { @@ -112,68 +50,47 @@ public override void Interact() { private void ShowMesh() { mesh.SetActive(true); } private void PickUp() { - AddContact(player.gameObject); + // give the player the yarn object and tell them to start holding playerManager.SetState(PlayerManager.State.Holding); playerManager.YarnHeld = this; + // this yarn is no longer interactable playerInteract.RemoveInteractable(this); + // parent the yarn to the player and position it in their arms transform.SetParent(player.transform); transform.localPosition = positionYarnInPlayersArms; + print("The player just picked up some yarn."); } public void PutDown() { + // return the player to normal, take it from the player playerManager.SetState(PlayerManager.State.Normal); playerManager.YarnHeld = null; + // unparent the yarn, pulling it out to the outermost level transform.parent = null; + // calculate a new position for the yarn on the grid and set it there Vector3 positionOnGround = new Vector3( Mathf.Round(player.transform.localPosition.x/2f)*2f, 0, Mathf.Round(player.transform.localPosition.z/2f)*2f); transform.localPosition = positionOnGround; + print("The player has dropped the yarn."); } - - /* Untie this Yarn object from the given Pushpin, returning control to the player. */ - public void UntieFrom(Pushpin pushpin) { - playerManager.SetState(PlayerManager.State.Pulling); - RemoveContactFromEnd(pushpin.gameObject); - AddContact(player.gameObject); - if(mesh) ShowMesh(); - } /* Ties this Yarn off on the given Pushpin, removing control from the player. */ public void TieTo(Pushpin pushpin) { playerManager.SetState(PlayerManager.State.Normal); - RemoveContactFromEnd(player); - AddContact(pushpin.gameObject); if(mesh) HideMesh(); + + // todo: switch the pushpin and player } - private void OnDrawGizmos() { - // render gizmos showing the render point connections - if (contacts != null) - for (var i = 0; i < contacts.Count; i++) { - // draw lines between all of the render points for this contact - var thisContact = contacts[i]; - if (thisContact.renderPoints.Count < 1) continue; - - for (var j = 0; j < thisContact.renderPoints.Count - 1; j++) { - var thisPoint = thisContact.renderPoints[j]; - var nextPoint = thisContact.renderPoints[j+1]; - Gizmos.DrawLine(thisPoint, nextPoint); - } - // if we know there's another contact after this one, draw a line - // from the last renderPoint on this contact to the first renderPoint - // on the next contact. - if (i >= contacts.Count - 1) continue; - - var nextContact = contacts[i + 1]; - if (nextContact.renderPoints.Count < 1) continue; - var thisContactLastPointIndex = thisContact.renderPoints.Count - 1; - - var thisContactLastPoint = thisContact.renderPoints[thisContactLastPointIndex]; - var nextContactFirstPoint = nextContact.renderPoints[0]; - Gizmos.DrawLine(thisContactLastPoint, nextContactFirstPoint); - } + /* Untie this Yarn object from the given Pushpin, returning control to the player. */ + public void UntieFrom(Pushpin pushpin) { + playerManager.SetState(PlayerManager.State.Pulling); + if(mesh) ShowMesh(); + + // todo: remove the pushpin's contact, add the player } } \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/Contact.cs b/Assets/Scripts/YarnContacting/Contact.cs index 5b28bdc..8433a13 100644 --- a/Assets/Scripts/YarnContacting/Contact.cs +++ b/Assets/Scripts/YarnContacting/Contact.cs @@ -1,164 +1,101 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using UnityEngine; +using Vector3 = UnityEngine.Vector3; -public class Contact { - // this Contact is in this Yarn's contacts list - public Yarn yarn; +/** + * A Contact is a single instance of a Yarn object being connected to something. + * + * Only Contactables can create Contacts of themselves. + */ +public abstract class Contact { + // uses host for GameObject data and Transform + public Contactable host { get; protected set; } - // the Contactable that this Contact points to - public Contactable source; + // needs prev and nextContacts for calculating angles + public Contact prevContact { get; set; } + public Contact nextContact { get; set; } - private LevelManager levelManager; - - /* - * the line that this Contact is responsible for checking. - * leaves from this Contact's last renderPoint and goes to the first - * renderPoint in the next Contact. - * - * note that this value may be null if this Contact has no next Contact. - */ - public Vector3 yarnLine; - public Vector2 yarnLineXZ; - - // the initial angular velocity the player had when this Contact was created - private float initialAngle; - - // a list of calculated points that the yarn is actually rendered at - public List renderPoints; + // render points describe how the yarn is visually connected to this Contact + public List renderPoints { get; protected set; } + public Vector3 headRenderPoint => renderPoints[0]; + public Vector3 tailRenderPoint => renderPoints[renderPoints.Count-1]; - // a list of candidates that this Contact might turn into a proceeding contact - public Dictionary candidates; - - public Contact(Yarn yarn, Contactable source, LevelManager levelManager, float initialAngle) { - this.yarn = yarn; - this.source = source; - this.levelManager = levelManager; - this.initialAngle = initialAngle; - renderPoints = new List(); - candidates = new Dictionary(); - UpdateRenderPoints(); - } - - /* Update the render points for this Contact. */ - public void UpdateRenderPoints() { - // todo: show render points properly by using values from Contactable class - renderPoints.Clear(); - renderPoints.Add(source.transform.position); - } - - /* Update the line that this Contact has to the nextContact following it. */ - public void UpdateLine(Contact nextContact) { - // next contact must exist to find values for it! - if (nextContact == null) return; - - // update the values this Contact has with the next Contact. - // use render points to determine this. - yarnLine = nextContact.renderPoints[0] - renderPoints[renderPoints.Count - 1]; - yarnLineXZ = new Vector2(yarnLine.x, yarnLine.z); - } - - /* - * Updates the list of Candidates that this Contact is watching. - * - * If a Candidate has changed in some way this update that suggests it should - * become a new Contact, this Contact will add it. - */ - public void UpdateCandidates(Contact nextContact, int index) { - if (nextContact == null) return; - - /* - * Create a new list of candidates. - */ - Dictionary newCandidates = new Dictionary(); - foreach (var c in levelManager.allContactables) { - if (c.gameObject != source - && c.gameObject != nextContact.source - && c.enabled) { - newCandidates.Add(c, new Candidate(this, c)); + // the vector entering this Contact from a previous Contact + public Vector3 arrivingVector { + get { + if (prevContact == null) { + Debug.LogError($"{host.name} is hosting a Contact that was asked for an arriving vector, " + + $"but this Contact has no previous Contact!"); } + return headRenderPoint - prevContact.tailRenderPoint; } - - /* - * For each Candidate this Contact cares about this update, check to see if it has an old - * record. If it does, check several criteria to see if it changed in a way that makes it - * deserve to become a Contact. If it doesn't, - */ - foreach (var candidate in newCandidates) { - var oldCandidate = GetCandidate(candidate.Key); - var newCandidate = candidate.Value; - - if (!oldCandidate.Equals(default(Candidate))) { - // so we found an old record of this candidate. cool. - // get the angles of both of these - var oldAngle = oldCandidate.parentAngle; - var newAngle = newCandidate.parentAngle; - var newRadius = newCandidate.parentRadius; - - // has this Candidate rotated in a way that crossed over this Contact's angle? - // and is this Candidate now within distance of this Contact's line? - // and is the new angle close-ish to zero so we aren't connecting backwards? - if (oldAngle * newAngle < 0 - && newRadius < yarnLineXZ.magnitude - && Math.Abs(newAngle) < 90) { - // if all of this is true, this candidate becomes a new contact - yarn.InsertContact(newCandidate.source.gameObject, index + 1, newAngle); - } + } + + // the vector leaving this Contact to the next Contact + public Vector3 leavingVector { + get { + if (prevContact == null) { + Debug.LogError($"{host.name} is hosting a Contact that was asked for a leaving vector, " + + $"but this Contact has no next Contact!"); } - // update the list of candidates, deleting the old ones - candidates = newCandidates; + return nextContact.headRenderPoint - tailRenderPoint; } } - /* - * Disconnects the most recent contact based on yarn tracking. + /** + * Updates all of this Contact's data based on the position of the nextContact. + * + * It's assumed that the nextContact is a fluidly moving GameObject, so all calculations + * are performed between previous and upcoming data. */ - public void UpdateUnraveled(Contact prevContact) { - var prevYarnLineXZ = prevContact.yarnLineXZ; - var angleToPrevious = Vector2.SignedAngle(prevYarnLineXZ, yarnLineXZ); - if (angleToPrevious * initialAngle < 0 - && Math.Abs(angleToPrevious) < 90) { - yarn.RemoveContact(this); - // todo: does this delete this contact properly? - } - } + public abstract void Update(Contact nextContact); +} + +public class CircleContact : Contact { + // how many times has this CircleContact been wrapped around? + public int rotations { get; } + // what angle does this CircleContact's line leave at compared to its initial angle? + public float angle { get; } - private Candidate GetCandidate(Contactable c) { - return candidates.ContainsKey(c) ? candidates[c] : default; - } - /** - * A Candidate is created by a currently existing Contact somewhere in the scene - * because it cares about this Contactable's angle to it. + * A CircleContact can only be created once: + * - We know the Contactable that is hosting the CircleContact + * - We know the initial render point that caused the CircleContact + * - We know the initial angle of contact so we can tell which way yarn is wrapping + * - We may know the previous Contact or the next Contact */ - public struct Candidate { - /* - * the Contact that is interested in the details of this Candidate - */ - public Contact parent; - - // the Contactable behind this Candidate - public Contactable source; + public CircleContact( + WrapContactable host, + Vector3 initialPoint, + float initialAngle, + Contact prevContact = null, + Contact nextContact = null) { + this.host = host; + this.prevContact = prevContact; + this.nextContact = nextContact; + // render points always has at least one point in it, it may never be empty + renderPoints = new List{initialPoint}; + rotations = 0; + angle = initialAngle; + } + + public override void Update(Contact nextContact) { - // the angle this Contactable has with the parent Contact - public float parentAngle; - public float parentRadius; + } +} - public Candidate(Contact parent, Contactable source) { - this.parent = parent; - this.source = source; - - /* - * get the signed angle between the parent Contact's yarnLineXZ - * and the line between the parent and this Contactable - */ - var parentPos = parent.renderPoints[parent.renderPoints.Count - 1]; - var sourcePos = source.transform.position; - var vecParentToThis = sourcePos - parentPos; - var vecParentToThisXZ = new Vector2(vecParentToThis.x, vecParentToThis.z); - parentAngle = Vector2.SignedAngle(parent.yarnLineXZ, vecParentToThisXZ); - parentRadius = vecParentToThisXZ.magnitude; - } +public class PointContact : Contact { + public PointContact( + InteractContactable host, + Contact prevContact = null, + Contact nextContact = null) { + this.host = host; + this.prevContact = prevContact; + this.nextContact = nextContact; + renderPoints = new List{host.transform.position + host.pointOffset}; + } + + public override void Update(Contact nextContact) { + } } \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/Contact.cs.meta b/Assets/Scripts/YarnContacting/Contact.cs.meta index 4472acb..97f36bb 100644 --- a/Assets/Scripts/YarnContacting/Contact.cs.meta +++ b/Assets/Scripts/YarnContacting/Contact.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 8313f239bd594e03ae63464437b19a2e -timeCreated: 1575148448 \ No newline at end of file +guid: 6195e93a001149388842f1854309f7eb +timeCreated: 1582155899 \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/Contact_Old.cs b/Assets/Scripts/YarnContacting/Contact_Old.cs new file mode 100644 index 0000000..ae0c8b4 --- /dev/null +++ b/Assets/Scripts/YarnContacting/Contact_Old.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +/* +public class Contact_Old { + // this Contact is in this Yarn's contacts list + public Yarn yarn; + + // the Contactable that this Contact points to + public Contactable source; + + private LevelManager levelManager; + + /* + * the line that this Contact is responsible for checking. + * leaves from this Contact's last renderPoint and goes to the first + * renderPoint in the next Contact. + * + * note that this value may be null if this Contact has no next Contact. + #1# + public Vector3 yarnLine; + public Vector2 yarnLineXZ; + + // the initial angular velocity the player had when this Contact was created + private float initialAngle; + + // a list of calculated points that the yarn is actually rendered at + public List renderPoints; + + // a list of candidates that this Contact might turn into a proceeding contact + public Dictionary candidates; + + public Contact_Old(Yarn yarn, Contactable source, LevelManager levelManager, float initialAngle) { + this.yarn = yarn; + this.source = source; + this.levelManager = levelManager; + this.initialAngle = initialAngle; + renderPoints = new List(); + candidates = new Dictionary(); + UpdateRenderPoints(); + } + + /* Update the render points for this Contact. #1# + public void UpdateRenderPoints() { + // todo: show render points properly by using values from Contactable class + renderPoints.Clear(); + renderPoints.Add(source.transform.position); + } + + /* Update the line that this Contact has to the nextContact following it. #1# + public void UpdateLine(Contact nextContact) { + // next contact must exist to find values for it! + if (nextContact == null) return; + + // update the values this Contact has with the next Contact. + // use render points to determine this. + yarnLine = nextContact.renderPoints[0] - renderPoints[renderPoints.Count - 1]; + yarnLineXZ = new Vector2(yarnLine.x, yarnLine.z); + } + + /* + * Updates the list of Candidates that this Contact is watching. + * + * If a Candidate has changed in some way this update that suggests it should + * become a new Contact, this Contact will add it. + #1# + public void UpdateCandidates(Contact nextContact, int index) { + if (nextContact == null) return; + + /* + * Create a new list of candidates. + #1# + Dictionary newCandidates = new Dictionary(); + foreach (var c in levelManager.allContactables) { + if (c.gameObject != source + && c.gameObject != nextContact.source + && c.enabled) { + newCandidates.Add(c, new Candidate(this, c)); + } + } + + /* + * For each Candidate this Contact cares about this update, check to see if it has an old + * record. If it does, check several criteria to see if it changed in a way that makes it + * deserve to become a Contact. If it doesn't, + #1# + foreach (var candidate in newCandidates) { + var oldCandidate = GetCandidate(candidate.Key); + var newCandidate = candidate.Value; + + if (!oldCandidate.Equals(default(Candidate))) { + // so we found an old record of this candidate. cool. + // get the angles of both of these + var oldAngle = oldCandidate.parentAngle; + var newAngle = newCandidate.parentAngle; + var newRadius = newCandidate.parentRadius; + + // has this Candidate rotated in a way that crossed over this Contact's angle? + // and is this Candidate now within distance of this Contact's line? + // and is the new angle close-ish to zero so we aren't connecting backwards? + if (oldAngle * newAngle < 0 + && newRadius < yarnLineXZ.magnitude + && Math.Abs(newAngle) < 90) { + // if all of this is true, this candidate becomes a new contact + yarn.InsertContact(newCandidate.source.gameObject, index + 1, newAngle); + } + } + // update the list of candidates, deleting the old ones + candidates = newCandidates; + } + } + + /* + * Disconnects the most recent contact based on yarn tracking. + #1# + public void UpdateUnraveled(Contact prevContact) { + var prevYarnLineXZ = prevContact.yarnLineXZ; + var angleToPrevious = Vector2.SignedAngle(prevYarnLineXZ, yarnLineXZ); + if (angleToPrevious * initialAngle < 0 + && Math.Abs(angleToPrevious) < 90) { + yarn.RemoveContact(this); + // todo: does this delete this contact properly? + } + } + + private Candidate GetCandidate(Contactable c) { + return candidates.ContainsKey(c) ? candidates[c] : default; + } + + /** + * A Candidate is created by a currently existing Contact somewhere in the scene + * because it cares about this Contactable's angle to it. + #1# + public struct Candidate { + /* + * the Contact that is interested in the details of this Candidate + #1# + public Contact parent; + + // the Contactable behind this Candidate + public Contactable source; + + // the angle this Contactable has with the parent Contact + public float parentAngle; + public float parentRadius; + + public Candidate(Contact parent, Contactable source) { + this.parent = parent; + this.source = source; + + /* + * get the signed angle between the parent Contact's yarnLineXZ + * and the line between the parent and this Contactable + #1# + var parentPos = parent.renderPoints[parent.renderPoints.Count - 1]; + var sourcePos = source.transform.position; + var vecParentToThis = sourcePos - parentPos; + var vecParentToThisXZ = new Vector2(vecParentToThis.x, vecParentToThis.z); + parentAngle = Vector2.SignedAngle(parent.yarnLineXZ, vecParentToThisXZ); + parentRadius = vecParentToThisXZ.magnitude; + } + } +}*/ \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/Contact_Old.cs.meta b/Assets/Scripts/YarnContacting/Contact_Old.cs.meta new file mode 100644 index 0000000..4472acb --- /dev/null +++ b/Assets/Scripts/YarnContacting/Contact_Old.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8313f239bd594e03ae63464437b19a2e +timeCreated: 1575148448 \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/Contactable.cs b/Assets/Scripts/YarnContacting/Contactable.cs index d1cddda..3db6db1 100644 --- a/Assets/Scripts/YarnContacting/Contactable.cs +++ b/Assets/Scripts/YarnContacting/Contactable.cs @@ -1,4 +1,9 @@ -using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Quaternion = UnityEngine.Quaternion; +using Vector3 = UnityEngine.Vector3; /** * A GameObject with this class has the ability to become a Contact in a line of yarn. @@ -9,11 +14,19 @@ * need if this GameObject became a Contact. */ public abstract class Contactable : MonoBehaviour { - /** - * Returns a new Contact object that represents this Contactable. - */ - public Contact GetContact() { - return new Contact(); + public Vector3 pastPosition; + public Vector3 currentPosition; + + private void Awake() { + var position = transform.position; + pastPosition = position; + currentPosition = position; + } + + protected virtual void FixedUpdate() { + // update past and current positions + pastPosition = currentPosition; + currentPosition = transform.position; } } @@ -22,7 +35,56 @@ public Contact GetContact() { * put this Behaviour on that GameObject. */ public class WrapContactable : Contactable { + // this is the radius of a circle on the XZ plane that the yarn line can hit to contact this object. + [Tooltip("Specifies the radius of the infinitely tall cylinder that represents the WrapContactable.")] + public float radius = 0.1f; + + protected override void FixedUpdate() { + base.FixedUpdate(); + // todo: do whatever needs to be done with past and current positions + } + + public CircleContact GetNewContact(Vector3 initialPoint, float initialAngle, Contact prevContact, Contact nextContact = null) { + return new CircleContact(this, initialPoint, initialAngle, prevContact, nextContact); + } + + /** + * Returns true if, from the host to the wrapper's position, the wrapper has wrapped around the wrappee. + */ + public static bool CheckWrapAround(Contactable host, WrapContactable wrappee, Contactable wrapper) { + var hostPosition = host.transform.position; + + Vector3 vecToObj = wrappee.transform.position - hostPosition; + Vector3 oldVecToWrapper = wrapper.pastPosition - hostPosition; + Vector3 newVecToWrapper = wrapper.transform.position - hostPosition; + + float oldAngle = Vector3.SignedAngle(vecToObj, oldVecToWrapper, Vector3.up); + float newAngle = Vector3.SignedAngle(vecToObj, newVecToWrapper, Vector3.up); + // if the angle from the wrapper to the object has flipped (one is positive, one is negative) + // and if either the old or the new vector to the wrapper is longer than the vector to the object + // then the wrapper has successfully wrapped around + return (oldAngle * newAngle < 0) && + (oldVecToWrapper.magnitude > vecToObj.magnitude || newVecToWrapper.magnitude > vecToObj.magnitude); + } + /** + * This method returns both points on a circle on the XZ axis that is tangent from the base of vecToCircleCenter. + * + * Starting from the base of vecToCircleCenter, two lines can always be drawn tangent to a circle centered at the + * end of vecToCircleCenter with a radius of radius. Both of these points are returned in a Vector3[], with + * element 0 being the vector counter-clockwise (negative angle) from vecToCircleCenter and element 1 being + * the other. + */ + private static Vector3[] FindTangentPointsToCircle(Vector3 vecToCircleCenter, float radius) { + // this is the angle between vecToCircleCenter to both tangents + float angleToTangents = Mathf.Asin(radius / vecToCircleCenter.magnitude); + Vector3 negativeTangent = Quaternion.Euler(0, angleToTangents, 0) * vecToCircleCenter; + Vector3 positiveTangent = Quaternion.Euler(0, -angleToTangents, 0) * vecToCircleCenter; + return new [] { + Vector3.Project(vecToCircleCenter, negativeTangent), + Vector3.Project(vecToCircleCenter, positiveTangent) + }; + } } /** @@ -30,5 +92,10 @@ public class WrapContactable : Contactable { * put this Behaviour on that GameObject. */ public class InteractContactable : Contactable { + [Tooltip("This is the offset from the GameObject's position where yarn will be attached.")] + public Vector3 pointOffset; + public PointContact GetNewContact() { + return new PointContact(this); + } } \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs b/Assets/Scripts/YarnContacting/YarnLine.cs new file mode 100644 index 0000000..50b2e53 --- /dev/null +++ b/Assets/Scripts/YarnContacting/YarnLine.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using UnityEngine; + +/** + * A YarnLine is a list that represents all the connections of a line of yarn. + */ +public class YarnLine { + // the head and tail contacts are always PointContacts + private PointContact head, tail; + // every other contact in the list is some sort of Contact + private List wraps; + + private Yarn host; + + public List contacts { get; private set; } + public List renderPoints { get; private set; } + + /** + * A YarnLine can only be created by a Yarn that has been started between the Player and a Pushpin + */ + public YarnLine(Yarn host, PointContact player, PointContact pushpin) { + this.host = host; + head = player; + tail = pushpin; + wraps = new List(); + } + + public void Update() { + + } + + /* Fires whenever the structure of the line changes. */ + public void OnLineChanged() { + // update the contacts list + List newContacts = new List(wraps.Count + 2){tail}; + newContacts.AddRange(wraps); + newContacts.Add(head); + contacts = newContacts; + + // update the renderpoints based on changes contacts + + } + + public void Add(Contact contact) { + wraps.Add(contact); + OnLineChanged(); + } + + public int RemoveAll(Contact contact) { + int result = wraps.RemoveAll(wrap => wrap.host.gameObject.Equals(contact.host.gameObject)); + OnLineChanged(); + return result; + } + + /** + * If you try to give this function a Player's Contact, it will flip the entire list + * to ensure the Player is at the tail. + */ + public void SetHead(PointContact contact) { + head = contact; + if (contact.host.CompareTag("Player")) ReverseList(); + OnLineChanged(); + } + + public void SetTail(PointContact contact) { + tail = contact; + OnLineChanged(); + } + + /* Reverses the entire list, including the head and tail contacts. */ + public void ReverseList() { + // swap head and tail + var temp = tail; + tail = head; + head = temp; + // reverse all wrapping points + wraps.Reverse(); + // reverse all prev and next Contact references + + } + + private void OnDrawGizmos() { + // render gizmos showing the render point connections + if (contacts != null) + for (var i = 0; i < contacts.Count; i++) { + // draw lines between all of the render points for this contact + var thisContact = contacts[i]; + if (thisContact.renderPoints.Count < 1) continue; + + for (var j = 0; j < thisContact.renderPoints.Count - 1; j++) { + var thisPoint = thisContact.renderPoints[j]; + var nextPoint = thisContact.renderPoints[j+1]; + Gizmos.DrawLine(thisPoint, nextPoint); + } + // if we know there's another contact after this one, draw a line + // from the last renderPoint on this contact to the first renderPoint + // on the next contact. + if (i >= contacts.Count - 1) continue; + + var nextContact = contacts[i + 1]; + if (nextContact.renderPoints.Count < 1) continue; + var thisContactLastPointIndex = thisContact.renderPoints.Count - 1; + + var thisContactLastPoint = thisContact.renderPoints[thisContactLastPointIndex]; + var nextContactFirstPoint = nextContact.renderPoints[0]; + Gizmos.DrawLine(thisContactLastPoint, nextContactFirstPoint); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs.meta b/Assets/Scripts/YarnContacting/YarnLine.cs.meta new file mode 100644 index 0000000..a54fd9d --- /dev/null +++ b/Assets/Scripts/YarnContacting/YarnLine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2bfac64ab1734a58858c2eef220fcbe4 +timeCreated: 1582156244 \ No newline at end of file diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 3c82008..6497495 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 18 + serializedVersion: 20 productGUID: 1daea68326fda5145a72e259ef9c4c36 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -52,7 +52,6 @@ PlayerSettings: m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - displayResolutionDialog: 0 iosUseCustomAppBackgroundBehavior: 0 iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 @@ -85,7 +84,6 @@ PlayerSettings: useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 - graphicsJobs: 0 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -93,7 +91,6 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 - graphicsJobMode: 0 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 @@ -113,6 +110,7 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 m_SupportedAspectRatios: 4:3: 1 @@ -152,11 +150,13 @@ PlayerSettings: sharedDepthBuffer: 1 dashSupport: 1 lowOverheadMode: 0 + protectedContext: 0 + v2Signing: 1 enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 - protectGraphicsMemory: 0 enableFrameTimingStats: 0 useHDRDisplay: 0 + D3DHDRBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 @@ -165,7 +165,7 @@ PlayerSettings: applicationIdentifier: {} buildNumber: {} AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 16 + AndroidMinSdkVersion: 19 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -180,10 +180,10 @@ PlayerSettings: StripUnusedMeshComponents: 1 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 9.0 + iOSTargetOSVersionString: 10.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 9.0 + tvOSTargetOSVersionString: 10.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -273,7 +273,6 @@ PlayerSettings: androidGamepadSupportLevel: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 - resolutionDialogBanner: {fileID: 0} m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] m_BuildTargetBatching: @@ -292,6 +291,38 @@ PlayerSettings: - m_BuildTarget: WebGL m_StaticBatching: 0 m_DynamicBatching: 0 + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: - m_BuildTarget: AndroidPlayer m_APIs: 150000000b000000 @@ -314,7 +345,6 @@ PlayerSettings: openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 - vuforiaEnabled: 0 m_TemplateCustomTags: {} mobileMTRendering: Android: 1 @@ -430,6 +460,7 @@ PlayerSettings: switchRatingsInt_9: 0 switchRatingsInt_10: 0 switchRatingsInt_11: 0 + switchRatingsInt_12: 0 switchLocalCommunicationIds_0: switchLocalCommunicationIds_1: switchLocalCommunicationIds_2: @@ -529,6 +560,7 @@ PlayerSettings: ps4contentSearchFeaturesUsed: 0 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} @@ -613,7 +645,6 @@ PlayerSettings: XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - xboxOneScriptCompiler: 1 XboxOneOverrideIdentityName: vrEditorSettings: daydream: @@ -632,13 +663,6 @@ PlayerSettings: luminVersion: m_VersionCode: 1 m_VersionName: - facebookSdkVersion: 7.9.4 - facebookAppId: - facebookCookies: 1 - facebookLogging: 1 - facebookStatus: 1 - facebookXfbml: 0 - facebookFrictionlessRequests: 1 apiCompatibilityLevel: 6 cloudProjectId: framebufferDepthMemorylessMode: 0 From 13a962117a39b48aaaee5c099d7edffc8573cc36 Mon Sep 17 00:00:00 2001 From: rubic Date: Thu, 5 Mar 2020 19:13:29 -0800 Subject: [PATCH 3/7] began tying together systems and testing contactable --- Assets/Prefabs/Match.prefab | 20 +-- Assets/Prefabs/Nail.prefab | 20 +-- Assets/Prefabs/Needle.prefab | 37 ++++-- Assets/Prefabs/Player.prefab | 17 +++ Assets/Prefabs/Pushpin.prefab | 45 +++++-- Assets/Scenes/Template.unity | 121 ++++++++++++++++-- Assets/Scripts/Interactables/Pushpin.cs | 10 +- Assets/Scripts/Interactables/Yarn.cs | 8 +- Assets/Scripts/YarnContacting/Contactable.cs | 92 ++++--------- .../YarnContacting/InteractContactable.cs | 14 ++ .../InteractContactable.cs.meta | 11 ++ .../Scripts/YarnContacting/WrapContactable.cs | 98 ++++++++++++++ .../YarnContacting/WrapContactable.cs.meta | 11 ++ Assets/Scripts/YarnContacting/YarnLine.cs | 17 ++- 14 files changed, 401 insertions(+), 120 deletions(-) create mode 100644 Assets/Scripts/YarnContacting/InteractContactable.cs create mode 100644 Assets/Scripts/YarnContacting/InteractContactable.cs.meta create mode 100644 Assets/Scripts/YarnContacting/WrapContactable.cs create mode 100644 Assets/Scripts/YarnContacting/WrapContactable.cs.meta diff --git a/Assets/Prefabs/Match.prefab b/Assets/Prefabs/Match.prefab index c0ef0b8..292984e 100644 --- a/Assets/Prefabs/Match.prefab +++ b/Assets/Prefabs/Match.prefab @@ -24,7 +24,7 @@ GameObject: m_Component: - component: {fileID: 8523065194936625137} - component: {fileID: 8523065194936625138} - - component: {fileID: 8839065093546782790} + - component: {fileID: 5940000930525792920} m_Layer: 0 m_Name: Match m_TagString: Untagged @@ -59,7 +59,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: cd85f814f92a48f7bf516ac06983ab78, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &8839065093546782790 +--- !u!114 &5940000930525792920 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -68,9 +68,13 @@ MonoBehaviour: m_GameObject: {fileID: 8523065194936625136} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a115767594c2aa643b4a85719c052d96, type: 3} + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} m_Name: m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 --- !u!1001 &8523065195629964848 PrefabInstance: m_ObjectHideFlags: 0 @@ -78,11 +82,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 8523065194936625137} m_Modifications: - - target: {fileID: -927199367670048503, guid: abe6dda665f9e2f4bb9fa774c916e053, - type: 3} - propertyPath: m_Name - value: Mesh - objectReference: {fileID: 0} - target: {fileID: -4216859302048453862, guid: abe6dda665f9e2f4bb9fa774c916e053, type: 3} propertyPath: m_LocalPosition.x @@ -158,6 +157,11 @@ PrefabInstance: propertyPath: m_Materials.Array.data[0] value: objectReference: {fileID: 2100000, guid: 87c8d427e891ff14c8a9fc1b5571c399, type: 2} + - target: {fileID: -927199367670048503, guid: abe6dda665f9e2f4bb9fa774c916e053, + type: 3} + propertyPath: m_Name + value: Mesh + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: abe6dda665f9e2f4bb9fa774c916e053, type: 3} --- !u!1 &390106403564140345 stripped diff --git a/Assets/Prefabs/Nail.prefab b/Assets/Prefabs/Nail.prefab index 375e932..0e1965b 100644 --- a/Assets/Prefabs/Nail.prefab +++ b/Assets/Prefabs/Nail.prefab @@ -10,7 +10,7 @@ GameObject: m_Component: - component: {fileID: 1293638319414553333} - component: {fileID: 1293638319414553339} - - component: {fileID: 2956844451186357919} + - component: {fileID: 2226853645861646875} m_Layer: 0 m_Name: Nail m_TagString: Untagged @@ -45,7 +45,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 1e4e97f2fe5cdf848bd6fe3be8acf8dd, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &2956844451186357919 +--- !u!114 &2226853645861646875 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -54,9 +54,13 @@ MonoBehaviour: m_GameObject: {fileID: 1293638319414553334} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a115767594c2aa643b4a85719c052d96, type: 3} + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} m_Name: m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 --- !u!136 &7231737498855535285 CapsuleCollider: m_ObjectHideFlags: 0 @@ -92,11 +96,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 1293638319414553333} m_Modifications: - - target: {fileID: -927199367670048503, guid: e7221bb4299f2d9418bc4bf09d1a609f, - type: 3} - propertyPath: m_Name - value: Mesh - objectReference: {fileID: 0} - target: {fileID: -4216859302048453862, guid: e7221bb4299f2d9418bc4bf09d1a609f, type: 3} propertyPath: m_LocalPosition.x @@ -172,6 +171,11 @@ PrefabInstance: propertyPath: m_Materials.Array.data[0] value: objectReference: {fileID: 2100000, guid: 1fa75e2ebacf4c243999e3f7628e4373, type: 2} + - target: {fileID: -927199367670048503, guid: e7221bb4299f2d9418bc4bf09d1a609f, + type: 3} + propertyPath: m_Name + value: Mesh + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: e7221bb4299f2d9418bc4bf09d1a609f, type: 3} --- !u!1 &7120754119071130942 stripped diff --git a/Assets/Prefabs/Needle.prefab b/Assets/Prefabs/Needle.prefab index 34a88e6..cf9e7f5 100644 --- a/Assets/Prefabs/Needle.prefab +++ b/Assets/Prefabs/Needle.prefab @@ -38,7 +38,8 @@ GameObject: m_Component: - component: {fileID: 8515438956722547815} - component: {fileID: 8515438956722547808} - - component: {fileID: 6464732955907209868} + - component: {fileID: 6561178820540645814} + - component: {fileID: 7689935896013740308} m_Layer: 0 m_Name: Needle m_TagString: Untagged @@ -73,7 +74,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 98e1c197ea674b5a9a129fd58e6579f2, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &6464732955907209868 +--- !u!114 &6561178820540645814 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -82,9 +83,29 @@ MonoBehaviour: m_GameObject: {fileID: 8515438956722547814} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a115767594c2aa643b4a85719c052d96, type: 3} + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} m_Name: m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 +--- !u!114 &7689935896013740308 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8515438956722547814} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + pointOffset: {x: 0, y: 0, z: 0} --- !u!1001 &8515438957613842491 PrefabInstance: m_ObjectHideFlags: 0 @@ -92,11 +113,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 8515438956722547815} m_Modifications: - - target: {fileID: -927199367670048503, guid: 8ed1fafe755612547a4b526e9c6a946d, - type: 3} - propertyPath: m_Name - value: Mesh - objectReference: {fileID: 0} - target: {fileID: -4216859302048453862, guid: 8ed1fafe755612547a4b526e9c6a946d, type: 3} propertyPath: m_LocalPosition.x @@ -162,6 +178,11 @@ PrefabInstance: propertyPath: m_Materials.Array.data[0] value: objectReference: {fileID: 2100000, guid: 1fa75e2ebacf4c243999e3f7628e4373, type: 2} + - target: {fileID: -927199367670048503, guid: 8ed1fafe755612547a4b526e9c6a946d, + type: 3} + propertyPath: m_Name + value: Mesh + objectReference: {fileID: 0} - target: {fileID: 4063835366044962077, guid: 8ed1fafe755612547a4b526e9c6a946d, type: 3} propertyPath: m_Materials.Array.data[0] diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab index 0999ff6..dd95d96 100644 --- a/Assets/Prefabs/Player.prefab +++ b/Assets/Prefabs/Player.prefab @@ -15,6 +15,7 @@ GameObject: - component: {fileID: 8072518499017028997} - component: {fileID: 8072518499017028996} - component: {fileID: 8072518499017028999} + - component: {fileID: 4103203640224951950} m_Layer: 0 m_Name: Player m_TagString: Player @@ -205,6 +206,22 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a79d0552d8ac375449d5c8b767c78682, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!114 &4103203640224951950 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8072518499017028998} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + pointOffset: {x: 0, y: 0, z: 0} --- !u!1 &8072518499020361757 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Pushpin.prefab b/Assets/Prefabs/Pushpin.prefab index 9377194..a6cbb9a 100644 --- a/Assets/Prefabs/Pushpin.prefab +++ b/Assets/Prefabs/Pushpin.prefab @@ -24,7 +24,8 @@ GameObject: m_Component: - component: {fileID: 6461784659212241894} - component: {fileID: 6461784659212241895} - - component: {fileID: 2124173856722540634} + - component: {fileID: 4833415352386671245} + - component: {fileID: 1545922046492766045} m_Layer: 0 m_Name: Pushpin m_TagString: Pushpin @@ -59,7 +60,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 75ae2d8f4608499fbbfc9f480d1f0a73, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &2124173856722540634 +--- !u!114 &4833415352386671245 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -68,9 +69,29 @@ MonoBehaviour: m_GameObject: {fileID: 6461784659212241893} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a115767594c2aa643b4a85719c052d96, type: 3} + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} m_Name: m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 +--- !u!114 &1545922046492766045 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6461784659212241893} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + pointOffset: {x: 0, y: 0, z: 0} --- !u!1001 &6461784659076987962 PrefabInstance: m_ObjectHideFlags: 0 @@ -78,11 +99,11 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 6461784659212241894} m_Modifications: - - target: {fileID: -927199367670048503, guid: e1d1a8f7ba95e0f4f91d68f542216319, + - target: {fileID: -6054058774237248251, guid: e1d1a8f7ba95e0f4f91d68f542216319, type: 3} - propertyPath: m_Name - value: Mesh - objectReference: {fileID: 0} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: fc883cb8b3fd8fa4a9c4b19e725146c3, type: 2} - target: {fileID: -4216859302048453862, guid: e1d1a8f7ba95e0f4f91d68f542216319, type: 3} propertyPath: m_LocalPosition.x @@ -153,16 +174,16 @@ PrefabInstance: propertyPath: m_LocalScale.z value: 0.7 objectReference: {fileID: 0} + - target: {fileID: -927199367670048503, guid: e1d1a8f7ba95e0f4f91d68f542216319, + type: 3} + propertyPath: m_Name + value: Mesh + objectReference: {fileID: 0} - target: {fileID: 4063835366044962077, guid: e1d1a8f7ba95e0f4f91d68f542216319, type: 3} propertyPath: m_Materials.Array.data[0] value: objectReference: {fileID: 2100000, guid: 1fa75e2ebacf4c243999e3f7628e4373, type: 2} - - target: {fileID: -6054058774237248251, guid: e1d1a8f7ba95e0f4f91d68f542216319, - type: 3} - propertyPath: m_Materials.Array.data[0] - value: - objectReference: {fileID: 2100000, guid: fc883cb8b3fd8fa4a9c4b19e725146c3, type: 2} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: e1d1a8f7ba95e0f4f91d68f542216319, type: 3} --- !u!1 &3066164092647859507 stripped diff --git a/Assets/Scenes/Template.unity b/Assets/Scenes/Template.unity index bcd9b90..3d52f6f 100644 --- a/Assets/Scenes/Template.unity +++ b/Assets/Scenes/Template.unity @@ -1004,7 +1004,7 @@ PrefabInstance: - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} propertyPath: m_RootOrder - value: 8 + value: 9 objectReference: {fileID: 0} - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} @@ -1415,7 +1415,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 5 + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 50, y: 0, z: 0} --- !u!114 &963194229 MonoBehaviour: @@ -1804,7 +1804,7 @@ PrefabInstance: - target: {fileID: 1239185254202489153, guid: c9803ecc16e1ec742b5a2d6280a67d35, type: 3} propertyPath: m_RootOrder - value: 10 + value: 11 objectReference: {fileID: 0} - target: {fileID: 1239185254202489153, guid: c9803ecc16e1ec742b5a2d6280a67d35, type: 3} @@ -1890,8 +1890,31 @@ PrefabInstance: propertyPath: m_Name value: Nail objectReference: {fileID: 0} - m_RemovedComponents: [] + m_RemovedComponents: + - {fileID: 2956844451186357919, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} +--- !u!1 &1293638319837771300 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 1293638319414553334, guid: 3f7ba35961265c14d95fd3df6e0e7e17, + type: 3} + m_PrefabInstance: {fileID: 1293638319837771299} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1293638319837771301 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1293638319837771300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 --- !u!1001 &1583258829877207816 PrefabInstance: m_ObjectHideFlags: 0 @@ -1942,7 +1965,7 @@ PrefabInstance: - target: {fileID: 1583258828818565569, guid: eedf6123f261655408fea12ace3e43f3, type: 3} propertyPath: m_RootOrder - value: 11 + value: 12 objectReference: {fileID: 0} - target: {fileID: 1583258828818565569, guid: eedf6123f261655408fea12ace3e43f3, type: 3} @@ -2011,7 +2034,7 @@ PrefabInstance: - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} propertyPath: m_RootOrder - value: 7 + value: 8 objectReference: {fileID: 0} - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} @@ -2028,8 +2051,47 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - m_RemovedComponents: [] + m_RemovedComponents: + - {fileID: 2124173856722540634, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} m_SourcePrefab: {fileID: 100100000, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} +--- !u!1 &6461784657988510637 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 6461784659212241893, guid: fff8d0044295e4f4db1036bcd8e4918d, + type: 3} + m_PrefabInstance: {fileID: 6461784657988510636} + m_PrefabAsset: {fileID: 0} +--- !u!114 &6461784657988510638 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6461784657988510637} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + pointOffset: {x: 0, y: 0, z: 0} +--- !u!114 &6461784657988510639 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6461784657988510637} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 --- !u!1001 &8515438955564073220 PrefabInstance: m_ObjectHideFlags: 0 @@ -2080,7 +2142,7 @@ PrefabInstance: - target: {fileID: 8515438956722547815, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} propertyPath: m_RootOrder - value: 6 + value: 7 objectReference: {fileID: 0} - target: {fileID: 8515438956722547815, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} @@ -2097,8 +2159,47 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - m_RemovedComponents: [] + m_RemovedComponents: + - {fileID: 6464732955907209868, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} +--- !u!1 &8515438955564073221 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8515438956722547814, guid: 4c3258452a716e34ca0be2fbf848b5e8, + type: 3} + m_PrefabInstance: {fileID: 8515438955564073220} + m_PrefabAsset: {fileID: 0} +--- !u!114 &8515438955564073222 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8515438955564073221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + pointOffset: {x: 0, y: 0, z: 0} +--- !u!114 &8515438955564073223 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8515438955564073221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} + m_Name: + m_EditorClassIdentifier: + pastPosition: {x: 0, y: 0, z: 0} + currentPosition: {x: 0, y: 0, z: 0} + wrapContactables: [] + radius: 0.1 --- !u!1001 &8523065194267575884 PrefabInstance: m_ObjectHideFlags: 0 @@ -2149,7 +2250,7 @@ PrefabInstance: - target: {fileID: 8523065194936625137, guid: 1b3a16bdb00e85445b4b342236544567, type: 3} propertyPath: m_RootOrder - value: 9 + value: 10 objectReference: {fileID: 0} - target: {fileID: 8523065194936625137, guid: 1b3a16bdb00e85445b4b342236544567, type: 3} diff --git a/Assets/Scripts/Interactables/Pushpin.cs b/Assets/Scripts/Interactables/Pushpin.cs index b679e1a..8ab2e9a 100644 --- a/Assets/Scripts/Interactables/Pushpin.cs +++ b/Assets/Scripts/Interactables/Pushpin.cs @@ -19,6 +19,8 @@ protected override void Awake() { public override void Interact() { YarnUpdate(); + + print($"{GetType()} was interacted with, but nothing has been implemented yet."); } /** @@ -28,13 +30,13 @@ public override void Interact() { private void YarnUpdate() { Yarn playerYarn = playerManager.YarnHeld; - switch (state) { + /*switch (state) { /* * Yarn can be attached to this Pushpin if: * - This Pushpin is Untied to anything * - The player is holding onto yarn, in which case the player wants to start a line of yarn * - The player is pulling yarn, in which case the player wants to finish a line of yarn - */ + #1# case State.Untied when playerManager.CheckState(PlayerManager.State.Holding): // start a line of yarn state = State.Tied; @@ -58,7 +60,7 @@ private void YarnUpdate() { * - This Pushpin must be part of this line of yarn AND be the only thing other than the player * - The player is normal, in which case they want to change an existing line of yarn * - This Pushpin must be either the first or last in the line of yarn AND there are at least two contacts - */ + #1# case State.Tied: case State.Done: { if (playerManager.CheckState(PlayerManager.State.Pulling) @@ -82,6 +84,6 @@ private void YarnUpdate() { } break; } - } + }*/ } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index 3bdae3e..4a2f445 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -25,9 +25,15 @@ protected override void Awake() { levelManager = FindObjectOfType(); } + private void FixedUpdate() { + // update the physics of the yarn line + //yarnLine?.FixedUpdate(); + // todo: allow yarn to update + } + private void Update() { // update the visuals of the yarn line - yarnLine?.Update(); + //yarnLine?.Update(); // update the points the LineRenderer is rendering if (lineRenderer && yarnLine != null) { diff --git a/Assets/Scripts/YarnContacting/Contactable.cs b/Assets/Scripts/YarnContacting/Contactable.cs index 3db6db1..cd2ab06 100644 --- a/Assets/Scripts/YarnContacting/Contactable.cs +++ b/Assets/Scripts/YarnContacting/Contactable.cs @@ -14,88 +14,44 @@ * need if this GameObject became a Contact. */ public abstract class Contactable : MonoBehaviour { - public Vector3 pastPosition; - public Vector3 currentPosition; + [HideInInspector] public Vector3 pastPosition; + [HideInInspector] public Vector3 currentPosition; - private void Awake() { + [HideInInspector] public List wrapContactables; + + protected virtual void Awake() { var position = transform.position; pastPosition = position; currentPosition = position; + + wrapContactables = FindObjectsOfType().ToList(); } - protected virtual void FixedUpdate() { + public void UpdatePosition() { // update past and current positions pastPosition = currentPosition; currentPosition = transform.position; } -} - -/** - * If a Yarn object wrapping around this Contactable should send a Contact to that Yarn, - * put this Behaviour on that GameObject. - */ -public class WrapContactable : Contactable { - // this is the radius of a circle on the XZ plane that the yarn line can hit to contact this object. - [Tooltip("Specifies the radius of the infinitely tall cylinder that represents the WrapContactable.")] - public float radius = 0.1f; - - protected override void FixedUpdate() { - base.FixedUpdate(); - // todo: do whatever needs to be done with past and current positions - } - - public CircleContact GetNewContact(Vector3 initialPoint, float initialAngle, Contact prevContact, Contact nextContact = null) { - return new CircleContact(this, initialPoint, initialAngle, prevContact, nextContact); - } /** - * Returns true if, from the host to the wrapper's position, the wrapper has wrapped around the wrappee. + * Return new Contacts for every wrap around a Contactable that is being made from this Contact to the other Contact. */ - public static bool CheckWrapAround(Contactable host, WrapContactable wrappee, Contactable wrapper) { - var hostPosition = host.transform.position; + public List CheckOverlaps(Contact other) { + // create an edited watch list + var watchedContactablesEdit = new List(wrapContactables); + // if the other Contactable is a WrapContactable, remove it + if(other.host.GetType() == typeof(WrapContactable)) + watchedContactablesEdit.Remove((WrapContactable)other.host); - Vector3 vecToObj = wrappee.transform.position - hostPosition; - Vector3 oldVecToWrapper = wrapper.pastPosition - hostPosition; - Vector3 newVecToWrapper = wrapper.transform.position - hostPosition; + List newContacts = new List(); - float oldAngle = Vector3.SignedAngle(vecToObj, oldVecToWrapper, Vector3.up); - float newAngle = Vector3.SignedAngle(vecToObj, newVecToWrapper, Vector3.up); - // if the angle from the wrapper to the object has flipped (one is positive, one is negative) - // and if either the old or the new vector to the wrapper is longer than the vector to the object - // then the wrapper has successfully wrapped around - return (oldAngle * newAngle < 0) && - (oldVecToWrapper.magnitude > vecToObj.magnitude || newVecToWrapper.magnitude > vecToObj.magnitude); - } - - /** - * This method returns both points on a circle on the XZ axis that is tangent from the base of vecToCircleCenter. - * - * Starting from the base of vecToCircleCenter, two lines can always be drawn tangent to a circle centered at the - * end of vecToCircleCenter with a radius of radius. Both of these points are returned in a Vector3[], with - * element 0 being the vector counter-clockwise (negative angle) from vecToCircleCenter and element 1 being - * the other. - */ - private static Vector3[] FindTangentPointsToCircle(Vector3 vecToCircleCenter, float radius) { - // this is the angle between vecToCircleCenter to both tangents - float angleToTangents = Mathf.Asin(radius / vecToCircleCenter.magnitude); - Vector3 negativeTangent = Quaternion.Euler(0, angleToTangents, 0) * vecToCircleCenter; - Vector3 positiveTangent = Quaternion.Euler(0, -angleToTangents, 0) * vecToCircleCenter; - return new [] { - Vector3.Project(vecToCircleCenter, negativeTangent), - Vector3.Project(vecToCircleCenter, positiveTangent) - }; - } -} - -/** - * If the player interacting with this Contactable should send a Contact to the player, - * put this Behaviour on that GameObject. - */ -public class InteractContactable : Contactable { - [Tooltip("This is the offset from the GameObject's position where yarn will be attached.")] - public Vector3 pointOffset; - - public PointContact GetNewContact() { - return new PointContact(this); + // loop through each WrapContactable and consider whether not a line has crossed it + foreach (var watchedContactable in wrapContactables) { + /*if (WrapContactable.CheckWrapAround(, watchedContactable, other)) { + + }*/ + } + + return newContacts; } } \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/InteractContactable.cs b/Assets/Scripts/YarnContacting/InteractContactable.cs new file mode 100644 index 0000000..09a7928 --- /dev/null +++ b/Assets/Scripts/YarnContacting/InteractContactable.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +/** + * If the player interacting with this Contactable should send a Contact to the player, + * put this Behaviour on that GameObject. + */ +public class InteractContactable : Contactable { + [Tooltip("This is the offset from the GameObject's position where yarn will be attached.")] + public Vector3 pointOffset; + + public PointContact GetNewContact() { + return new PointContact(this); + } +} diff --git a/Assets/Scripts/YarnContacting/InteractContactable.cs.meta b/Assets/Scripts/YarnContacting/InteractContactable.cs.meta new file mode 100644 index 0000000..708999f --- /dev/null +++ b/Assets/Scripts/YarnContacting/InteractContactable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb3afdf96468fd04b95c0148819ca2d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/YarnContacting/WrapContactable.cs b/Assets/Scripts/YarnContacting/WrapContactable.cs new file mode 100644 index 0000000..0eef552 --- /dev/null +++ b/Assets/Scripts/YarnContacting/WrapContactable.cs @@ -0,0 +1,98 @@ +using UnityEngine; + +/** + * If a Yarn object wrapping around this Contactable should send a Contact to that Yarn, + * put this Behaviour on that GameObject. + */ + +public class WrapContactable : Contactable { + // this is the radius of a circle on the XZ plane that the yarn line can hit to contact this object. + [Tooltip("Specifies the radius of the infinitely tall cylinder that represents the WrapContactable.")] + public float radius = 0.1f; + + protected override void Awake() { + base.Awake(); + // if we're a WrapContactable, we better remove ourselves from our own list of wrap contactables + wrapContactables.Remove(this); + } + + public CircleContact GetNewContact(Vector3 initialPoint, float initialAngle, Contact prevContact, Contact nextContact = null) { + return new CircleContact(this, initialPoint, initialAngle, prevContact, nextContact); + } + + /** + * Determines if, from one Contact to the other's position, a wrap has been made around a wrappee. + * The WrapResult will specify whether a wrap has occurred or not. + */ + public static WrapResult CheckWrapAround(Contact from, WrapContactable wrappee, Contact to) { + // this is the point that all vectors under consideration are based from + var hostPosition = from.tailRenderPoint; + + var positionDelta = to.host.currentPosition - to.host.pastPosition; + + // these are the vectors from the host position to the other contact, before and after. + Vector3 oldVecToWrapper = to.headRenderPoint - hostPosition; + Vector3 newVecToWrapper = to.headRenderPoint - hostPosition; + + // get both lines from the host that are tangent to the wrappee + Vector3[] wrappeeLines = FindTangentPointsToCircle(wrappee.transform.position - hostPosition, wrappee.radius); + var wrappeeLine = wrappeeLines[1]; + + // pick one based on the direction of the old vec to the new vec + // if the signed angle is position, rotation is clockwise, pick the clockwise-most wrappee line + if (Vector3.SignedAngle(oldVecToWrapper, newVecToWrapper, Vector3.up) >= 0) { + wrappeeLine = wrappeeLines[0]; + } + + + + return new WrapResult(); + } + + public struct WrapResult { + public bool wrapOccurred; + public WrapContactable wrappee; + public Vector3 wrapPosition; + public float initialAngle; + + public WrapResult(bool wrapOccurred, WrapContactable wrappee, Vector3 wrapPosition, float initialAngle) { + this.wrapOccurred = wrapOccurred; + this.wrappee = wrappee; + this.wrapPosition = wrapPosition; + this.initialAngle = initialAngle; + } + } + + /** + * Returns true if, from oldVec to newVec, it has wrapped around baseVec on the XZ plane. + */ + public static bool VectorHasWrappedVector(Vector3 baseVec, Vector3 oldVec, Vector3 newVec) { + float oldAngle = Vector3.SignedAngle(baseVec, oldVec, Vector3.up); + float newAngle = Vector3.SignedAngle(baseVec, newVec, Vector3.up); + + // if the angle between baseVec to the other vector has flipped (one is positive, one is negative) + // and if either the old or the new vector is longer than baseVec + // then one vector has wrapped another + return (oldAngle * newAngle < 0) && + (oldVec.magnitude > baseVec.magnitude || newVec.magnitude > baseVec.magnitude); + } + + /** + * This method returns both points on a circle on the XZ axis that is tangent from the base of vecToCircleCenter. + * + * Starting from the base of vecToCircleCenter, two lines can always be drawn tangent to a circle centered at the + * end of vecToCircleCenter with a radius of radius. Both of these points are returned in a Vector3[], with + * element 0 being the vector counter-clockwise (negative angle) from vecToCircleCenter and element 1 being + * the other. + */ + private static Vector3[] FindTangentPointsToCircle(Vector3 vecToCircleCenter, float radius) { + // this is the angle between vecToCircleCenter to both tangents + float angleToTangents = Mathf.Asin(radius / vecToCircleCenter.magnitude); + Vector3 negativeTangent = Quaternion.Euler(0, angleToTangents, 0) * vecToCircleCenter; + Vector3 positiveTangent = Quaternion.Euler(0, -angleToTangents, 0) * vecToCircleCenter; + return new [] { + Vector3.Project(vecToCircleCenter, negativeTangent), + Vector3.Project(vecToCircleCenter, positiveTangent) + }; + } +} \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/WrapContactable.cs.meta b/Assets/Scripts/YarnContacting/WrapContactable.cs.meta new file mode 100644 index 0000000..c57426a --- /dev/null +++ b/Assets/Scripts/YarnContacting/WrapContactable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29aab9a7c4fc6a04e854dffd2cf68812 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs b/Assets/Scripts/YarnContacting/YarnLine.cs index 50b2e53..bdba0ec 100644 --- a/Assets/Scripts/YarnContacting/YarnLine.cs +++ b/Assets/Scripts/YarnContacting/YarnLine.cs @@ -25,6 +25,21 @@ public YarnLine(Yarn host, PointContact player, PointContact pushpin) { wraps = new List(); } + /** + * Updates the line of yarn physically, considering new contact points and removing invalid ones + */ + public void FixedUpdate() { + // run through all Contacts: + // if a Contact's Contactable sees an overlap with other Contactables, add them + // if a Contact has become invalid, remove it + for (var i = 0; i < contacts.Count; i++) { + var contact = contacts[i]; + } + } + + /** + * Updates the line of yarn visually, after physics calculation have been performed + */ public void Update() { } @@ -37,7 +52,7 @@ public void OnLineChanged() { newContacts.Add(head); contacts = newContacts; - // update the renderpoints based on changes contacts + // update the renderpoints based on changed contacts } From ed8c12ca41f2eb06ef5de06f0e8fe2919a7294bb Mon Sep 17 00:00:00 2001 From: rubic Date: Fri, 6 Mar 2020 01:17:58 -0800 Subject: [PATCH 4/7] working on making the pushpin functional again --- Assets/Prefabs/Player.prefab | 36 +++--- Assets/Scenes/Template.unity | 107 +----------------- Assets/Scripts/GameManager.cs | 12 +- Assets/Scripts/Interactables/Air.cs | 2 +- Assets/Scripts/Interactables/Door.cs | 2 +- Assets/Scripts/Interactables/Interactable.cs | 10 +- Assets/Scripts/Interactables/Match.cs | 2 +- Assets/Scripts/Interactables/Nail.cs | 2 +- Assets/Scripts/Interactables/Needle.cs | 2 +- Assets/Scripts/Interactables/Pushpin.cs | 76 ++++++------- Assets/Scripts/Interactables/Yarn.cs | 34 ++++-- .../Scripts/PlayerBehavior/PlayerInteract.cs | 12 +- .../Scripts/PlayerBehavior/PlayerManager.cs | 21 ++-- Assets/Scripts/YarnContacting/Contactable.cs | 1 - .../YarnContacting/PlayerContactable.cs | 11 ++ .../YarnContacting/PlayerContactable.cs.meta | 11 ++ .../Scripts/YarnContacting/WrapContactable.cs | 11 +- Assets/Scripts/YarnContacting/YarnLine.cs | 24 ++-- 18 files changed, 153 insertions(+), 223 deletions(-) create mode 100644 Assets/Scripts/YarnContacting/PlayerContactable.cs create mode 100644 Assets/Scripts/YarnContacting/PlayerContactable.cs.meta diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab index dd95d96..22f9f69 100644 --- a/Assets/Prefabs/Player.prefab +++ b/Assets/Prefabs/Player.prefab @@ -9,13 +9,13 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 8072518499017028993} - - component: {fileID: 8072518499017028992} - component: {fileID: 8072518499017028995} - component: {fileID: 8072518499017028994} + - component: {fileID: 8072518499017028992} - component: {fileID: 8072518499017028997} - component: {fileID: 8072518499017028996} - component: {fileID: 8072518499017028999} - - component: {fileID: 4103203640224951950} + - component: {fileID: 2313245474546743258} m_Layer: 0 m_Name: Player m_TagString: Player @@ -38,20 +38,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &8072518499017028992 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8072518499017028998} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0daccf5fb693e6b4b817a62deb9df3db, type: 3} - m_Name: - m_EditorClassIdentifier: - normalMesh: {fileID: 227068772183194632} - holdingMesh: {fileID: 227068771119847383} --- !u!54 &8072518499017028995 Rigidbody: m_ObjectHideFlags: 0 @@ -82,6 +68,20 @@ CapsuleCollider: m_Height: 2 m_Direction: 1 m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &8072518499017028992 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8072518499017028998} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0daccf5fb693e6b4b817a62deb9df3db, type: 3} + m_Name: + m_EditorClassIdentifier: + normalMesh: {fileID: 227068772183194632} + holdingMesh: {fileID: 227068771119847383} --- !u!114 &8072518499017028997 MonoBehaviour: m_ObjectHideFlags: 0 @@ -206,7 +206,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a79d0552d8ac375449d5c8b767c78682, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &4103203640224951950 +--- !u!114 &2313245474546743258 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -215,7 +215,7 @@ MonoBehaviour: m_GameObject: {fileID: 8072518499017028998} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} + m_Script: {fileID: 11500000, guid: ab040f71654faec4c811af8fee2ae1c4, type: 3} m_Name: m_EditorClassIdentifier: pastPosition: {x: 0, y: 0, z: 0} diff --git a/Assets/Scenes/Template.unity b/Assets/Scenes/Template.unity index 3d52f6f..27c1af2 100644 --- a/Assets/Scenes/Template.unity +++ b/Assets/Scenes/Template.unity @@ -1890,31 +1890,8 @@ PrefabInstance: propertyPath: m_Name value: Nail objectReference: {fileID: 0} - m_RemovedComponents: - - {fileID: 2956844451186357919, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} + m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} ---- !u!1 &1293638319837771300 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 1293638319414553334, guid: 3f7ba35961265c14d95fd3df6e0e7e17, - type: 3} - m_PrefabInstance: {fileID: 1293638319837771299} - m_PrefabAsset: {fileID: 0} ---- !u!114 &1293638319837771301 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1293638319837771300} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} - m_Name: - m_EditorClassIdentifier: - pastPosition: {x: 0, y: 0, z: 0} - currentPosition: {x: 0, y: 0, z: 0} - wrapContactables: [] - radius: 0.1 --- !u!1001 &1583258829877207816 PrefabInstance: m_ObjectHideFlags: 0 @@ -2051,47 +2028,8 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - m_RemovedComponents: - - {fileID: 2124173856722540634, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} + m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} ---- !u!1 &6461784657988510637 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 6461784659212241893, guid: fff8d0044295e4f4db1036bcd8e4918d, - type: 3} - m_PrefabInstance: {fileID: 6461784657988510636} - m_PrefabAsset: {fileID: 0} ---- !u!114 &6461784657988510638 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6461784657988510637} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} - m_Name: - m_EditorClassIdentifier: - pastPosition: {x: 0, y: 0, z: 0} - currentPosition: {x: 0, y: 0, z: 0} - wrapContactables: [] - pointOffset: {x: 0, y: 0, z: 0} ---- !u!114 &6461784657988510639 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6461784657988510637} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} - m_Name: - m_EditorClassIdentifier: - pastPosition: {x: 0, y: 0, z: 0} - currentPosition: {x: 0, y: 0, z: 0} - wrapContactables: [] - radius: 0.1 --- !u!1001 &8515438955564073220 PrefabInstance: m_ObjectHideFlags: 0 @@ -2159,47 +2097,8 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - m_RemovedComponents: - - {fileID: 6464732955907209868, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} + m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} ---- !u!1 &8515438955564073221 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 8515438956722547814, guid: 4c3258452a716e34ca0be2fbf848b5e8, - type: 3} - m_PrefabInstance: {fileID: 8515438955564073220} - m_PrefabAsset: {fileID: 0} ---- !u!114 &8515438955564073222 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8515438955564073221} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cb3afdf96468fd04b95c0148819ca2d6, type: 3} - m_Name: - m_EditorClassIdentifier: - pastPosition: {x: 0, y: 0, z: 0} - currentPosition: {x: 0, y: 0, z: 0} - wrapContactables: [] - pointOffset: {x: 0, y: 0, z: 0} ---- !u!114 &8515438955564073223 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8515438955564073221} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 29aab9a7c4fc6a04e854dffd2cf68812, type: 3} - m_Name: - m_EditorClassIdentifier: - pastPosition: {x: 0, y: 0, z: 0} - currentPosition: {x: 0, y: 0, z: 0} - wrapContactables: [] - radius: 0.1 --- !u!1001 &8523065194267575884 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs index c6cb185..d41ed98 100644 --- a/Assets/Scripts/GameManager.cs +++ b/Assets/Scripts/GameManager.cs @@ -29,15 +29,15 @@ private void Awake() DontDestroyOnLoad(gameObject); playerInput = new PlayerInput(); - } - - private void OnEnable() { playerInput.Player.Restart.started += OnRestart; playerInput.Player.Enable(); } - - private void OnDisable() { - playerInput?.Player.Disable(); + + private void OnDestroy() { + if (playerInput != null) { + playerInput.Player.Restart.started -= OnRestart; + playerInput.Player.Disable(); + } } /** diff --git a/Assets/Scripts/Interactables/Air.cs b/Assets/Scripts/Interactables/Air.cs index 275e287..6e87642 100644 --- a/Assets/Scripts/Interactables/Air.cs +++ b/Assets/Scripts/Interactables/Air.cs @@ -1,5 +1,5 @@ public class Air : Interactable { - public override void Interact() { + public override void Interact(PlayerManager player) { print("Air was interacted with and nothing happened."); } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Door.cs b/Assets/Scripts/Interactables/Door.cs index 5b0564d..571fe0c 100644 --- a/Assets/Scripts/Interactables/Door.cs +++ b/Assets/Scripts/Interactables/Door.cs @@ -2,7 +2,7 @@ public class Door : Interactable { public string goToLevel; - public override void Interact() { + public override void Interact(PlayerManager player) { SceneManager.LoadScene(goToLevel); } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Interactable.cs b/Assets/Scripts/Interactables/Interactable.cs index e113651..dc292df 100644 --- a/Assets/Scripts/Interactables/Interactable.cs +++ b/Assets/Scripts/Interactables/Interactable.cs @@ -16,10 +16,6 @@ public abstract class Interactable : MonoBehaviour { private BoxCollider boxCollider; protected virtual void Awake() { - player = GameObject.FindGameObjectWithTag("Player"); - playerManager = player.GetComponent(); - playerInteract = player.GetComponent(); - // place a trigger region on this Interactable boxCollider = gameObject.AddComponent(); boxCollider.isTrigger = true; @@ -31,7 +27,11 @@ protected virtual void Awake() { * Performs an interaction with this Interactable. * Should be customized per type of Interactable. */ - public abstract void Interact(); + public virtual void Interact(PlayerManager player) { + this.player = player.gameObject; + this.playerManager = player; + this.playerInteract = this.player.GetComponent(); + } private void OnTriggerEnter(Collider other) { if (other.CompareTag("Player")) { diff --git a/Assets/Scripts/Interactables/Match.cs b/Assets/Scripts/Interactables/Match.cs index 4ed9d67..52c3dd1 100644 --- a/Assets/Scripts/Interactables/Match.cs +++ b/Assets/Scripts/Interactables/Match.cs @@ -1,5 +1,5 @@ public class Match : Interactable { - public override void Interact() { + public override void Interact(PlayerManager player) { print("A Match was interacted with and nothing happened."); } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Nail.cs b/Assets/Scripts/Interactables/Nail.cs index 9c63095..372cc9c 100644 --- a/Assets/Scripts/Interactables/Nail.cs +++ b/Assets/Scripts/Interactables/Nail.cs @@ -15,7 +15,7 @@ protected override void Awake() { meshLowerable = GetComponentInChildren(); } - public override void Interact() { + public override void Interact(PlayerManager player) { ToggleState(); } diff --git a/Assets/Scripts/Interactables/Needle.cs b/Assets/Scripts/Interactables/Needle.cs index e6ad924..58e9667 100644 --- a/Assets/Scripts/Interactables/Needle.cs +++ b/Assets/Scripts/Interactables/Needle.cs @@ -12,7 +12,7 @@ protected override void Awake() { meshLowerable = GetComponentInChildren(); } - public override void Interact() { + public override void Interact(PlayerManager player) { ToggleState(); } diff --git a/Assets/Scripts/Interactables/Pushpin.cs b/Assets/Scripts/Interactables/Pushpin.cs index 8ab2e9a..6ea2f46 100644 --- a/Assets/Scripts/Interactables/Pushpin.cs +++ b/Assets/Scripts/Interactables/Pushpin.cs @@ -1,4 +1,9 @@ public class Pushpin : Interactable { + + private Yarn connectedYarn; + + public InteractContactable interactContactable { get; protected set; } + public enum State { Untied, Tied, @@ -7,83 +12,66 @@ public enum State { private State state; public bool IsDone() { return state == State.Done; } - - // the yarn that is connected to this pushpin. can only be one - private Yarn connectedYarn; - protected override void Awake() { base.Awake(); state = State.Untied; connectedYarn = null; + interactContactable = GetComponent(); } - public override void Interact() { - YarnUpdate(); - - print($"{GetType()} was interacted with, but nothing has been implemented yet."); - } - - /** - * A Pushpin will attempt to update the player and any yarn they're holding - * based on the states of those objects. - */ - private void YarnUpdate() { - Yarn playerYarn = playerManager.YarnHeld; + public override void Interact(PlayerManager player) { + base.Interact(player); + connectedYarn = player.yarnHeld; - /*switch (state) { + switch (state) { /* * Yarn can be attached to this Pushpin if: * - This Pushpin is Untied to anything * - The player is holding onto yarn, in which case the player wants to start a line of yarn * - The player is pulling yarn, in which case the player wants to finish a line of yarn - #1# - case State.Untied when playerManager.CheckState(PlayerManager.State.Holding): - // start a line of yarn - state = State.Tied; - playerManager.SetState(PlayerManager.State.Pulling); - connectedYarn = playerYarn; - //connectedYarn.AddContact(gameObject); - print("Yarn was just tied to a Pushpin, starting a line."); - break; - case State.Untied when playerManager.CheckState(PlayerManager.State.Pulling): { - // finish a line of yarn - state = State.Tied; - connectedYarn = playerYarn; - connectedYarn.TieTo(this); - print("Yarn was just tied to a Pushpin, ending a line."); + */ + case State.Untied: { + if (playerManager.CheckState(PlayerManager.State.Holding)) { + state = State.Tied; + playerManager.SetState(PlayerManager.State.Pulling); + connectedYarn.TieStart(this); + print("Yarn was just tied to a Pushpin, starting a line."); + + } else if (playerManager.CheckState(PlayerManager.State.Pulling)) { + state = State.Tied; + playerManager.SetState(PlayerManager.State.Normal); + connectedYarn.TieEnd(this); + print("Yarn was just tied to a Pushpin, ending a line."); + } break; } /* * Yarn can be detached from this Pushpin if: * - This Pushpin is Tied OR Done already - * - The player is pulling yarn, which case they want to return to just holding yarn + * - The player is pulling yarn, in which case they want to return to just holding yarn * - This Pushpin must be part of this line of yarn AND be the only thing other than the player * - The player is normal, in which case they want to change an existing line of yarn - * - This Pushpin must be either the first or last in the line of yarn AND there are at least two contacts - #1# + * - This Pushpin must be either the first or last in the line of yarn + */ case State.Tied: case State.Done: { if (playerManager.CheckState(PlayerManager.State.Pulling) - && connectedYarn.ContactCount() == 2 - && connectedYarn == playerYarn) { + && connectedYarn.yarnLine != null) { // return to holding yarn state = State.Untied; playerManager.SetState(PlayerManager.State.Holding); - connectedYarn.RemoveContactAll(gameObject); - connectedYarn = null; + connectedYarn.UntieEnd(this); print("Yarn was just untied from a Pushpin, undoing a line."); } else if (playerManager.CheckState(PlayerManager.State.Normal) - && connectedYarn.ContactCount() >= 2 - && connectedYarn.IsContactAtEnd(gameObject)) { + && connectedYarn.yarnLine != null) { // start changing a line of yarn again state = State.Untied; - connectedYarn.UntieFrom(this); - connectedYarn = null; + connectedYarn.UntieStart(this); print("Yarn was just untied from a Pushpin, to edit a line."); } break; } - }*/ + } } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index 4a2f445..7b03c8e 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -8,7 +8,7 @@ public class Yarn : Interactable { public GameObject mesh; private LevelManager levelManager; - private YarnLine yarnLine; + [HideInInspector] public YarnLine yarnLine; public enum State { Normal, @@ -28,7 +28,7 @@ protected override void Awake() { private void FixedUpdate() { // update the physics of the yarn line //yarnLine?.FixedUpdate(); - // todo: allow yarn to update + // todo: allow yarn to update when things are ready } private void Update() { @@ -44,7 +44,7 @@ private void Update() { } } - public override void Interact() { + public override void Interact(PlayerManager player) { // the player picks up the yarn if they have their arms free if (playerManager.CheckState(PlayerManager.State.Normal)) { PickUp(); @@ -58,9 +58,11 @@ public override void Interact() { private void PickUp() { // give the player the yarn object and tell them to start holding playerManager.SetState(PlayerManager.State.Holding); - playerManager.YarnHeld = this; + playerManager.yarnHeld = this; + // this yarn is no longer interactable playerInteract.RemoveInteractable(this); + // parent the yarn to the player and position it in their arms transform.SetParent(player.transform); transform.localPosition = positionYarnInPlayersArms; @@ -71,9 +73,11 @@ private void PickUp() { public void PutDown() { // return the player to normal, take it from the player playerManager.SetState(PlayerManager.State.Normal); - playerManager.YarnHeld = null; + playerManager.yarnHeld = null; + // unparent the yarn, pulling it out to the outermost level transform.parent = null; + // calculate a new position for the yarn on the grid and set it there Vector3 positionOnGround = new Vector3( Mathf.Round(player.transform.localPosition.x/2f)*2f, @@ -84,19 +88,29 @@ public void PutDown() { print("The player has dropped the yarn."); } - /* Ties this Yarn off on the given Pushpin, removing control from the player. */ - public void TieTo(Pushpin pushpin) { + /* Starts a line of yarn on the given pushpin. */ + public void TieStart(Pushpin pushpin) { playerManager.SetState(PlayerManager.State.Normal); if(mesh) HideMesh(); - // todo: switch the pushpin and player + yarnLine = new YarnLine(this, playerManager.playerContactable.GetNewContact(), pushpin.interactContactable.GetNewContact()); + } + + /* Finishes off a line of yarn on the given pushpin. */ + public void TieEnd(Pushpin pushpin) { + } - /* Untie this Yarn object from the given Pushpin, returning control to the player. */ - public void UntieFrom(Pushpin pushpin) { + /* Untie a line of yarn from a pushpin to continue to edit the line. */ + public void UntieStart(Pushpin pushpin) { playerManager.SetState(PlayerManager.State.Pulling); if(mesh) ShowMesh(); // todo: remove the pushpin's contact, add the player } + + /* Untie a line of yarn from a pushpin to remove the line. */ + public void UntieEnd(Pushpin pushpin) { + + } } \ No newline at end of file diff --git a/Assets/Scripts/PlayerBehavior/PlayerInteract.cs b/Assets/Scripts/PlayerBehavior/PlayerInteract.cs index 1dffe07..547a062 100644 --- a/Assets/Scripts/PlayerBehavior/PlayerInteract.cs +++ b/Assets/Scripts/PlayerBehavior/PlayerInteract.cs @@ -14,19 +14,23 @@ private void Awake() { playerInput = new PlayerInput(); playerManager = GetComponent(); - playerInput.Player.Fire.started += OnInteract; SceneManager.sceneLoaded += (scene, mode) => { interactables.Clear(); }; - interactables = new List(); } private void OnEnable() { + playerInput.Player.Fire.started += OnInteract; playerInput.Player.Enable(); } + private void OnDisable() { + playerInput.Player.Fire.started -= OnInteract; + playerInput.Player.Disable(); + } + private void Update() { // player rotates to face cursor on screen var ray = Camera.main.ScreenPointToRay(Input.mousePosition); @@ -44,9 +48,9 @@ private void Update() { private void OnInteract(InputAction.CallbackContext ctx) { if (interactables.Count > 0) { - TopInteractable().Interact(); + TopInteractable().Interact(playerManager); } else if (playerManager.CheckState(PlayerManager.State.Holding)) { - playerManager.YarnHeld.PutDown(); + playerManager.yarnHeld.PutDown(); } } } diff --git a/Assets/Scripts/PlayerBehavior/PlayerManager.cs b/Assets/Scripts/PlayerBehavior/PlayerManager.cs index 9760f88..a5cb095 100644 --- a/Assets/Scripts/PlayerBehavior/PlayerManager.cs +++ b/Assets/Scripts/PlayerBehavior/PlayerManager.cs @@ -1,10 +1,15 @@ using System; -using System.Collections; -using System.Collections.Generic; using UnityEngine; -public class PlayerManager : MonoBehaviour -{ +public class PlayerManager : MonoBehaviour { + + public GameObject normalMesh; + public GameObject holdingMesh; + + public Yarn yarnHeld { get; set; } + + public PlayerContactable playerContactable { get; protected set; } + public enum State { Normal, Holding, @@ -14,13 +19,9 @@ public enum State { private const State DEFAULT_STATE = State.Normal; private State state; - public GameObject normalMesh; - public GameObject holdingMesh; - - public Yarn YarnHeld { get; set; } - - private void Start() { + private void Awake() { SetState(DEFAULT_STATE); + playerContactable = GetComponent(); } public void SetState(State state) { diff --git a/Assets/Scripts/YarnContacting/Contactable.cs b/Assets/Scripts/YarnContacting/Contactable.cs index cd2ab06..b7b8db0 100644 --- a/Assets/Scripts/YarnContacting/Contactable.cs +++ b/Assets/Scripts/YarnContacting/Contactable.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -using Quaternion = UnityEngine.Quaternion; using Vector3 = UnityEngine.Vector3; /** diff --git a/Assets/Scripts/YarnContacting/PlayerContactable.cs b/Assets/Scripts/YarnContacting/PlayerContactable.cs new file mode 100644 index 0000000..76937a1 --- /dev/null +++ b/Assets/Scripts/YarnContacting/PlayerContactable.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +/** + * This Contactable uniquely belongs to the Player. + * + * It's an InteractContactable because interaction is the only way in which the player is added or removed + * as a Contact to a Yarn object. + */ +public class PlayerContactable : InteractContactable { + +} \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/PlayerContactable.cs.meta b/Assets/Scripts/YarnContacting/PlayerContactable.cs.meta new file mode 100644 index 0000000..cff4090 --- /dev/null +++ b/Assets/Scripts/YarnContacting/PlayerContactable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab040f71654faec4c811af8fee2ae1c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/YarnContacting/WrapContactable.cs b/Assets/Scripts/YarnContacting/WrapContactable.cs index 0eef552..eba2f1a 100644 --- a/Assets/Scripts/YarnContacting/WrapContactable.cs +++ b/Assets/Scripts/YarnContacting/WrapContactable.cs @@ -85,11 +85,14 @@ public static bool VectorHasWrappedVector(Vector3 baseVec, Vector3 oldVec, Vecto * element 0 being the vector counter-clockwise (negative angle) from vecToCircleCenter and element 1 being * the other. */ - private static Vector3[] FindTangentPointsToCircle(Vector3 vecToCircleCenter, float radius) { + public static Vector3[] FindTangentPointsToCircle(Vector3 vecToCircleCenter, float radius) { // this is the angle between vecToCircleCenter to both tangents - float angleToTangents = Mathf.Asin(radius / vecToCircleCenter.magnitude); - Vector3 negativeTangent = Quaternion.Euler(0, angleToTangents, 0) * vecToCircleCenter; - Vector3 positiveTangent = Quaternion.Euler(0, -angleToTangents, 0) * vecToCircleCenter; + float angleToTangents = Mathf.Asin(radius / vecToCircleCenter.magnitude) * Mathf.Rad2Deg; + // rotates counter clockwise + Vector3 negativeTangent = Quaternion.Euler(0, -angleToTangents, 0) * vecToCircleCenter; + // rotates clockwise + Vector3 positiveTangent = Quaternion.Euler(0, angleToTangents, 0) * vecToCircleCenter; + return new [] { Vector3.Project(vecToCircleCenter, negativeTangent), Vector3.Project(vecToCircleCenter, positiveTangent) diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs b/Assets/Scripts/YarnContacting/YarnLine.cs index bdba0ec..25a5b71 100644 --- a/Assets/Scripts/YarnContacting/YarnLine.cs +++ b/Assets/Scripts/YarnContacting/YarnLine.cs @@ -7,11 +7,12 @@ public class YarnLine { // the head and tail contacts are always PointContacts private PointContact head, tail; + // every other contact in the list is some sort of Contact private List wraps; private Yarn host; - + public List contacts { get; private set; } public List renderPoints { get; private set; } @@ -36,24 +37,22 @@ public void FixedUpdate() { var contact = contacts[i]; } } - + /** * Updates the line of yarn visually, after physics calculation have been performed */ - public void Update() { - - } - + public void Update() { } + /* Fires whenever the structure of the line changes. */ public void OnLineChanged() { // update the contacts list - List newContacts = new List(wraps.Count + 2){tail}; + List newContacts = new List(wraps.Count + 2) {tail}; newContacts.AddRange(wraps); newContacts.Add(head); contacts = newContacts; - + // update the renderpoints based on changed contacts - + } public void Add(Contact contact) { @@ -61,12 +60,13 @@ public void Add(Contact contact) { OnLineChanged(); } - public int RemoveAll(Contact contact) { - int result = wraps.RemoveAll(wrap => wrap.host.gameObject.Equals(contact.host.gameObject)); + public int RemoveAll(Contact contact) { return RemoveAll(contact.host.gameObject); } + public int RemoveAll(GameObject gameObject) { + int result = wraps.RemoveAll(wrap => wrap.host.gameObject.Equals(gameObject)); OnLineChanged(); return result; } - + /** * If you try to give this function a Player's Contact, it will flip the entire list * to ensure the Player is at the tail. From e6425bd1873b4df3284b8a87042a1f9211c7a504 Mon Sep 17 00:00:00 2001 From: rubic Date: Fri, 10 Apr 2020 00:58:02 -0700 Subject: [PATCH 5/7] fixed an interaction error after previous merge --- Assets/Scripts/Interactables/Yarn.cs | 5 +++-- Assets/Scripts/YarnContacting/YarnLine.cs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index fb85b5d..3bb0b58 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -27,13 +27,13 @@ protected override void Awake() { private void FixedUpdate() { // update the physics of the yarn line - //yarnLine?.FixedUpdate(); + yarnLine?.PhysicsUpdate(); // todo: allow yarn to update when things are ready } private void Update() { // update the visuals of the yarn line - //yarnLine?.Update(); + yarnLine?.Draw(); // update the points the LineRenderer is rendering if (lineRenderer && yarnLine != null) { @@ -45,6 +45,7 @@ private void Update() { } public override void Interact(PlayerManager player) { + base.Interact(player); // the player picks up the yarn if they have their arms free if (playerManager.CheckState(PlayerManager.State.Normal)) { PickUp(); diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs b/Assets/Scripts/YarnContacting/YarnLine.cs index 25a5b71..e840d78 100644 --- a/Assets/Scripts/YarnContacting/YarnLine.cs +++ b/Assets/Scripts/YarnContacting/YarnLine.cs @@ -29,7 +29,7 @@ public YarnLine(Yarn host, PointContact player, PointContact pushpin) { /** * Updates the line of yarn physically, considering new contact points and removing invalid ones */ - public void FixedUpdate() { + public void PhysicsUpdate() { // run through all Contacts: // if a Contact's Contactable sees an overlap with other Contactables, add them // if a Contact has become invalid, remove it @@ -41,7 +41,7 @@ public void FixedUpdate() { /** * Updates the line of yarn visually, after physics calculation have been performed */ - public void Update() { } + public void Draw() { } /* Fires whenever the structure of the line changes. */ public void OnLineChanged() { From 54d3e6859f79d062231b30d7f925d9116f6a5c6e Mon Sep 17 00:00:00 2001 From: rubic Date: Sat, 11 Apr 2020 03:19:34 -0700 Subject: [PATCH 6/7] began yet another redesign of the underlying systems naming functions more appropriately and following better design principles regarding responsibility of state changes. my goal is just to get the basic act of connecting to two pushpins working, with all states communicating properly. --- Assets/Scripts/Interactables/Air.cs | 2 +- Assets/Scripts/Interactables/Door.cs | 2 +- Assets/Scripts/Interactables/Interactable.cs | 10 +- Assets/Scripts/Interactables/Match.cs | 2 +- Assets/Scripts/Interactables/Nail.cs | 2 +- Assets/Scripts/Interactables/Needle.cs | 2 +- Assets/Scripts/Interactables/Pushpin.cs | 60 +++++++----- Assets/Scripts/Interactables/Yarn.cs | 43 ++++----- Assets/Scripts/PlayerBehavior/Player.cs | 92 +++++++++++++++++++ .../{PlayerManager.cs.meta => Player.cs.meta} | 0 .../Scripts/PlayerBehavior/PlayerInteract.cs | 10 +- .../Scripts/PlayerBehavior/PlayerManager.cs | 42 --------- ProjectSettings/EditorBuildSettings.asset | 3 - 13 files changed, 160 insertions(+), 110 deletions(-) create mode 100644 Assets/Scripts/PlayerBehavior/Player.cs rename Assets/Scripts/PlayerBehavior/{PlayerManager.cs.meta => Player.cs.meta} (100%) delete mode 100644 Assets/Scripts/PlayerBehavior/PlayerManager.cs diff --git a/Assets/Scripts/Interactables/Air.cs b/Assets/Scripts/Interactables/Air.cs index 6e87642..433e770 100644 --- a/Assets/Scripts/Interactables/Air.cs +++ b/Assets/Scripts/Interactables/Air.cs @@ -1,5 +1,5 @@ public class Air : Interactable { - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { print("Air was interacted with and nothing happened."); } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Door.cs b/Assets/Scripts/Interactables/Door.cs index 40dd266..c0e8ab8 100644 --- a/Assets/Scripts/Interactables/Door.cs +++ b/Assets/Scripts/Interactables/Door.cs @@ -4,7 +4,7 @@ public class Door : Interactable { public string goToLevel; public Text doorText; - public override void Interact(PlayerManager player) + public override void Interact(Player player) { SceneManager.LoadScene(goToLevel); } diff --git a/Assets/Scripts/Interactables/Interactable.cs b/Assets/Scripts/Interactables/Interactable.cs index dc292df..5cf0106 100644 --- a/Assets/Scripts/Interactables/Interactable.cs +++ b/Assets/Scripts/Interactables/Interactable.cs @@ -6,8 +6,7 @@ * An Interactable will create its own BoxCollider according to dimensions and offset */ public abstract class Interactable : MonoBehaviour { - protected GameObject player; - protected PlayerManager playerManager; + protected Player player; protected PlayerInteract playerInteract; // Sets the dimensions of the collider and offset from center of this GameObject @@ -27,10 +26,9 @@ protected virtual void Awake() { * Performs an interaction with this Interactable. * Should be customized per type of Interactable. */ - public virtual void Interact(PlayerManager player) { - this.player = player.gameObject; - this.playerManager = player; - this.playerInteract = this.player.GetComponent(); + public virtual void Interact(Player player) { + this.player = player; + playerInteract = player.GetComponent(); } private void OnTriggerEnter(Collider other) { diff --git a/Assets/Scripts/Interactables/Match.cs b/Assets/Scripts/Interactables/Match.cs index 52c3dd1..62b402e 100644 --- a/Assets/Scripts/Interactables/Match.cs +++ b/Assets/Scripts/Interactables/Match.cs @@ -1,5 +1,5 @@ public class Match : Interactable { - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { print("A Match was interacted with and nothing happened."); } } \ No newline at end of file diff --git a/Assets/Scripts/Interactables/Nail.cs b/Assets/Scripts/Interactables/Nail.cs index 372cc9c..bdda971 100644 --- a/Assets/Scripts/Interactables/Nail.cs +++ b/Assets/Scripts/Interactables/Nail.cs @@ -15,7 +15,7 @@ protected override void Awake() { meshLowerable = GetComponentInChildren(); } - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { ToggleState(); } diff --git a/Assets/Scripts/Interactables/Needle.cs b/Assets/Scripts/Interactables/Needle.cs index 58e9667..173b846 100644 --- a/Assets/Scripts/Interactables/Needle.cs +++ b/Assets/Scripts/Interactables/Needle.cs @@ -12,7 +12,7 @@ protected override void Awake() { meshLowerable = GetComponentInChildren(); } - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { ToggleState(); } diff --git a/Assets/Scripts/Interactables/Pushpin.cs b/Assets/Scripts/Interactables/Pushpin.cs index 6ea2f46..0cff023 100644 --- a/Assets/Scripts/Interactables/Pushpin.cs +++ b/Assets/Scripts/Interactables/Pushpin.cs @@ -1,6 +1,8 @@ +using System; + public class Pushpin : Interactable { - private Yarn connectedYarn; + public Yarn connectedYarn { get; protected set; } public InteractContactable interactContactable { get; protected set; } @@ -10,8 +12,14 @@ public enum State { Done, } private State state; - - public bool IsDone() { return state == State.Done; } + + private bool CheckState(State state) { return state == this.state; } + public bool IsUntied() { return CheckState(State.Untied); } + public bool IsTied() { return CheckState(State.Tied); } + public bool IsDone() { return CheckState(State.Done); } + + private void SetState(State state) { this.state = state; } + protected override void Awake() { base.Awake(); state = State.Untied; @@ -19,7 +27,7 @@ protected override void Awake() { interactContactable = GetComponent(); } - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { base.Interact(player); connectedYarn = player.yarnHeld; @@ -31,16 +39,18 @@ public override void Interact(PlayerManager player) { * - The player is pulling yarn, in which case the player wants to finish a line of yarn */ case State.Untied: { - if (playerManager.CheckState(PlayerManager.State.Holding)) { - state = State.Tied; - playerManager.SetState(PlayerManager.State.Pulling); - connectedYarn.TieStart(this); + if (player.IsHolding()) { + // start a line of yarn + SetState(State.Tied); + player.StartPulling(connectedYarn, this); + connectedYarn.StartYarnLine(this); print("Yarn was just tied to a Pushpin, starting a line."); - } else if (playerManager.CheckState(PlayerManager.State.Pulling)) { - state = State.Tied; - playerManager.SetState(PlayerManager.State.Normal); - connectedYarn.TieEnd(this); + } else if (player.IsPulling()) { + // finish a line of yarn + SetState(State.Tied); + player.FinishPulling(connectedYarn, this); + connectedYarn.FinishYarnLine(this); print("Yarn was just tied to a Pushpin, ending a line."); } break; @@ -55,20 +65,22 @@ public override void Interact(PlayerManager player) { */ case State.Tied: case State.Done: { - if (playerManager.CheckState(PlayerManager.State.Pulling) - && connectedYarn.yarnLine != null) { - // return to holding yarn - state = State.Untied; - playerManager.SetState(PlayerManager.State.Holding); - connectedYarn.UntieEnd(this); - print("Yarn was just untied from a Pushpin, undoing a line."); + // connected yarn needs to have a yarn line to be detached + if (connectedYarn.yarnLine == null) break; - } else if (playerManager.CheckState(PlayerManager.State.Normal) - && connectedYarn.yarnLine != null) { - // start changing a line of yarn again - state = State.Untied; - connectedYarn.UntieStart(this); + if (player.IsNormal()) { + // resume editing a line of yarn + SetState(State.Untied); + player.EditPulling(connectedYarn, this); + connectedYarn.EditYarnLine(this); print("Yarn was just untied from a Pushpin, to edit a line."); + } else if (player.IsPulling()) { + // undo the line of yarn entirely + SetState(State.Untied); + player.UndoPulling(connectedYarn, this); + connectedYarn.UndoYarnLine(this); + print("Yarn was just untied from a Pushpin, undoing a line."); + } break; } diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index 3bb0b58..f9b12c5 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -8,7 +8,7 @@ public class Yarn : Interactable { public GameObject mesh; private LevelManager levelManager; - [HideInInspector] public YarnLine yarnLine; + public YarnLine yarnLine { get; private set; } public enum State { Normal, @@ -16,7 +16,9 @@ public enum State { } private State state; - public bool IsDestroyed() { return state == State.Destroyed; } + private bool CheckState(State state) { return state == this.state; } + public bool IsNormal() { return CheckState(State.Normal); } + public bool IsDestroyed() { return CheckState(State.Destroyed); } protected override void Awake() { base.Awake(); @@ -28,7 +30,6 @@ protected override void Awake() { private void FixedUpdate() { // update the physics of the yarn line yarnLine?.PhysicsUpdate(); - // todo: allow yarn to update when things are ready } private void Update() { @@ -44,11 +45,11 @@ private void Update() { } } - public override void Interact(PlayerManager player) { + public override void Interact(Player player) { base.Interact(player); // the player picks up the yarn if they have their arms free - if (playerManager.CheckState(PlayerManager.State.Normal)) { - PickUp(); + if (player.IsNormal()) { + GetPickedUp(player); } } @@ -56,10 +57,9 @@ public override void Interact(PlayerManager player) { private void ShowMesh() { mesh.SetActive(true); } - private void PickUp() { - // give the player the yarn object and tell them to start holding - playerManager.SetState(PlayerManager.State.Holding); - playerManager.yarnHeld = this; + private void GetPickedUp(Player player) { + // give the player this yarn + player.GiveYarn(this); // this yarn is no longer interactable playerInteract.RemoveInteractable(this); @@ -71,10 +71,9 @@ private void PickUp() { print("The player just picked up some yarn."); } - public void PutDown() { + public void GetPutDown(Player player) { // return the player to normal, take it from the player - playerManager.SetState(PlayerManager.State.Normal); - playerManager.yarnHeld = null; + player.RemoveYarn(this); // unparent the yarn, pulling it out to the outermost level transform.parent = null; @@ -90,30 +89,24 @@ public void PutDown() { } /* Starts a line of yarn on the given pushpin. */ - public void TieStart(Pushpin pushpin) { - playerManager.SetState(PlayerManager.State.Normal); - if(mesh) HideMesh(); - - yarnLine = new YarnLine(this, playerManager.playerContactable.GetNewContact(), pushpin.interactContactable.GetNewContact()); + public void StartYarnLine(Pushpin pushpin) { + yarnLine = new YarnLine(this, player.playerContactable.GetNewContact(), pushpin.interactContactable.GetNewContact()); } /* Finishes off a line of yarn on the given pushpin. */ - public void TieEnd(Pushpin pushpin) { - + public void FinishYarnLine(Pushpin pushpin) { + if(mesh) HideMesh(); } /* Untie a line of yarn from a pushpin to continue to edit the line. */ - public void UntieStart(Pushpin pushpin) { - playerManager.SetState(PlayerManager.State.Pulling); + public void EditYarnLine(Pushpin pushpin) { if(mesh) ShowMesh(); // todo: remove the pushpin's contact, add the player } /* Untie a line of yarn from a pushpin to remove the line. */ - public void UntieEnd(Pushpin pushpin) { + public void UndoYarnLine(Pushpin pushpin) { } - - } \ No newline at end of file diff --git a/Assets/Scripts/PlayerBehavior/Player.cs b/Assets/Scripts/PlayerBehavior/Player.cs new file mode 100644 index 0000000..7adaac0 --- /dev/null +++ b/Assets/Scripts/PlayerBehavior/Player.cs @@ -0,0 +1,92 @@ +using System; +using UnityEngine; + +public class Player : MonoBehaviour { + + public GameObject normalMesh; + public GameObject holdingMesh; + + public Yarn yarnHeld { get; set; } + public PlayerContactable playerContactable { get; protected set; } + + public enum State { + Normal, + Holding, + Pulling, + } + + private State state; + private const State DEFAULT_STATE = State.Normal; + + private bool CheckState(State state) { return state == this.state; } + public bool IsNormal() { return CheckState(State.Normal); } + public bool IsHolding() { return CheckState(State.Holding); } + public bool IsPulling() { return CheckState(State.Pulling); } + + private void SetState(State state) { + if(state == this.state) Debug.LogWarning($"{this} was told to set state to {state}, but was already of state {this.state}."); + this.state = state; + + // perform updates that can be entirely determined from state + if(IsNormal()) ShowNormalMesh(); + else ShowHoldingMesh(); + } + + /* Player, not holding yarn, is given yarn to hold. */ + public void GiveYarn(Yarn yarn) { + if (yarnHeld != null) throw new Exception($"{this} was given yarn, but already had yarn!"); + + yarnHeld = yarn; + SetState(State.Holding); + } + + /* Player, already holding yarn, loses their yarn. */ + public void RemoveYarn(Yarn yarn) { + if (yarnHeld != yarn) throw new Exception($"{this} was told to remove yarn that wasn't the yarn being held!"); + + yarnHeld = null; + SetState(State.Normal); + } + + /* Player, already holding yarn, starts pulling a line of yarn from a Pushpin. */ + public void StartPulling(Yarn yarn, Pushpin pushpin) { + if (yarn != yarnHeld) throw new Exception($"{this} was told to start pulling yarn from a pushpin, but StartPulling was given yarn different from the yarn the player is holding."); + SetState(State.Pulling); + } + + /* Player, previously holding yarn, finishes pulling a line of yarn at a Pushpin. */ + public void FinishPulling(Yarn yarn, Pushpin pushpin) { + if(yarn != yarnHeld) throw new Exception($"{this} was told to finish pulling yarn at a pushpin, but FinishPulling was given yarn different from the yarn the player is holding."); + RemoveYarn(yarn); + } + + /* Player, holding nothing, wants to edit a line of yarn from a Pushpin. */ + public void EditPulling(Yarn yarn, Pushpin pushpin) { + if (yarnHeld != null) throw new Exception($"{this} was told to edit a line of yarn at a pushpin, but the player was already holding yarn."); + if (pushpin.connectedYarn != yarn) throw new Exception($"{this} was told to edit a line of yarn at a pushpin, but EditPulling was given a pushpin and yarn that were not connected!"); + // give the player the yarn and then move directly into a pulling state, + // because this yarn and pushpin are already connected + GiveYarn(yarn); + SetState(State.Pulling); + } + + /* Player, already pulling yarn, wants to undo a line of yarn they just started from a Pushpin. */ + public void UndoPulling(Yarn yarn, Pushpin pushpin) { + SetState(State.Holding); + } + + private void ShowNormalMesh() { + if(normalMesh) normalMesh.SetActive(true); + if(holdingMesh) holdingMesh.SetActive(false); + } + + private void ShowHoldingMesh() { + if(holdingMesh) holdingMesh.SetActive(true); + if(normalMesh) normalMesh.SetActive(false); + } + + private void Awake() { + SetState(DEFAULT_STATE); + playerContactable = GetComponent(); + } +} diff --git a/Assets/Scripts/PlayerBehavior/PlayerManager.cs.meta b/Assets/Scripts/PlayerBehavior/Player.cs.meta similarity index 100% rename from Assets/Scripts/PlayerBehavior/PlayerManager.cs.meta rename to Assets/Scripts/PlayerBehavior/Player.cs.meta diff --git a/Assets/Scripts/PlayerBehavior/PlayerInteract.cs b/Assets/Scripts/PlayerBehavior/PlayerInteract.cs index 547a062..0063a15 100644 --- a/Assets/Scripts/PlayerBehavior/PlayerInteract.cs +++ b/Assets/Scripts/PlayerBehavior/PlayerInteract.cs @@ -7,12 +7,12 @@ public class PlayerInteract : MonoBehaviour { private PlayerInput playerInput; - private PlayerManager playerManager; + private Player player; private List interactables; private void Awake() { playerInput = new PlayerInput(); - playerManager = GetComponent(); + player = GetComponent(); SceneManager.sceneLoaded += (scene, mode) => { interactables.Clear(); @@ -48,9 +48,9 @@ private void Update() { private void OnInteract(InputAction.CallbackContext ctx) { if (interactables.Count > 0) { - TopInteractable().Interact(playerManager); - } else if (playerManager.CheckState(PlayerManager.State.Holding)) { - playerManager.yarnHeld.PutDown(); + TopInteractable().Interact(player); + } else if (player.IsHolding()) { + player.yarnHeld.GetPutDown(player); } } } diff --git a/Assets/Scripts/PlayerBehavior/PlayerManager.cs b/Assets/Scripts/PlayerBehavior/PlayerManager.cs deleted file mode 100644 index a5cb095..0000000 --- a/Assets/Scripts/PlayerBehavior/PlayerManager.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using UnityEngine; - -public class PlayerManager : MonoBehaviour { - - public GameObject normalMesh; - public GameObject holdingMesh; - - public Yarn yarnHeld { get; set; } - - public PlayerContactable playerContactable { get; protected set; } - - public enum State { - Normal, - Holding, - Pulling, - } - - private const State DEFAULT_STATE = State.Normal; - private State state; - - private void Awake() { - SetState(DEFAULT_STATE); - playerContactable = GetComponent(); - } - - public void SetState(State state) { - this.state = state; - UpdateFromState(); - } - public bool CheckState(State state) { return state == this.state; } - - private void UpdateFromState() { - if (CheckState(State.Normal)) { - if(normalMesh) normalMesh.SetActive(true); - if(holdingMesh) holdingMesh.SetActive(false); - } else { - if(holdingMesh) holdingMesh.SetActive(true); - if(normalMesh) normalMesh.SetActive(false); - } - } -} diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index eb4e938..dc05aac 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -11,9 +11,6 @@ EditorBuildSettings: - enabled: 1 path: Assets/Scenes/HubWorld.unity guid: 6a84e2a0d6e1b0b469a7fd70b9a6e061 - - enabled: 1 - path: Assets/Scenes/Template.unity - guid: 9fc0d4010bbf28b4594072e72b8655ab - enabled: 1 path: Assets/Scenes/Levels/1.unity guid: e34c4f68cd9f049489917c15af9ccf69 From c6889049afcf711bdba865a13609b860fce6d362 Mon Sep 17 00:00:00 2001 From: rubic Date: Sun, 12 Apr 2020 01:49:16 -0700 Subject: [PATCH 7/7] attaching to pushpin and detaching working again! but the contacts aren't updating each frame for some reason? --- Assets/Scenes/Template.unity | 21 +++++---- Assets/Scripts/Interactables/Pushpin.cs | 26 ++++++----- Assets/Scripts/Interactables/Yarn.cs | 29 ++++++++---- Assets/Scripts/YarnContacting/YarnLine.cs | 57 +++++++++++++++-------- 4 files changed, 85 insertions(+), 48 deletions(-) diff --git a/Assets/Scenes/Template.unity b/Assets/Scenes/Template.unity index fe5135a..e23f455 100644 --- a/Assets/Scenes/Template.unity +++ b/Assets/Scenes/Template.unity @@ -1023,7 +1023,7 @@ PrefabInstance: - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} propertyPath: m_RootOrder - value: 9 + value: 8 objectReference: {fileID: 0} - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} @@ -1511,7 +1511,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 6 + m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 50, y: 0, z: 0} --- !u!114 &963194229 MonoBehaviour: @@ -2702,7 +2702,7 @@ PrefabInstance: - target: {fileID: 1239185254202489153, guid: c9803ecc16e1ec742b5a2d6280a67d35, type: 3} propertyPath: m_RootOrder - value: 11 + value: 10 objectReference: {fileID: 0} - target: {fileID: 1239185254202489153, guid: c9803ecc16e1ec742b5a2d6280a67d35, type: 3} @@ -2766,7 +2766,7 @@ PrefabInstance: - target: {fileID: 1293638319414553333, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} propertyPath: m_RootOrder - value: 5 + value: 4 objectReference: {fileID: 0} - target: {fileID: 1293638319414553333, guid: 3f7ba35961265c14d95fd3df6e0e7e17, type: 3} @@ -2840,7 +2840,7 @@ PrefabInstance: - target: {fileID: 1583258828818565569, guid: eedf6123f261655408fea12ace3e43f3, type: 3} propertyPath: m_RootOrder - value: 12 + value: 11 objectReference: {fileID: 0} - target: {fileID: 1583258828818565569, guid: eedf6123f261655408fea12ace3e43f3, type: 3} @@ -2857,6 +2857,11 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 7411008065860400178, guid: eedf6123f261655408fea12ace3e43f3, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: eedf6123f261655408fea12ace3e43f3, type: 3} --- !u!1001 &6461784657988510636 @@ -2909,7 +2914,7 @@ PrefabInstance: - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} propertyPath: m_RootOrder - value: 8 + value: 7 objectReference: {fileID: 0} - target: {fileID: 6461784659212241894, guid: fff8d0044295e4f4db1036bcd8e4918d, type: 3} @@ -2978,7 +2983,7 @@ PrefabInstance: - target: {fileID: 8515438956722547815, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} propertyPath: m_RootOrder - value: 7 + value: 6 objectReference: {fileID: 0} - target: {fileID: 8515438956722547815, guid: 4c3258452a716e34ca0be2fbf848b5e8, type: 3} @@ -3047,7 +3052,7 @@ PrefabInstance: - target: {fileID: 8523065194936625137, guid: 1b3a16bdb00e85445b4b342236544567, type: 3} propertyPath: m_RootOrder - value: 10 + value: 9 objectReference: {fileID: 0} - target: {fileID: 8523065194936625137, guid: 1b3a16bdb00e85445b4b342236544567, type: 3} diff --git a/Assets/Scripts/Interactables/Pushpin.cs b/Assets/Scripts/Interactables/Pushpin.cs index 0cff023..11f59a9 100644 --- a/Assets/Scripts/Interactables/Pushpin.cs +++ b/Assets/Scripts/Interactables/Pushpin.cs @@ -29,7 +29,6 @@ protected override void Awake() { public override void Interact(Player player) { base.Interact(player); - connectedYarn = player.yarnHeld; switch (state) { /* @@ -39,18 +38,19 @@ public override void Interact(Player player) { * - The player is pulling yarn, in which case the player wants to finish a line of yarn */ case State.Untied: { + connectedYarn = player.yarnHeld; if (player.IsHolding()) { // start a line of yarn - SetState(State.Tied); player.StartPulling(connectedYarn, this); - connectedYarn.StartYarnLine(this); + connectedYarn.StartYarnLine(player, this); + SetState(State.Tied); print("Yarn was just tied to a Pushpin, starting a line."); } else if (player.IsPulling()) { // finish a line of yarn - SetState(State.Tied); player.FinishPulling(connectedYarn, this); connectedYarn.FinishYarnLine(this); + SetState(State.Tied); print("Yarn was just tied to a Pushpin, ending a line."); } break; @@ -58,30 +58,32 @@ public override void Interact(Player player) { /* * Yarn can be detached from this Pushpin if: * - This Pushpin is Tied OR Done already - * - The player is pulling yarn, in which case they want to return to just holding yarn - * - This Pushpin must be part of this line of yarn AND be the only thing other than the player * - The player is normal, in which case they want to change an existing line of yarn * - This Pushpin must be either the first or last in the line of yarn + * - The player is pulling yarn, in which case they want to return to just holding yarn + * - This Pushpin must be part of this line of yarn AND be the only thing other than the player */ case State.Tied: case State.Done: { - // connected yarn needs to have a yarn line to be detached - if (connectedYarn.yarnLine == null) break; + // pushpin needs to have connected yarn for said yarn to be detached + if (connectedYarn == null) throw new Exception($"{this} was interacted with in a Tied or Done state but somehow has no connected Yarn!"); if (player.IsNormal()) { // resume editing a line of yarn - SetState(State.Untied); player.EditPulling(connectedYarn, this); - connectedYarn.EditYarnLine(this); + connectedYarn.EditYarnLine(this, player); + SetState(State.Untied); print("Yarn was just untied from a Pushpin, to edit a line."); + } else if (player.IsPulling()) { // undo the line of yarn entirely - SetState(State.Untied); player.UndoPulling(connectedYarn, this); connectedYarn.UndoYarnLine(this); + SetState(State.Untied); print("Yarn was just untied from a Pushpin, undoing a line."); - } + + connectedYarn = null; break; } } diff --git a/Assets/Scripts/Interactables/Yarn.cs b/Assets/Scripts/Interactables/Yarn.cs index f9b12c5..9601d8a 100644 --- a/Assets/Scripts/Interactables/Yarn.cs +++ b/Assets/Scripts/Interactables/Yarn.cs @@ -39,7 +39,7 @@ private void Update() { // update the points the LineRenderer is rendering if (lineRenderer && yarnLine != null) { var linePoints = new List(); - foreach (var c in yarnLine.contacts) linePoints.AddRange(c.renderPoints); + linePoints.AddRange(yarnLine.renderPoints); lineRenderer.positionCount = linePoints.Count; lineRenderer.SetPositions(linePoints.ToArray()); } @@ -57,6 +57,7 @@ public override void Interact(Player player) { private void ShowMesh() { mesh.SetActive(true); } + /* A Player picks up this Yarn. */ private void GetPickedUp(Player player) { // give the player this yarn player.GiveYarn(this); @@ -71,6 +72,7 @@ private void GetPickedUp(Player player) { print("The player just picked up some yarn."); } + /* A Player puts down this Yarn. */ public void GetPutDown(Player player) { // return the player to normal, take it from the player player.RemoveYarn(this); @@ -88,25 +90,34 @@ public void GetPutDown(Player player) { print("The player has dropped the yarn."); } - /* Starts a line of yarn on the given pushpin. */ - public void StartYarnLine(Pushpin pushpin) { + /* Starts a line of yarn between a Player and a Pushpin. */ + public void StartYarnLine(Player player, Pushpin pushpin) { yarnLine = new YarnLine(this, player.playerContactable.GetNewContact(), pushpin.interactContactable.GetNewContact()); } - /* Finishes off a line of yarn on the given pushpin. */ + /* Finishes off this Yarn's line on the given Pushpin. */ public void FinishYarnLine(Pushpin pushpin) { if(mesh) HideMesh(); + yarnLine.SetTail(pushpin.interactContactable.GetNewContact()); } - /* Untie a line of yarn from a pushpin to continue to edit the line. */ - public void EditYarnLine(Pushpin pushpin) { + /* Unties this Yarn's line from a Pushpin to allow a Player to edit the line. */ + public void EditYarnLine(Pushpin pushpin, Player player) { if(mesh) ShowMesh(); - // todo: remove the pushpin's contact, add the player + // add the player on the same side of the YarnLine that the given Pushpin is at + if (yarnLine.GetHead().gameObject.Equals(pushpin.gameObject)) { + yarnLine.SetHead(player.playerContactable.GetNewContact()); + } else if (yarnLine.GetTail().gameObject.Equals(pushpin.gameObject)) { + yarnLine.SetTail(player.playerContactable.GetNewContact()); + } else { + throw new Exception($"{this} was told to edit its YarnLine, but was given a Pushpin that isn't on either side of the YarnLine!"); + } } - /* Untie a line of yarn from a pushpin to remove the line. */ + /* Undoes this Yarn's line from a Pushpin to remove the line. */ public void UndoYarnLine(Pushpin pushpin) { - + yarnLine.Clear(); + yarnLine = null; } } \ No newline at end of file diff --git a/Assets/Scripts/YarnContacting/YarnLine.cs b/Assets/Scripts/YarnContacting/YarnLine.cs index e840d78..81651dd 100644 --- a/Assets/Scripts/YarnContacting/YarnLine.cs +++ b/Assets/Scripts/YarnContacting/YarnLine.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using UnityEngine; /** @@ -11,7 +12,7 @@ public class YarnLine { // every other contact in the list is some sort of Contact private List wraps; - private Yarn host; + private Yarn yarn; public List contacts { get; private set; } public List renderPoints { get; private set; } @@ -19,11 +20,12 @@ public class YarnLine { /** * A YarnLine can only be created by a Yarn that has been started between the Player and a Pushpin */ - public YarnLine(Yarn host, PointContact player, PointContact pushpin) { - this.host = host; - head = player; - tail = pushpin; + public YarnLine(Yarn yarn, PointContact player, PointContact pushpin) { + this.yarn = yarn; + head = pushpin; + tail = player; wraps = new List(); + OnLineChanged(); } /** @@ -35,38 +37,46 @@ public void PhysicsUpdate() { // if a Contact has become invalid, remove it for (var i = 0; i < contacts.Count; i++) { var contact = contacts[i]; + // todo: check whatever needs to be checked to add or remove contacts from this YarnLine } } /** * Updates the line of yarn visually, after physics calculation have been performed */ - public void Draw() { } + public void Draw() { + + } /* Fires whenever the structure of the line changes. */ - public void OnLineChanged() { + private void OnLineChanged() { // update the contacts list - List newContacts = new List(wraps.Count + 2) {tail}; - newContacts.AddRange(wraps); - newContacts.Add(head); - contacts = newContacts; + contacts = new List(wraps.Count + 2) {head}; + contacts.AddRange(wraps); + contacts.Add(tail); // update the renderpoints based on changed contacts - + renderPoints = new List(); + foreach (var contact in contacts) { + if(contact != null) renderPoints.AddRange(contact.renderPoints); + } } - public void Add(Contact contact) { + private void Add(Contact contact) { wraps.Add(contact); OnLineChanged(); } - public int RemoveAll(Contact contact) { return RemoveAll(contact.host.gameObject); } - public int RemoveAll(GameObject gameObject) { + private int RemoveAll(Contact contact) { return RemoveAll(contact.host.gameObject); } + private int RemoveAll(GameObject gameObject) { int result = wraps.RemoveAll(wrap => wrap.host.gameObject.Equals(gameObject)); OnLineChanged(); return result; } + public Contactable GetHead() { return head.host; } + public Contactable GetTail() { return tail.host; } + /** * If you try to give this function a Player's Contact, it will flip the entire list * to ensure the Player is at the tail. @@ -83,15 +93,24 @@ public void SetTail(PointContact contact) { } /* Reverses the entire list, including the head and tail contacts. */ - public void ReverseList() { + private void ReverseList() { // swap head and tail var temp = tail; tail = head; head = temp; // reverse all wrapping points wraps.Reverse(); - // reverse all prev and next Contact references - + // todo: reverse all prev and next Contact references + } + + /** + * Clears the entire line, removing everything. + */ + public void Clear() { + head = null; + tail = null; + wraps.Clear(); + OnLineChanged(); } private void OnDrawGizmos() {