Can anybody give me Example or Tutorial Video to achieve the effect in the video

Look at 1:28 Second.

You see when player takes the red shoe, it gives player an effect like this picture: 2667803--188214--asdf.png

I don’t know what’s the name of the effect and can’t find it on google. Kindly help me with this.

You can achieve this by instantiating a number of gameobjects or prefabs with a spriterenderer set to the current sprite frame of your character, and then fading it out quickly and destroying it or recycling it. You would instantiate them with a slight delay time, or base the instantiation on the distance the character has moved.

I’d recommend against instantiating and deleting gameObjects quickly like above. You’re probably better off just updating the animation frame and location of the one in the back. Say if you wanted the length of “clones” to be 3, after the 3rd one is updated the 1st placed sprite is moved and its frame updated.

For a small project it probably doesn’t matter but it’s a better habit to not go about instantiating and destroying objects all the time. This kind of goes along with why you shouldn’t instantiate bullets and delete them but instead keep them in a queue.

Instantiating and destroying, while inefficient, is a very straightforward concept, and I didn’t want to introduce object pooling or other potentially confusing subjects on the first go. I did mention recycling the objects as an alternative.

Instantiating and Destroying seems to be a very good idea. Thank you so much. Although I was thinking about Particle System… which one will be better? “Instantiating and Destroying” or “Particle System”, I need this effect only for player.

It’s a good idea until you are doing it too frequently. They are both heavy operations and it’s not efficient to be doing constantly.

I wouldn’t recommend using a particle system because it’s not possible to change the particle image per particle on the fly.

1 Like

Thank you for you suggestion.

This piqued my interest and I decided to take a shot at making it because I’ve always liked this effect.

This script will create as many objects as necessary to keep the loop going. It’s based on distance the player has moved which is what I think you want.

Put this component on your player, on the same object as the spriteRenderer you want to create a trail of. Enabling and Disabling the component will turn the effect on and off.

On the first run it will create as many objects as necessary, and subsequent runs will reuse those objects. There is an option to define a number of pre-created objects to lighten or eliminate the need to create more during the effect.

It’s not the most elegant code, but I did this very quickly. It should work nonetheless.

I took the liberty of commenting the living crap out of this so that hopefully anybody reading this will be able to follow the logic.

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

[RequireComponent(typeof(SpriteRenderer))]
public class SpriteAfterImageEffect : MonoBehaviour
{
    [Tooltip("The color each after-image will fade to over its lifetime. Alpha of 0 is recommended")]
    public Color finalColor = Color.clear;

    [Tooltip("The amount of time an after-image will take to fade away.")]
    public float trailLifetime = .25f;

    [Tooltip("The distance this object must move to spawn one after-image.")]
    public float distancePerSpawn = .1f;

    [Header("Optimization")]
    [Tooltip("The number of after-image objects pooled on Awake before the effect starts, to reduce the number of objects created while the effect is running.")]
    public int spawnOnStart = 0;

    // the sprite renderer to trail after
    private SpriteRenderer mainSpriteRenderer;

    // the list of objects ready to be shown
    private List<SpriteRenderer> readyObjects;

    // the distance this object has moved since the last object was shown
    private float distanceTraveledSinceLastSpawn;

    // the position of the last spawned object
    private Vector3 lastSpawnPosition;

    // original color before fading out
    private Color initialColor;
   
    // Called once by Unity when this object first loads
    private void Awake()
    {
        // get the sprite renderer on this object
        mainSpriteRenderer = GetComponent<SpriteRenderer>();

        // save the starting color of the sprite
        initialColor = mainSpriteRenderer.color;

        // initialize the empty list of sprite object references
        readyObjects = new List<SpriteRenderer>();

        // populate list beforehand with objects to use
        for(int i = 0; i < spawnOnStart; i++)
        {
            readyObjects.Add(makeSpriteObject());
        }
    }

