Showing posts with label unity. Show all posts
Showing posts with label unity. Show all posts

Monday, August 20, 2018

How to stop an Input field being submitted when it loses focus

The Problem:
In Unity the default behaviour of an input field when it loses focus is to fire the OnEndEdit event.

Solution:
If you don't want this to happen - at the start of the method that is called by OnEndEdit check to see if the enter key is being pressed and return without doing anything is it isn't.

Eg:

if (!Input.GetKey(KeyCode.Return))
  return;

Saturday, June 16, 2018

Contents of Scroll View UI won't display

Symptoms:

My exact symptoms were that the Scroll View contents would be displayed if I played from the scene with the Scroll View, but if I started in another scene and went to that scene the Scroll View would be empty.

Solution:

Set the Under the Scroll Rect component of the Scroll View set the visibility to "Permanent".

Friday, June 15, 2018

How to create Linked Text in Unity with Textmesh Pro

What I was trying to achieve was a block of UI text with links that I could click with the mouse to cause something to happen. In Unity this doesn't happen out of the box. However there is a package called TextMesh Pro which with a bit of effort achieved what I was after.

Here is the link: https://assetstore.unity.com/packages/essentials/beta-projects/textmesh-pro-84126

Unfortunately the documentation is a bit sketchy, some out-of-date, and difficult to find for the newer version.

So to get it to work...
  1. Update to Unity 5.6 or later.
  2. Download and install the package.
  3. From GameObject > UI add a TextMeshPro-Text to the canvas.
  4. Make sure the scene has an Event System object.
  5. Add a script to TextMesh Pro Text object based on TMP_Text_Selector_B.cs 
  6. Links in the text need to be tagged like: Some text <link="link_name">this text has a link</link> and this is boring text.
  7. In TMP_TextInfoDebugTool.cs comment out the contents of method OnDrawGizmos() as this causes errors in the editor.
  8. There is a sample scene called: 12 - Link Example with links that work.
  9. If using the color tag (which works a little different to to the Text color tag) make sure that the base text color is white. Color tags are in the form: <#40A0FF>This is a color tag - just specify the color in the tag.</color>
  10. While I could get the mouseovers to work using the new TMP Text Event Handler script I couldn't get it to register mouse clicks so I used the old TMP_Text_Selector_B version instead.
This is my Selector script based on TMP_Text_Selector_B
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
using TMPro;

// Disabled warning due to SetVertices being deprecated 
// until new release with SetMesh() is available.
#pragma warning disable 0618

public class TextOutputTextSelector : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler, IPointerUpHandler
{
 public RectTransform TextPopup_Prefab_01;

 private RectTransform m_TextPopup_RectTransform;
 private TextMeshProUGUI m_TextPopup_TMPComponent;

 private const string k_LinkText = "You have selected link <#ffff00>";
 private const string k_WordText = "Word Index: <#ffff00>";


 private TextMeshProUGUI m_TextMeshPro;
 private Canvas m_Canvas;
 private Camera m_Camera;

 // Flags
 private bool isHoveringObject;
 private int m_selectedLink = -1;
 private int m_selectedWord = -1;
 private int m_lastIndex = -1;

 private Matrix4x4 m_matrix;

 private TMP_MeshInfo[] m_cachedMeshInfoVertexData;

 // ----------------------------------------------------------------------------
 public void Awake()
 {
  m_TextMeshPro = gameObject.GetComponent<TextMeshProUGUI>();
  m_Canvas = gameObject.GetComponentInParent<Canvas>();

  // Get a reference to the camera if Canvas Render Mode is not ScreenSpace Overlay.
  if (m_Canvas.renderMode == RenderMode.ScreenSpaceOverlay)
   m_Camera = null;
  else
   m_Camera = m_Canvas.worldCamera; 
 }

