-->

分類

2017年4月23日 星期日

Unity UGUI text underline

reference


using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TextUnderline : MonoBehaviour {
 //Text that draws underline
 public Text underline;

 /*
  refText: Text that its text content will be underlined
  clear: clear underline
  underlineVerticalOffsetScale: control distance between refText and underline
 
  sample hierarchy structure:

  refText(components: Text)
   underline(components: Text, TextUnderline)   
 */
 public void setup(Text refText, bool clear = false, float underlineVerticalOffsetScale = 1.0f)
 {
  if(clear)
  {
   underline.text = "";
   return;
  }
  RectTransform rt = underline.GetComponent();
  RectTransform refRT = refText.GetComponent();

  underline.font = refText.font;
  underline.fontSize = refText.fontSize;
  //underline.fontStyle = refText.fontStyle;
  underline.color = refText.color;
  underline.text = "_";

  rt.localScale = refRT.localScale;
  float refHeight = refText.preferredHeight;

  float perlineWidth = underline.preferredWidth * rt.localScale.x;
  Debug.Log(perlineWidth);

  float refWidth = refText.preferredWidth;
  int lineCount = (int)Mathf.Round(refWidth / perlineWidth);
  Debug.Log(lineCount);
  for (int i = 1; i < lineCount; i++)
  {
   underline.text += "_";
  }

  float selfHeight = underline.preferredHeight;
  rt.anchoredPosition = new Vector2(0.0f, -(refHeight + selfHeight) * underlineVerticalOffsetScale);
 }
}








2017年4月4日 星期二

Unity load external script at runtime(using Visual Studio)

reference link

To load external script into Unity at runtime, the external script needs to be compiled as assembly(.dll), here are steps to do so.

1. Create a new C# project with Visual Studio, choose the project type as "Class Library"
2. Add UnityEngine.dll as project reference, the UnityEngine.dll is located at "<Unity_Install_Path>\Editor\Data\Managed". Add the dll to project reference by the following steps: 
right click project name in Solution Explorer -> Properties -> Reference Paths -> Folder -> browse to find the folder that contains .dll -> Add Folder


right click "References" in Solution Explorer -> Add References -> Assembly -> search the dll you added

3. in the created Class Library project, create a class that extends MonoBehaviour like what we usually do in Unity, you can implement its Start(), Update()...

4. Release build this library project and remember the path to the .dll created by this library project

5. use the WWWAssemblyLoader in the reference link above or my modified assembly loader below:


using UnityEngine;
using System.Collections;
using System;
using System.Reflection;

public class MyWWWAssemblyLoader
{

 public IEnumerator loadAssembly(string url, Action finishCallback)
 {
  if(url == null || finishCallback == null)
  {
   yield break;
  }
  WWW m_WWW = new WWW(url);
  while(!m_WWW.isDone)
  {
   yield return null;
  }

  Assembly assembly = LoadAssembly(m_WWW);
  if (assembly != null)
  {
   Debug.Log("load assembly: " + url + " Done");
   finishCallback(true, url, assembly);
  }
  else
  {
   Debug.Log("load assembly: " + url + " Failed");
   finishCallback(false, url, assembly);
  }

 }

 private Assembly LoadAssembly(WWW m_WWW)
 {
  try
  {
   return Assembly.Load(m_WWW.bytes);
  }
  catch (System.Exception e)
  {
   Debug.LogError(e.ToString());
   return null;
  }
 }
}

6. load the dll and use reflection to control it as following:


 IEnumerator Start()
 {
  //load script
  yield return StartCoroutine(loadAssemblyScriptAsync("file:///YourAssembly.dll", onAssemblyScriptLoaded));
 }

 private IEnumerator loadAssemblyScriptAsync(string url, Action callback)
 {
  MyWWWAssemblyLoader myLoader = new MyWWWAssemblyLoader();
  yield return StartCoroutine(myLoader.loadAssembly(url, callback));

 }

 private void onAssemblyScriptLoaded(bool success, string url, Assembly assembly)
 {
  if (!success)
  {
   Debug.LogError("onAssemblyScriptLoaded failed");
   return;
  }
  Debug.Log("Assembly url: " + url);

  System.Type type = assembly.GetType("YourClassNameSpace.YourClassName");
  if (type == null)
  {
   Debug.LogError("type is null");
   return;
  }
  FieldInfo field = type.GetField("YourFloatField");

  GameObject go = GameObject.Find("YourEmptyGameObject");
  //add loaded script to go
  Component comp = go.AddComponent(type);

  FieldInfo myFieldInfo = type.GetField("YourFloatField");

  Debug.Log("The field value of YourFloatField is " + myFieldInfo.GetValue(comp));

  myFieldInfo.SetValue(comp, 30.0f);

  Debug.Log("The new field value of YourFloatField is " + myFieldInfo.GetValue(comp));
 }

7. the external script for above code can be:


using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace YourClassNameSpace
{
    public class YourClassName : MonoBehaviour
 {
  public float YourFloatField = 1.0f;
  // Use this for initialization
  void Start()
  {

  }

  // Update is called once per frame
  void Update()
  {
   transform.Rotate(Vector3.up, YourFloatField * Time.deltaTime);
  }
 }
}