" OnMouseDown()" or " OnMouseUp" On GUIT

Hello, i’ve read in many post that OnMouseUp() should work in Unity iPhone the same as in regular unity. Since in my case it doesn’t i’d very much like to know if for somebody does work, so maybe i just have to reinstall unity.
Else how do I use GUITextures as buttons ??

Please help!

The simple solution is to fully use GUI.xxx

What would be nice is if OnMouse calls worked in the gui system. I cant follow the equivilent for these in the newer gui system and Im still saddened that the origional gui will get scrapped. I really need OnMouseDown/OnMouseUp type stuff. Simple, Works, Unity. I hope UT remembers the artists out there that dont really like having to wade through lengthy code when we just want a button to work. Simple is good, real good.

/2c
AC

OnMouseDown/OnMouseUp() are disabled in iPhone Unity for performance reasons.

You can use following C# code to find GUI element under the touch:

GUIElement FindGUIElement(Camera camera, Vector3 mousePosition)
{
	// Is the mouse inside the cameras viewport?
	Rect rect = camera.pixelRect;
	if (!rect.Contains (mousePosition))
		return null;

	// Did we hit any gui elements?
	GUILayer layer = (GUILayer)camera.GetComponent (typeof (GUILayer));
	if (!layer)
		return null;

	return layer.HitTest (mousePosition);
}

If you want to simulate OnMouseDown in the old way, then you can do :

if (Input.GetMouseButtonDown(0))
{
	GUIElement element = FindGUIElement(MainCamera, Input.mousePosition);
	if (element) element.SendMessage("OnMouseDown");
}

thanks a lot the code, i had begun creating box colliders for all my gui elements, but it was a bore to place them. As soon as i will get to my computer I will try it!
Thanks again!

  • Update - Hum… actually i know very little about c, and don’t manage to implement your script. I’ve created a new c sharp script but it doesn’t compile…
    How should i use it?

Thanks to all for the interest and help and especially ReJ for the code, but i’m really a beginner…

Ok now everything works, i had to change “MainCamera” with “Camera.main”.

here i post the full code of the c sharp script you have to assign to a gameObject to have “OnMouseUp()” or “OnMouseDown()” on GUITextures just as in regular Unity.
Thanks a lot to ReJ for the code!

using UnityEngine;
using System.Collections;




public class TouchController2 : MonoBehaviour {
	
	 GUIElement FindGUIElement(Camera camera, Vector3 mousePosition){
   // Is the mouse inside the cameras viewport? 
   Rect rect = camera.pixelRect; 
   if (!rect.Contains (mousePosition)) 
      return null; 

   // Did we hit any gui elements? 
   GUILayer layer = (GUILayer)camera.GetComponent (typeof (GUILayer)); 
   if (!layer) 
      return null; 

   return layer.HitTest (mousePosition); 
	 }
	

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		
 
   
   if (Input.GetMouseButtonDown(0)) 
{ 
   GUIElement element = FindGUIElement( Camera.main, Input.mousePosition); 
   if (element)
    element.SendMessage("OnMouseUp"); // change to "OnMouseDown" if needed
}
}
}

Interestingly enough, I get much better performance by removing my GUI.Buttons and replacing them with GUITextures using a variant of this (ReJ’s) script. As an added benefit these buttons also work with the Unity Remote with no problem.

Am I the only one finding GUI.x and OnGUI to be unresponsive and a real resource hog? In an empty project it works fine, but as soon as you have some complexity weird things start happening with the performance. My project was dropping 10-12 FPS when dragging your finger anywhere on the screen earlier this weekend. Otherwise it ran at a solid 30fps, only when dragging your finger did it drop frames. This was in a project that was not checking or responding to input in any way other than checking the touch count, and OnGUI() consisted of 3 empty GUI.Buttons being created. (I was also using the ‘this.useGUILayout = false;’ trick) Comment out the GUI.Buttons, frame drop problem would go away.

Now tonight I swap out the buttons with these, and presto - almost no frame hit when dragging (.5 to 1 frame drop). The buttons actually feel more responsive too, and aren’t nearly as stubborn to trigger.

Sure, GUI.Buttons and GUI.xxx stuff is much heavier than GUITexture. Parts of GUI.xxx are written in C# and rendering is much more complicated due to custom skins.

I would advice against using any GUI.xxx in-game, but only for menus and other parts which don’t require steady 30/20/15fps. Just use GUITexture in game.

Ok ReJ, going forward I will only use GUITextures for UI items in-game. I was using the GUI.x stuff because, from everything I had read, GUIText and GUITexture were being phased out and no longer ‘supported’.