 // ----------------------------------------------------------------------------
 public void OnEnable()
 {

  // Subscribe to event fired when text object has been regenerated.
  TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ON_TEXT_CHANGED);
 }
  
 // ----------------------------------------------------------------------------
 public void OnDisable()
 {
  // UnSubscribe to event fired when text object has been regenerated.
  TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ON_TEXT_CHANGED);
 }

 // ----------------------------------------------------------------------------
 public void ON_TEXT_CHANGED(Object obj)
 {

  if (obj == m_TextMeshPro)
  {
   // Update cached vertex data.
   m_cachedMeshInfoVertexData = m_TextMeshPro.textInfo.CopyMeshInfoVertexData();
  }
 }

 // ----------------------------------------------------------------------------
 public void LateUpdate()
 {

  if (isHoveringObject)
  {
   // LINKS 
   // Check if mouse intersects with any links.
   int linkIndex = TMP_TextUtilities.FindIntersectingLink(m_TextMeshPro, Input.mousePosition, m_Camera);

   // Clear previous link selection if one existed.
   if ((linkIndex == -1 && m_selectedLink != -1) || linkIndex != m_selectedLink)
   {
    m_selectedLink = -1;
   }

   // Handle new Link selection.
   if (linkIndex != -1 && linkIndex != m_selectedLink)
   {
    m_selectedLink = linkIndex;
    TMP_LinkInfo linkInfo = m_TextMeshPro.textInfo.linkInfo[linkIndex];

    Debug.Log("(Late Update) Selected Link Index: " + m_selectedLink);
    Debug.Log("*** (Late Update) Link ID: \"" + linkInfo.GetLinkID() + "\"   Link Text: \"" + linkInfo.GetLinkText() + "\""); 

    Vector3 worldPointInRectangle = Vector3.zero;
    RectTransformUtility.ScreenPointToWorldPointInRectangle(m_TextMeshPro.rectTransform, Input.mousePosition, m_Camera, out worldPointInRectangle);

    // change color of link (Doesn't quite work but leaving here for future use)
    // Iterate through each of the characters of the word.
    /*
    Debug.Log("First Character Index: " + linkInfo.linkTextfirstCharacterIndex);
    Debug.Log("Link Text Length: " + linkInfo.linkTextLength);

    for (int i = 0; i < linkInfo.linkTextLength; i++)
    {
     int characterIndex = linkInfo.linkTextfirstCharacterIndex + i;

     // Get the index of the material / sub text object used by this character.
     int meshIndex = m_TextMeshPro.textInfo.characterInfo[characterIndex].materialReferenceIndex;

     int vertexIndex = m_TextMeshPro.textInfo.characterInfo[characterIndex].vertexIndex;

     // Get a reference to the vertex color
     Color32[] vertexColors = m_TextMeshPro.textInfo.meshInfo[meshIndex].colors32;

     Color32 c = vertexColors[vertexIndex + 0].Tint(0.75f);

     vertexColors[vertexIndex + 0] = c;
     vertexColors[vertexIndex + 1] = c;
     vertexColors[vertexIndex + 2] = c;
     vertexColors[vertexIndex + 3] = c;
    }

    // Update Geometry
    m_TextMeshPro.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
    */
   }

  }
  else
  {
   // Restore any character that may have been modified
   if (m_lastIndex != -1)
   {
    RestoreCachedVertexAttributes(m_lastIndex);
    m_lastIndex = -1;
   }
  }
 }

 // ----------------------------------------------------------------------------
 public void OnPointerEnter(PointerEventData eventData)
 {
  isHoveringObject = true;
 }

 // ----------------------------------------------------------------------------
 public void OnPointerExit(PointerEventData eventData)
 {
  //Debug.Log("OnPointerExit()");
  isHoveringObject = false;
 }

 // ----------------------------------------------------------------------------
 public void OnPointerClick(PointerEventData eventData)
 {
        // Check if Mouse intersects any words and if so assign a random color to that word.
        int linkIndex = TMP_TextUtilities.FindIntersectingLink(m_TextMeshPro, Input.mousePosition, m_Camera);
  if (linkIndex != -1)
  {
   //TMP_LinkInfo linkInfo = m_TextMeshPro.textInfo.linkInfo[linkIndex];
   Debug.Log("(On Pointer Click) - Selected Link ID: " + m_selectedLink);
   Debug.Log("Mouse position - X: " + Input.mousePosition.x + ", Y: " + Input.mousePosition.y);
  }
 }

 // ----------------------------------------------------------------------------
 public void OnPointerUp(PointerEventData eventData)
 {
  //Debug.Log("OnPointerUp()");
 }

 // ----------------------------------------------------------------------------
 void RestoreCachedVertexAttributes(int index)
 {
  if (index == -1 || index > m_TextMeshPro.textInfo.characterCount - 1) return;

  // Get the index of the material / sub text object used by this character.
  int materialIndex = m_TextMeshPro.textInfo.characterInfo[index].materialReferenceIndex;

  // Get the index of the first vertex of the selected character.
  int vertexIndex = m_TextMeshPro.textInfo.characterInfo[index].vertexIndex;

  // Restore Vertices
  // Get a reference to the cached / original vertices.
  Vector3[] src_vertices = m_cachedMeshInfoVertexData[materialIndex].vertices;

  // Get a reference to the vertices that we need to replace.
  Vector3[] dst_vertices = m_TextMeshPro.textInfo.meshInfo[materialIndex].vertices;

  // Restore / Copy vertices from source to destination
  dst_vertices[vertexIndex + 0] = src_vertices[vertexIndex + 0];
  dst_vertices[vertexIndex + 1] = src_vertices[vertexIndex + 1];
  dst_vertices[vertexIndex + 2] = src_vertices[vertexIndex + 2];
  dst_vertices[vertexIndex + 3] = src_vertices[vertexIndex + 3];

  // Restore Vertex Colors
  // Get a reference to the vertex colors we need to replace.
  Color32[] dst_colors = m_TextMeshPro.textInfo.meshInfo[materialIndex].colors32;

  // Get a reference to the cached / original vertex colors.
  Color32[] src_colors = m_cachedMeshInfoVertexData[materialIndex].colors32;

  // Copy the vertex colors from source to destination.
  dst_colors[vertexIndex + 0] = src_colors[vertexIndex + 0];
  dst_colors[vertexIndex + 1] = src_colors[vertexIndex + 1];
  dst_colors[vertexIndex + 2] = src_colors[vertexIndex + 2];
  dst_colors[vertexIndex + 3] = src_colors[vertexIndex + 3];

  // Restore UV0S
  // UVS0
  Vector2[] src_uv0s = m_cachedMeshInfoVertexData[materialIndex].uvs0;
  Vector2[] dst_uv0s = m_TextMeshPro.textInfo.meshInfo[materialIndex].uvs0;
  dst_uv0s[vertexIndex + 0] = src_uv0s[vertexIndex + 0];
  dst_uv0s[vertexIndex + 1] = src_uv0s[vertexIndex + 1];
  dst_uv0s[vertexIndex + 2] = src_uv0s[vertexIndex + 2];
  dst_uv0s[vertexIndex + 3] = src_uv0s[vertexIndex + 3];

  // UVS2
  Vector2[] src_uv2s = m_cachedMeshInfoVertexData[materialIndex].uvs2;
  Vector2[] dst_uv2s = m_TextMeshPro.textInfo.meshInfo[materialIndex].uvs2;
  dst_uv2s[vertexIndex + 0] = src_uv2s[vertexIndex + 0];
  dst_uv2s[vertexIndex + 1] = src_uv2s[vertexIndex + 1];
  dst_uv2s[vertexIndex + 2] = src_uv2s[vertexIndex + 2];
  dst_uv2s[vertexIndex + 3] = src_uv2s[vertexIndex + 3];


  // Restore last vertex attribute as we swapped it as well
  int lastIndex = (src_vertices.Length / 4 - 1) * 4;

  // Vertices
  dst_vertices[lastIndex + 0] = src_vertices[lastIndex + 0];
  dst_vertices[lastIndex + 1] = src_vertices[lastIndex + 1];
  dst_vertices[lastIndex + 2] = src_vertices[lastIndex + 2];
  dst_vertices[lastIndex + 3] = src_vertices[lastIndex + 3];

  // Vertex Colors
  src_colors = m_cachedMeshInfoVertexData[materialIndex].colors32;
  dst_colors = m_TextMeshPro.textInfo.meshInfo[materialIndex].colors32;
  dst_colors[lastIndex + 0] = src_colors[lastIndex + 0];
  dst_colors[lastIndex + 1] = src_colors[lastIndex + 1];
  dst_colors[lastIndex + 2] = src_colors[lastIndex + 2];
  dst_colors[lastIndex + 3] = src_colors[lastIndex + 3];

  // UVS0
  src_uv0s = m_cachedMeshInfoVertexData[materialIndex].uvs0;
  dst_uv0s = m_TextMeshPro.textInfo.meshInfo[materialIndex].uvs0;
  dst_uv0s[lastIndex + 0] = src_uv0s[lastIndex + 0];
  dst_uv0s[lastIndex + 1] = src_uv0s[lastIndex + 1];
  dst_uv0s[lastIndex + 2] = src_uv0s[lastIndex + 2];
  dst_uv0s[lastIndex + 3] = src_uv0s[lastIndex + 3];

  // UVS2
  src_uv2s = m_cachedMeshInfoVertexData[materialIndex].uvs2;
  dst_uv2s = m_TextMeshPro.textInfo.meshInfo[materialIndex].uvs2;
  dst_uv2s[lastIndex + 0] = src_uv2s[lastIndex + 0];
  dst_uv2s[lastIndex + 1] = src_uv2s[lastIndex + 1];
  dst_uv2s[lastIndex + 2] = src_uv2s[lastIndex + 2];
  dst_uv2s[lastIndex + 3] = src_uv2s[lastIndex + 3];

  // Need to update the appropriate 
  m_TextMeshPro.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
 }
}