    // Called by Unity when this component becomes enabled
    private void OnEnable()
    {
        // start the trail loop
        StartCoroutine(trailCoroutine());
    }

    // function to create a sprite gameobject ready for use
    private SpriteRenderer makeSpriteObject()
    {
        // create a gameobject named "TrailSprite" with a SpriteRenderer component
        GameObject spriteObject = new GameObject("TrailSprite", typeof(SpriteRenderer));

        // parent the object to this object so that it follows it
        spriteObject.transform.SetParent(transform);

        // center it on this object
        spriteObject.transform.localPosition = Vector3.zero;

        // deactivate it
        spriteObject.SetActive(false);

        return spriteObject.GetComponent<SpriteRenderer>();
    }

    // coroutine which drives the trailing effect
    private IEnumerator trailCoroutine()
    {
        // keep looping while this component is enabled
        while(enabled)
        {
            // get the distance between the current position and
            // the last position a sprite object was spawned
            distanceTraveledSinceLastSpawn = Vector2.Distance(lastSpawnPosition, transform.position);

            // if that distance is greater than the specified distance per spawn
            if(distanceTraveledSinceLastSpawn > distancePerSpawn)
            {
                // if there aren't any objects ready to show, spawn a new one
                if(readyObjects.Count == 0)
                {
                    // add that object's sprite renderer to the trail list
                    readyObjects.Add(makeSpriteObject());
                }

                // get the first object in the ready list
                SpriteRenderer nextObject = readyObjects[0];

                // set this sprite object to the current player's sprite
                nextObject.sprite = mainSpriteRenderer.sprite;

                // this makes it so that the trail will render behind the main sprite
                nextObject.sortingOrder = mainSpriteRenderer.sortingOrder - 1;

                // unparent it, making it no longer follow this object
                nextObject.transform.SetParent(null, true);

                // activate it
                nextObject.gameObject.SetActive(true);

                // start it fading out over time
                StartCoroutine(fadeOut(nextObject));

                // remove it from the list of ready objects
                readyObjects.Remove(nextObject);

                // save this position as the last spawned position
                lastSpawnPosition = transform.position;

                // reset the distance traveled
                distanceTraveledSinceLastSpawn = 0;
            }

            // wait until next frame to continue the loop
            yield return null;
        }
    }

    private IEnumerator fadeOut(SpriteRenderer sprite)
    {
        // variable to keep track of how much time has passed while this is going
        float timeElapsed = 0;

        // while the elapsed time is less than the specified trailLifetime
        while(timeElapsed < trailLifetime)
        {
            // get a number between 0 and 1 that represents how much time has passed
            // 0 = no time has passed, 1 = trailLifetime seconds has passed
            float progress = timeElapsed / trailLifetime;

            // linearly interpolate between the initial color and the final color
            // based on the value of progress (0 to 1 : initial to final)
            sprite.color = Color.Lerp(initialColor, finalColor, progress);

            // track the time passed since last frame
            timeElapsed += Time.deltaTime;

            // wait until next frame to continue the loop
            yield return null;
        }

        // now that the loop is done
        // reset the object so that it can be reused
        resetObject(sprite);
    }

    // resets the object so that it is ready to use again
    private void resetObject(SpriteRenderer sprite)
    {
        // deactivate the sprite
        sprite.gameObject.SetActive(false);

        // reset the tint to default
        sprite.color = initialColor;

        // parent it to this object
        sprite.transform.SetParent(transform);

        // center it on this object
        sprite.transform.localPosition = Vector3.zero;

        // add it to the ready list
        readyObjects.Add(sprite);
    }
}
1 Like

My most favorite kind of code! :wink:

1 Like

I added the options to specify a final color for the after-images, as well as a number of objects to pool on initialization as a minor optimization.

Thank you ULTRA VERY MUCH :stuck_out_tongue: Bro. It worked perfectly.

1 Like

Enjoy, let me know if you have any trouble with it, or if you need help tweaking the behavior.

1 Like