The problem I’m running into does still seem like a bug with the GUI.x code, however. After some further testing I was able to re-create the problem with a barebones scene - after some further testing I’ll submit it with the bug tools. It seems that once a scene hits 15 draw calls or more, GUI.Button (and possibly more GUI.x) controls cause large drops in framerate when dragging your finger(s) anywhere on the screen. Stationary touches continue to have no effect. In my barebones test scene, with 1.5k static untextured tris and 15 draw calls, dragging my finger drops 10-15 frames per second.

I worked on the script some more to seperate between OnMouseUp and OnMouseDown
(it can also detect OnMouseOver and OnMouseExit though probably most will not need those in their iphone apps so its toggled off by default :slight_smile: ).
Just save it as GUITouchController.cs, slap it onto a gameObject and then you can have scripts on your guiTextures etc with function OnMouseDown, OnMouseUp etc :slight_smile:

using UnityEngine; 
using System.Collections; 

//todo: iterate throw multiple prevFrame items in array
//todo: check if pref frame items still exist
//todo: add optional constant check option

public class GUITouchController : MonoBehaviour { 

    public bool detectOnMouseOver = false;
    private bool wasMouseDownInPrevFrame = false;
    private bool wasMouseOverInPrevFrame = false;
    private GUIElement prevFrameElement;
    
    GUIElement FindGUIElement(Camera camera, Vector3 mousePosition){ 
   // Is the mouse inside the cameras viewport? 
   Rect rect = camera.pixelRect; 
   if (!rect.Contains (mousePosition)) 
      return null; 

   // Did we hit any gui elements? 
   GUILayer layer = (GUILayer)camera.GetComponent (typeof (GUILayer)); 
   if (!layer) 
      return null; 

   return layer.HitTest (mousePosition); 
    } 
    

   // Use this for initialization 
   void Start () { 
    
   } 
    
    // Update is called once per frame 
	void Update () { 
		if(detectOnMouseOver){
			GUIElement element = FindGUIElement( Camera.main, Input.mousePosition); 
			if (element){ 
				if (!wasMouseOverInPrevFrame){
					wasMouseOverInPrevFrame = true;
					element.SendMessage("OnMouseOver",null,SendMessageOptions.DontRequireReceiver);
				} 
				if (Input.GetMouseButtonDown(0)){ 
					if(!wasMouseDownInPrevFrame){
						wasMouseDownInPrevFrame = true;
						element.SendMessage("OnMouseDown",null,SendMessageOptions.DontRequireReceiver); 
					}
				}else if(wasMouseDownInPrevFrame){
					if (!Input.GetMouseButton(0)){ 
						element.SendMessage("OnMouseUp",null,SendMessageOptions.DontRequireReceiver);
						wasMouseDownInPrevFrame = false;
					}
				} 
				prevFrameElement = element;	
			}else if (wasMouseOverInPrevFrame){
				prevFrameElement.SendMessage("OnMouseExit",null,SendMessageOptions.DontRequireReceiver); 	
				wasMouseOverInPrevFrame = false;
			} 
		
		}else{
   			//only detect OnMouseDown and OnMouseUp, not also OnMouseOver and OnMouseExit to save performance (by only looking for gui elements when mouse button is pressed)
			if (Input.GetMouseButtonDown(0)){ 
				GUIElement element = FindGUIElement( Camera.main, Input.mousePosition); 
				if (element){ 
					if(!wasMouseDownInPrevFrame){
						wasMouseDownInPrevFrame = true;
						element.SendMessage("OnMouseDown",null,SendMessageOptions.DontRequireReceiver); 
						prevFrameElement = element;		
					}			
				} 
			}else if(wasMouseDownInPrevFrame){
				if (!Input.GetMouseButton(0)){ 
					prevFrameElement.SendMessage("OnMouseUp",null,SendMessageOptions.DontRequireReceiver);
					wasMouseDownInPrevFrame = false;
				}
			}    			
   		}
   	}
	

}

[/code]

Oh Man! I’ve been working for HOURS trying to get OnMouseDown working on iPhone and I just couldn’t make it work until I read this post that said that it’s disabled on the iPhone! Well, it would have been nice to write it in the documentation. What else doesn’t work on the iPhone? Anyway, Tommosaur just saved my life. Thanks for the script!

cheers, i´m glad it was helpful :slight_smile:

One problem fixed, another one poping up… Usually I would add a script to the object that would be animated. Like onMouseDowm play whatever animation. But now I use your script on a GUI Texture and I need that button to drive the animation of another asset. How do I do that? Or what if I want to drive the animation on 5 different assets?

That’s the last issue I need to fix in order to finish my game.

Thanks,

Robert

you would add scripts to those 5 objects that have a specific function lets say “DoAnimation”

Then on your ongui you would search for those 5 objects (FindObjectsOfType(typeof()) returns an array with all of them), then you would call DoAnimation on them