Tuesday, May 15, 2018

CommandInvokationFailure: While Compiling for Android

While compiling for Android I got the following error:

CommandInvokationFailure: Failed to build apk. See the Console for details.
C:\Program Files\Java\jdk-10.0.1\bin\java.exe -Xmx2048M -Dcom.android.sdkmanager.toolsdir="C:/Program Files (x86)/Android/android-sdk\tools" -Dfile.encoding=UTF8 -jar "C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\sdktools.jar"


Solution:

Use Java JDK 8. 

It seems that Unity 5.3.8 doesn't like JDK 9 or higher.
Downloaded 
jdk-8u171-windows-x64 from Oracle and install it.

Then in Unity under Edit > Preferences > External Tools point Unity to JDK 8.


Android SDK is outdated

I finished making the make screens for the game and it runs well when compiled for PC. Ultimately I want the game to run on Android and iOS so I thought I'd compile an APK file and try and get it running on my Samsung S6.

After following the instructions I found here: Building your Unity game to an Android device for testing

I installed Java JDK and Android Studio and pointed Unity to the tools directory that contains the Android SDK.


The Problem


However when I compiled for Android I kept getting the following messages:

"Android SDK is outdated" and "sdk tools version 23 < 24".

Unity then asked me if I wanted to update and after replying "yes" it went off, looped around a bit and then came back with same messages.



The Solution


All that was needed was for Unity to be running in Administrator mode.
Once in Administrator mode Unity managed to download what it needed and continue compiling.

So I decided that I want to make a game in Unity 3D


A Brief Prologue

I've been thinking about this game for about a year now and I've dabbled with Unity 3D on and off over a couple of years. A few years ago I started a Udemy course in Unity which I found pretty good. I only completed the 2D section which I think is all I need to make this game. Link: Complete C# Unity Developer 2D - Learn to Code Making Games

I have a background in programming and graphic design and I've worked a few years in the gaming industry so I'm hoping I know what I'm getting myself and I'm not going to bite off more than I can chew, which is often the case with wanna be game developers.

Anyway I'm not going to go into any detail about what this game is about as that is not the purpose of the blog.

The Purpose of this Blog

The purpose of this blog or rather Dev Diary is to catalogue the problems and solutions I encounter while making this game. This is for both myself as much as for anyone reading this - as I know from experience that I will solve many issues and forget how I solved them when I come across them again.

Also

This is the first time I've used Blogger so things may look a little rough for awhile.