Friday, January 3, 2014

Unity Improved Touch Input - TouchLogicV2!


Check out the code below the videos



In this Unity tutorial we will improve our TouchLogic script (original here) making it more optimized for better performance. I will also rewrite and better explain a few things to solve any issues you may have had with the original.

NOTE: If you use this script, all previous scripts on my site were made using the old "TouchLogic", this is "TouchLogicV2". If you want to use this new method, you'll have to make some minor changes to the old scripts (Find and ReplaceAll instructions below)

To edit all your existing scripts in MonoDevelop to use our new TouchLogic: Hit Ctrl + Shift + F :: Replace in Files :: Find "void OnTouch" :: Replace "public override void OnTouch" :: Look in "Whole Solution" or "Current Project" should work :: Click Replace :: Go to File :: Save All. It should all be changed. Look in the "Search Results" that popped up at the bottom to make sure everything looks right.

Also, if you're child classes aren't going to use "Update" feel free to switch "CheckTouches" back to "Update". That was just an optional demonstration for those of you who needed "Update" in your child classes.

Time Breakdown:
  • 1:00 - Demonstration of "No Reciever" error messages
  • 2:00 - Explanation of why TouchLogic wasn't working if child class had an Update defined
  • 4:00 - (Optional) How to fix that multiple Update issue
  • 5:00 - (Optional) Disabling Touch Input at runtime
  • 6:55 - Fixing "No Reciever" error messages by setting up Virtual and Override methods in lieu of SendMessage... This is also faster, performance-wise, than SendMessage
  • 11:45 - Removing OnTouch3D functions for performance (we'll create a new script to handle this in a future tutorial)
  • 13:10 - Outro, overview of what we did, thanks for watching :D


  • Time Breakdown:
    • 0:55 - Description of demo scene and scripts
    • 2:00 - Demonstration of bug
    • 2:43 - How touch index identifies touches
    • 3:33 - How fingerID is different
    • 4:08 - Writing the actual fix
    • 5:08 - Demonstration of fix
    • 6:37 - Thanks for watching :D

    Support Further Tutorial Development
    Comments?
    Check out the videos above to hear the explanation and see the code in action
    /*/
    * Script by Devin Curry
    * www.Devination.com
    * www.youtube.com/user/curryboy001
    * Please like and subscribe if you found my tutorials helpful :D
    * Google+ Community: https://plus.google.com/communities/108584850180626452949
    * Twitter: https://twitter.com/Devination3D
    * Facebook Page: https://www.facebook.com/unity3Dtutorialsbydevin
    /*/
    using UnityEngine;
    using System.Collections;
    
    public class TouchLogicV2 : MonoBehaviour
    {
     public static int currTouch = 0;//so other scripts can know what touch is currently on screen
     [HideInInspector]
     public int touch2Watch = 64;
     public virtual void Update()//If your child class uses Update, you must call base.Update(); to get this functionality
     {
      //is there a touch on screen?
      if(Input.touches.Length <= 0)
      {
       OnNoTouches();
      }
      else //if there is a touch
      {
       //loop through all the the touches on screen
       foreach(Touch touch in Input.touches)
       {
        currTouch = touch.fingerId;
        //executes this code for current touch (i) on screen
        if(this.guiTexture != null && (this.guiTexture.HitTest(touch.position)))
        {
         //if current touch hits our guitexture, run this code
         if(touch.phase == TouchPhase.Began)
         {
          OnTouchBegan();
          touch2Watch = currTouch;
         }
         if(touch.phase == TouchPhase.Ended)
         {
          OnTouchEnded();
         }
         if(touch.phase == TouchPhase.Moved)
         {
          OnTouchMoved();
         }
         if(touch.phase == TouchPhase.Stationary)
         {
          OnTouchStayed();
         }
        }
        //outside so it doesn't require the touch to be over the guitexture
        switch(touch.phase)
        {
        case TouchPhase.Began:
         OnTouchBeganAnywhere();
         break;
        case TouchPhase.Ended:
         OnTouchEndedAnywhere();
         break;
        case TouchPhase.Moved:
         OnTouchMovedAnywhere();
         break;
        case TouchPhase.Stationary:
         OnTouchStayedAnywhere();
         break;
        }
       }
      }
     }
     //the default functions, define what will happen if the child doesn't override these functions
     public virtual void OnNoTouches(){}
     public virtual void OnTouchBegan(){print (name + " is not using OnTouchBegan");}
     public virtual void OnTouchEnded(){}
     public virtual void OnTouchMoved(){}
     public virtual void OnTouchStayed(){}
     public virtual void OnTouchBeganAnywhere(){}
     public virtual void OnTouchEndedAnywhere(){}
     public virtual void OnTouchMovedAnywhere(){}
     public virtual void OnTouchStayedAnywhere(){}
    }
    
    And an example of how to use it:
    using UnityEngine;
    using System.Collections;
    
    public class TestButton : TouchLogicV2 
    {
     public bool disableTouches;
     
     public override void Update()//(optional) only use Update if you need to
     {
      //you can do some logic before you check for the touches on screen
    
      if(!disableTouches)//(optional) dynamically change whether or not to check for touches
       base.Update();//must have this somewhere or TouchLogicV2's Update will be totally overwritten by this class's Update
     }
     
     public override void OnTouchBegan()
     {
      print ("HELLO FROM TEST BUTTON!");
     }
    }