Skip to content

Instantly share code, notes, and snippets.

@CoffeeVampir3
Last active July 4, 2021 17:45
Show Gist options
  • Save CoffeeVampir3/16fcbe178d1c56d4430255f2f6e78238 to your computer and use it in GitHub Desktop.
Save CoffeeVampir3/16fcbe178d1c56d4430255f2f6e78238 to your computer and use it in GitHub Desktop.
using Sirenix.OdinInspector;
using UnityEngine;
namespace VisualNovelFramework
{
public class VNDialogueController : MonoBehaviour
{
[SerializeField]
private TMPShakeParser shakeParser = null;
[SerializeField]
private TMPTeletyper teletyper = null;
[SerializeField]
private TMPVertexer vertexManipulator = null;
private void DisplayString(string tString)
{
vertexManipulator.StopShake();
teletyper.ClearAndSet(tString);
var shakeRegions = shakeParser.ParseString(tString);
if (shakeRegions != null)
{
vertexManipulator.SetShake(shakeRegions);
}
teletyper.StartTeletype();
}
[TextArea(10,10)]
public string testText = "This is the <b>thing<b> to display.";
[Button]
private void TestDisplay()
{
DisplayString(testText);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
namespace VisualNovelFramework
{
public class TMPShakeParser : MonoBehaviour
{
public TMP_Text target;
public string GetTMPROWithoutTags()
{
var info = target.textInfo.characterInfo;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < info.Length; i++)
{
builder.Append(info[i].character);
}
return builder.ToString();
}
public readonly struct ShakeRegion
{
public readonly int start;
public readonly int end;
public ShakeRegion(int s, int e)
{
start = s;
end = e;
}
}
public List<ShakeRegion> ParseShakeRegions(ref string inputString)
{
Regex shakeRegex = new Regex("<shake>");
Regex shakeClosingRegex = new Regex("</shake>");
var shakeOpen = shakeRegex.Matches(inputString);
var shakeClose = shakeClosingRegex.Matches(inputString);
if (shakeOpen.Count <= 0)
{
return null;
}
if (shakeOpen.Count != shakeClose.Count)
{
Debug.LogError("Malformed or missing tags detected in shake-string parse: " + inputString);
}
List<ShakeRegion> shakeRegions = new List<ShakeRegion>();
int offset = 0;
for (int i = 0; i < shakeOpen.Count; i++)
{
int start = shakeOpen[i].Index - offset;
int end = shakeClose[i].Index - offset - 7; //length of <shake>
shakeRegions.Add(new ShakeRegion(start, end));
offset += 15; // length of <shake> + </shake>
}
target.text = target.text.Replace("<shake>", "");
target.text = target.text.Replace("</shake>", "");
return shakeRegions;
}
public List<ShakeRegion> ParseString(string stuff)
{
target.text = stuff;
target.ForceMeshUpdate();
var info = GetTMPROWithoutTags();
return ParseShakeRegions(ref info);
}
}
}
using TMPro;
using UnityEngine;
namespace VisualNovelFramework
{
public class TMPTeletyper : MonoBehaviour
{
public TMP_Text target;
private int cursor = 0;
[SerializeField]
private float vnTickRate = .1f;
[SerializeField]
private bool running = false;
private float timeOffset = 0f;
private int totalVisible = 0;
public void ClearAndSet(string targetString)
{
target.maxVisibleCharacters = 0;
target.text = targetString;
target.ForceMeshUpdate();
totalVisible = target.textInfo.characterCount;
running = false;
timeOffset = 0f;
cursor = 0;
}
public void StartTeletype()
{
running = true;
}
public void Update()
{
if (!running)
return;
if (!(Time.time - timeOffset > vnTickRate))
return;
timeOffset = Time.time;
if (cursor <= totalVisible)
{
target.maxVisibleCharacters = cursor;
}
else
{
running = false;
return;
}
cursor++;
}
}
}
using System.Collections.Generic;
using TMPro;
using UnityEngine;
namespace VisualNovelFramework
{
public class TMPVertexer : MonoBehaviour
{
public TMP_Text target;
private List<TMPShakeParser.ShakeRegion> shakeRegions;
private bool shake = false;
public void SetShake(List<TMPShakeParser.ShakeRegion> regions)
{
shakeRegions = regions;
shake = true;
}
public void StopShake()
{
shakeRegions?.Clear();
shake = false;
}
public void LateUpdate()
{
if (!shake) return;
target.ForceMeshUpdate();
var textInfo = target.textInfo;
foreach (TMPShakeParser.ShakeRegion region in shakeRegions)
{
for (int i = region.start; i < region.end; i++)
{
var charInfo = textInfo.characterInfo[i];
if (!charInfo.isVisible)
continue;
var verts = textInfo.meshInfo[charInfo.materialReferenceIndex].vertices;
for (int j = 0; j < 4; j++)
{
var orig = verts[charInfo.vertexIndex + j];
verts[charInfo.vertexIndex + j] =
orig + new Vector3(0,
Mathf.Sin(Time.time*2f * charInfo.vertexIndex * 0.01f) * 10, 0);
}
}
}
for (int i = 0; i < textInfo.meshInfo.Length; i++)
{
var meshInfo = textInfo.meshInfo[i];
meshInfo.mesh.vertices = meshInfo.vertices;
target.UpdateGeometry(meshInfo.mesh, i);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment