How can i script a wiggle?

Hi folks,

I’m trying to script a “wiggle” like After Effects wiggle expression (After Effects: Create a wiggle effect - YouTube), but i dont have it yet.

So, if i use a Random number, this is going to give me a random number each frame. I do not want this, because the number “jumps” each frame to the new random number. I want an expression that moves my number randomly but also that allows me to control the frequency on time and that my number moves smooth from one to the other random number. Like a lerp.

If you know the After Effects wiggle expression, you are going to know what i am talking about.

I would appreciate any help.

Hi, I'm not sure what you mean about been smooth.. You have total control of the smoothness with the speed & AnimationCurve, you can use an ease-in-out to make a smooth elastic effect. To add rotation to the script I've already done, it should be pretty easy. Let us know if that's what you want.

Oh, sorry. i did not use the Animation Curve in my test, therefore i did not see any smoothness in the movements. Well, when i assign a curve on the inspector i get this problem: transform.position assign attempt for 'Cube' is not valid. Input position is { NaN, NaN, NaN }. UnityEngine.Transform:set_position(Vector3) Do you know what's happening?

Sounds like transform.position is been given an invalid vector.. Really can't understand how that would happen, unless randomToPos has not been called. You got a simple demo I could look at.?

4 Answers

4

Hi, here’s a little wiggle script I knocked up…

My first Script in Unity, and it seems to work… Crikey!!.

Just attach the script to any object,.

Set the curve you want to use, eg. Linear, ease-in, ease-out

Set what you want to Wiggle by in the Distance, you can make it wiggle in the x,y & z.

Set the speed, eg. 0.5 would wiggle 2 times a second.

using UnityEngine;
using System.Collections;

public class Wiggle : MonoBehaviour {

	public AnimationCurve curve;
	public Vector3 distance;
	public float speed;

	private Vector3 startPos, toPos;
	private float timeStart;

	void randomToPos() {
		toPos = startPos;
		toPos.x += Random.Range(-1.0f, +1.0f) * distance.x;
		toPos.y += Random.Range(-1.0f, +1.0f) * distance.y;
		toPos.z += Random.Range(-1.0f, +1.0f) * distance.z;
		timeStart = Time.time;
	}

	// Use this for initialization
	void Start () {
		startPos = transform.position;
		randomToPos();
	}
	
	// Update is called once per frame
	void Update () {
		float d = (Time.time - timeStart) / speed, m = curve.Evaluate(d);
		if (d > 1) {
			randomToPos();
		} else if (d < 0.5) {
			transform.position = Vector3.Lerp(startPos, toPos, m * 2.0f);
		} else {
			transform.position = Vector3.Lerp(toPos, startPos, (m - 0.5f) * 2.0f);
		}
	}
}

Hi, i tried to attach this script to an object and it says an error : [165785-wiggle.png|165785] Any idea what I can do? Thank you!

For MonoBehaviours the class name must fit the file name, so if you want to call your filr WiggleFX.cs, it must say public class WiggleFX : MonoBehaviour.

If anyone is still interested, I created a fairly simple non-linear wiggle:

public float speed = 1;
public float amplitude = 2;
public int octaves = 4;

Vector3 destination;
int currentTime = 0;

void FixedUpdate ()
{
	// if number of frames played since last change of direction > octaves create a new destination
	if (currentTime > octaves)
	{
		currentTime = 0;
		destination = generateRandomVector(amplitude);
		print("new Vector Generated: " + destination);
	}
		   
	// smoothly moves the object to the random destination
	transform.position = Vector3.SmoothDamp(transform.position, destination, ref vel, speed);

	currentTime++;
}

// generates a random vector based on a single amplitude for x y and z
Vector3 generateRandomVector(float amp)
{
	Vector3 result = new Vector3();
	for (int i = 0; i < 3; i++)
	{
		float x = Random.Range(-amp, amp);
		result *= x;*
  • }*
  • return result;*
    }

Hello, this script looks great! But I was wondering... how can I obtain the same thing, but for the color alpha of my sprite? I mean, not wiggling it in space, but wiggling its opacity keeping it in the same position. Thanks a lot! (sorry I'm a bit of a noob with script)

cowemoji’s had a few issues for me, so I’ve cleaned it up, given you the choice to loop back or not, and removed any issues with signed/unsigned rotations

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Wiggle : MonoBehaviour
{
    [Header("Animation Size")]
    public float animationLoopTime = 1.0f;
    public float posRange = 2.0f;
    public float rotRange = 1.0f;

    [Header("Settings")]
    public bool noZMove = true;
    public bool shouldReturnToStart = false;
    public bool lockRotToZ = false;

    Vector3 initPos, initRot, startPos, startRot, endPos, endRot;
    float timePassed;

    // Use this for initialization
    void Start()
    {
        initPos = startPos = transform.position;
        initRot = startRot = transform.localRotation.eulerAngles;

        SetNewPositions();
    }

    float RandomFromOrderCorrectedRange(float a, float b)
    {
        if (a > b)
        {
            return Random.Range(b, a);
        }
        else
        {
            return Random.Range(a, b);
        }
    }

    void SetNewPositions()
    {
        if (shouldReturnToStart)
        {
            startPos = initPos;
            startRot = initRot;
        }
        else
        {
            startPos = transform.position;
            startRot = transform.localRotation.eulerAngles;
        }

        endPos = new Vector3(
              RandomFromOrderCorrectedRange(initPos.x - posRange, initPos.x + posRange),
              RandomFromOrderCorrectedRange(initPos.y - posRange, initPos.y + posRange),
              noZMove ? 0 : RandomFromOrderCorrectedRange(initPos.z - posRange, initPos.z + posRange)
          );

        endRot = new Vector3(
            lockRotToZ ? 0 : RandomFromOrderCorrectedRange(initRot.x - rotRange, initRot.x + rotRange),
            lockRotToZ ? 0 : RandomFromOrderCorrectedRange(initRot.y - rotRange, initRot.y + rotRange),
            RandomFromOrderCorrectedRange(initRot.z - rotRange, initRot.z + rotRange)
        );
    }

    // Update is called once per frame
    void Update()
    {
        timePassed += Time.deltaTime / animationLoopTime;



        if (timePassed < 0.5f)
        {
            transform.position = Vector3.Lerp(startPos, endPos, timePassed * 2f);
            transform.localRotation = Quaternion.Lerp(Quaternion.Euler(startRot), Quaternion.Euler(endRot), timePassed * 2f);
        }
        else if (shouldReturnToStart && timePassed < 1.0f)
        {
            // tween back
            float pct2 = (1.0f - timePassed) * 2f;
            transform.position = Vector3.Lerp(startPos, endPos, pct2);
            transform.localRotation = Quaternion.Lerp(Quaternion.Euler(startRot), Quaternion.Euler(endRot), pct2);

        }
        else if (!shouldReturnToStart || timePassed >= 1.0f)
        {
            timePassed = 0;
            SetNewPositions();
            return;
        }

    }
}

Here’s another one for anyone from Google

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class wiggle : MonoBehaviour {

	float startTime;
	public float animDur = 1.0f;

	Vector3 startPos, endPos;
	public float posRange = 2.0f;
	public bool noZMove = true;

	Vector3 startRot, endRot;
	public float rotRange = 1.0f;
	public bool lockRotToZ = false;

	// Use this for initialization
	void Start()
	{
		startPos = transform.position;
		startRot = transform.eulerAngles;

		makeNewEnds();
	}

	float randomRange(float a, float b)
	{
		if (a > b)
		{
			return Random.Range(b, a);
		}
		else
		{
			return Random.Range(a, b);
		}
	}

	void makeNewEnds()
	{
		startTime = Time.time;

		endPos = new Vector3(
			randomRange(startPos.x-posRange, startPos.x+posRange),
			randomRange(startPos.y-posRange, startPos.y+posRange),
			noZMove? 0 : randomRange(startPos.z-posRange, startPos.z+posRange)
		);

		endRot = new Vector3(
			lockRotToZ? 0 : randomRange(startRot.x-rotRange, startRot.x+rotRange),
			lockRotToZ? 0 : randomRange(startRot.y-rotRange, startRot.y+rotRange),
			randomRange(startRot.z-rotRange, startRot.z+rotRange)
		);
	}

	// Update is called once per frame
	void Update()
	{
		float timePassed = Time.time - startTime;
		float pctComplete = timePassed / animDur;

		if (pctComplete >= 1.0f)
		{
			makeNewEnds();
			return;
		}

		if (pctComplete < 0.5f)
		{
			transform.position = Vector3.Lerp(startPos, endPos, pctComplete*2f);
			transform.eulerAngles = Vector3.Lerp(startRot, endRot, pctComplete*2f);
		}
		else
		{
			// tween back
			float pct2 = (1.0f - pctComplete) * 2f;
			transform.position = Vector3.Lerp(startPos, endPos, pct2);
			transform.eulerAngles = Vector3.Lerp(startRot, endRot, pct2);
		}
	}
}

this works for me! thanks