How does one shake the GUI?

What the title says. Is there any way to achieve a screen-shaking effect on the UnityGUI? Google gets me a few responses for shaking a camera in general, but from what I gather, that moves the position of the camera and wouldn’t affect the GUI at all.

If someone answers, I’d much prefer C#, since I don’t know any of the other supported programming languages.

A mathematical approach would be to use some cos or sin function, if you don’t want to go into iTween:

var pos :float;
var amp : int;  
var omega : float;


function Update(){
pos = amp*Mathf.Cos(omega*Time.time);
}

function OnGUI()
{
    var sW = Screen.width;
    var sH = Screen.height;
    // Your gui receives pos as x position, it will oscillates left to right and back.
    GUILayout.BeginArea(Rect(pos,transform.position.y,sW*.9,sH*.9));

    //GUI STUFF
    GUILayout.Button ("Click me");
    GUILayout.Button ("Or me");

    GUILayout.EndArea();
}

amp is how far you want it to move, omega is how fast you want it to move.

Also, if you want to make it go bling and then slowly get back use a damping.

A quite straight forward way is to manipulate the GUI.matrix.

function OnGUI()
{
    var pos : Vector3 = [Shake x and y]
    GUI.matrix = Matrix4x4.SetTRS(pos, Quaternion.identity, Vector3.one);
    // any GUI stuff
}

You can of course also shake the rotation by using a quaternion. There’s also the function GUIUtility.RotateAroundPivot which also manipulates the GUI matrix but helps you to rotate around a certain point.

If you want just a part of the GUI to shake you have to use a group that contains the stuff to shake like @fafase and @lttldude9 mentioned.

It works the same way for non GUILayout but you have to use GUI.BeginGroup and GUI.EndGroup instead. Keep in mind that elements between BeginGroup and EndGroup are relative the the groups position.

I think the following would be simple and effective:

var shakeAmount=30;
var shareOffset: int=0;
 
if(bShake)
{
   var duration = .50;
   var lerp : float = Mathf.PingPong (Time.time, duration) / duration;
   shareOffset=Mathf.Lerp(0,shakeAmount,lerp);
}

So just add the offset to every standalone GUI item or container (ie you dont need to shake an item if you’ve shaken the container its in):

GUI.Button( Rect (x+shareOffset,y,z) , "Button");

More things in containers obviously the better.

Are you familiar with iTween?

I made an example of how to shake the GUI. It’s in JS, but it’s so simple you could figure out the C#.

Pretty much attach the GUI script to an object with only a transform component. The only prep work is putting all your GUI in some sort of container like GUILayout.BeginArea. Either run the iTween on start or something, or really you can call the iTween from any script, just change the “gameObject” to this game object.

Here it is:

var amount : float;
var duration : float;

function Start()
{
	iTween.ShakePosition(gameObject, Vector3(amount,amount,0), duration);
}

function OnGUI()
{
	var sW = Screen.width;
	var sH = Screen.height;
	
	GUILayout.BeginArea(Rect(transform.position.x,transform.position.y,sW*.9,sH*.9));
	
	//GUI STUFF
	GUILayout.Button ("Click me");
	GUILayout.Button ("Or me");
	
	GUILayout.EndArea();
}

Edit: Also make sure that empty GameObject’s x and y position is at 0. Also the GUI doesn’t have to be on this gameObject, it could be on the camera or whatever, just need to reference the shaking object in GUI script