I want to make an anagram puzzle solver; so the behaviours I’m going to need in my script are ‘muddling’ the characters in a word and allowing the player to drag and drop the characters in a word to form new sequences.
I have written a script that implements the IBeginDragHandler, IDragHandler, IEndDragHandler interfaces to drag RectTransforms around on a canvas, and I was originally going to have a TextMesh Pro object for each letter. But I have since learned that TextMesh Pro contains a lot of definitions for word and text structure, and I want to leverage that.
However, I have been unable to find a way to move a character mesh according to mouse position. I have done a lot of research in the past week, and all I have been able to accomplish is this mess:
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(TextMeshProUGUI))]
public class Test : MonoBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
private TMP_Text text;
private TMP_TextInfo textInfo;
private TMP_CharacterInfo charInfo;
private int charIndex;
private int vertexIndex;
private Vector3[] vertices;
private Matrix4x4 matrix; //?
private RectTransform canvasRectTransform; // The RectTransform of the Canvas.
private RectTransform rectTransform; // The RectTransform of the Draggable GameObject.
private Vector2 offset; // The mouse position offset on the Draggable GameObject.
private Vector3 origin; // The origin position of the Draggable GameObject.
private Vector3 bottomLeft;
private Vector3 topLeft;
private Vector3 topRight;
private Vector3 bottomRight;
private RectTransform rt;
private Rect rect;
private TextMeshPro textMeshPro;
private void Awake()
{
text = GetComponent<TMP_Text>();
textMeshPro = GetComponent<TextMeshPro>();
}
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
rectTransform = eventData.pointerEnter.transform as RectTransform;
canvasRectTransform = eventData.pointerEnter.transform.GetComponentInParent<Canvas>().transform as RectTransform;
}
public void OnBeginDrag(PointerEventData eventData)
{
// Generate the mesh and populate the textInfo with data we can use and manipulate.
text.ForceMeshUpdate();
charIndex = TMP_TextUtilities.FindIntersectingCharacter(text, Input.mousePosition, eventData.pressEventCamera, true);
textInfo = text.textInfo;
charInfo = textInfo.characterInfo[charIndex];
vertices = textInfo.meshInfo[0].vertices;
bottomLeft = canvasRectTransform.InverseTransformPoint(charInfo.bottomLeft);
topLeft = canvasRectTransform.InverseTransformPoint(charInfo.topLeft);
topRight = canvasRectTransform.InverseTransformPoint(charInfo.topRight);
bottomRight = canvasRectTransform.InverseTransformPoint(charInfo.bottomRight);
rect = new Rect(topLeft.x, topLeft.y, Mathf.Abs(topLeft.x - topRight.x), Mathf.Abs(topLeft.y - bottomLeft.y));
text.havePropertiesChanged = true;
//textMeshPro.renderMode = TextRenderFlags.DontRender; // Instructing TextMesh Pro not to upload the mesh as we will be modifying it
vertexIndex = textInfo.characterInfo[charIndex].vertexIndex;
Debug.Log(charInfo.character);
}
public void OnDrag(PointerEventData eventData)
{
// Compute the baseline mid point for each character
//Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[charIndex].baseLine);
//// Apply offset to adjust our pivot point.
//vertices[vertexIndex + 0] += -offsetToMidBaseline;
//vertices[vertexIndex + 1] += -offsetToMidBaseline;
//vertices[vertexIndex + 2] += -offsetToMidBaseline;
//vertices[vertexIndex + 3] += -offsetToMidBaseline;
//var vertex0Screen = RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, vertices[vertexIndex + 0]);
//var vertex1Screen = RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, vertices[vertexIndex + 1]);
//var vertex2Screen = RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, vertices[vertexIndex + 2]);
//var vertex3Screen = RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, vertices[vertexIndex + 3]);
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, eventData.position, eventData.pressEventCamera, out Vector2 mouseLocal);
bottomLeft = mouseLocal;
vertices[vertexIndex + 0] = canvasRectTransform.TransformPoint(bottomLeft);
//RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, vertex0Screen, eventData.pressEventCamera, out Vector2 vertex0Local);
//RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, vertex1Screen, eventData.pressEventCamera, out Vector2 vertex1Local);
//RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, vertex2Screen, eventData.pressEventCamera, out Vector2 vertex2Local);
//RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, vertex3Screen, eventData.pressEventCamera, out Vector2 vertex3Local);
//vertices[vertexIndex + 0] = canvasRectTransform.TransformPoint(mouseLocal);
//TMP_TextUtilities.ScreenPointToWorldPointInRectangle(text.transform, eventData.position, eventData.pressEventCamera, out Vector3 mouseWorld);
//var vertex0World = canvasRectTransform.TransformPoint(new Vector2(rect.xMin, rect.yMax));
//var vertex1World = canvasRectTransform.TransformPoint(new Vector2(rect.xMin, rect.yMin));
//var vertex2World = canvasRectTransform.TransformPoint(new Vector2(rect.yMax, rect.yMin));
//var vertex3World = canvasRectTransform.TransformPoint(new Vector2(rect.yMax, rect.yMax));
////Debug.Log(position.ToString());
//vertices[vertexIndex + 0] = vertex0World;
//vertices[vertexIndex + 1] = vertex1World;
//vertices[vertexIndex + 2] = vertex2World;
//vertices[vertexIndex + 3] = vertex3World;
//matrix = Matrix4x4.TRS(mouseWorld, Quaternion.identity, Vector3.one);
//vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]);
//vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]);
//vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]);
//vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]);
//vertices[vertexIndex + 0] += offsetToMidBaseline;
//vertices[vertexIndex + 1] += offsetToMidBaseline;
//vertices[vertexIndex + 2] += offsetToMidBaseline;
//vertices[vertexIndex + 3] += offsetToMidBaseline;
text.mesh.vertices = vertices;
text.mesh.uv = textInfo.meshInfo[0].uvs0;
text.mesh.uv2 = textInfo.meshInfo[0].uvs2;
text.mesh.colors32 = textInfo.meshInfo[0].colors32;
// Upload the mesh with the revised information
text.UpdateVertexData();
//textMeshPro.mesh.RecalculateBounds(); // We need to update the bounds of the text object.
//text.UpdateVertexData(TMP_VertexDataUpdateFlags.Vertices);
//text.ForceMeshUpdate();
}
public void OnEndDrag(PointerEventData eventData)
{
//text.UpdateVertexData(TMP_VertexDataUpdateFlags.Vertices);
//text.ForceMeshUpdate();
}
}
Could someone more experienced with TextMesh Pro please point me in the right direction as to what my code should look like inside the IDragHandler method for moving a character mesh according to mouse position?