yeah… well… for a guy who’s been working with Unity for only a week during the evenings, that may be a little difficult for me at this moment but I will give it a try. Unless you would be kind enough to make me a little example scene :roll:

Cheers,

Robert

Ok, this system seems all very good and well…
until I try to layout my GUI! My objects (my buttons etc) by default are huge, and at the moment I’m just ‘guessing’ the size and position but it’s not very helpful when I want a pixel-perfect layout.

GUITexture is a component of GameObject, so correct me if I’m wrong, I have to create one GameObject for every GUITexture.

The two ways to adjust the size of the texture on screen would be via GameObject.transform.localscale or via the pixelInset property of the GUITexture. I can’t get either to work logically. Also, depending on the ratio of my window, the GUITextures appear at different ratios too! (Image attached - which u have to log in to see)

Is there something I’m missing? One thing that would be helpful too would be to set my Game View to be the size of the iPhone screen (ie: 480 x 320)…

Any help would be much appreciated!

public class GUITouchController2 : MonoBehaviour {

	public Texture2D testBtnTexture;
	private Rect btnRect;
	
	private GUITexture myBtn;
	
	void Start(){

		GameObject tempObj = new GameObject();
		
		myBtn = (GUITexture)(tempObj.AddComponent("GUITexture"));
		myBtn.texture = testBtnTexture;
		myBtn.name = "theButton";
		
		//this doesn't work for placement..
		btnRect = new Rect(100, 100, testBtnTexture.width, testBtnTexture.height);
		myBtn.pixelInset = btnRect;
		
	}

[/img]

121468--4579--$guitextureprob_145.jpg

This one is a little hard to wrap your head around (was for me). That is:
You set the x,y position of the transform.position (in 3 space) the z position gets ignored I guesss.

Alternately you can setup the guitexture in the editor, and have it pre-instantiated by a slot (public variable)
in your script:
Here is a script I wrote tonight for a similar purpose

//-------------------------------------------------------------------------------
// TurnChoiceButton.js
// A GUITexture to act as button for alternately: 
// Draw button
// Pass button
// Cancel button
// one button combined for all of these (1 model - 3 textures)
//------------------------------------------------------------------------------
#pragma strict

enum ButtonMode 
{
	Draw,
	Pass,
	Cancel,
	Hidden
};


// editor outlets:
var drawButtonTexture : Texture2D;
var passButtonTexture : Texture2D;
var cancelButtonTexture : Texture2D;


// public vars:

// the player  to callback when the button is pressed
var player : Player;
static var instance : TurnChoiceButton;

// private vars:
private var _curMode : ButtonMode;

private var _guiTexture : GUITexture;
private var _guiLayer : GUILayer;

function Awake () 
{
	DontDestroyOnLoad(this);
	instance = this;
	
	// cache
	_guiTexture = gameObject.guiTexture;	

		
	// start off hidden:
	setMode( ButtonMode.Hidden );
}

function Start () 
{
	// cache
	_guiLayer = PlayerBones.instance.cam.GetComponent (typeof (GUILayer));	
}


function setMode ( mode : ButtonMode ) 
{
	_curMode = mode;
	
	_guiTexture.enabled = true;
	enabled = true;
	
	switch( _curMode ) 
	{
		case ButtonMode.Draw:
			_guiTexture.texture = drawButtonTexture;
			break;
			
		case ButtonMode.Pass:
			_guiTexture.texture = passButtonTexture;
			break;
							
		case ButtonMode.Cancel:
			_guiTexture.texture = cancelButtonTexture;
			break;
			
		case ButtonMode.Hidden:
			_guiTexture.enabled = false;
			enabled = false;
			break;
	}	
}

function getMode ()  : ButtonMode
{
	return _curMode;
}

function Update () 
{
	if( iPhoneInput.touchCount )
	{
	   	var element : GUIElement = _guiLayer.HitTest (Input.mousePosition);
		if(element == _guiTexture )
		{
			player.turnChoiceCallback( _curMode );
		}
	}
}

It’s used to determine which elements are in front of other elements, so you can layer them as you like.

As far as scale and such goes, if the scale of the object is set to 0, then it’s pixel-perfect and uses the pixel inset values as you would expect. If it’s non-zero, then the object is automatically resolution-independent and adjusts its size based on the view, and you should set the pixel inset values to 0. i.e., a GUITexture with a scale of 1,1 will fill up the entire screen no matter what size it is in pixels.

–Eric

Thanks for ur script mindlube :slight_smile:

And Eric! Saving my bacon once again - so u set the transform local scale to be zero, THEN it listens to the pixel inset param. Jee… not sure how I was going to guess that…! Tried it and it works a charm!

About pixelInset, the docs sayeth:

:slight_smile:

–Eric