Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Let us know a bit about your interests, and if you'd like to become more directly involved. Take our survey!
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

shadow clones(Castlevania style) 2D

Discussion in '2D' started by fosmark13, Jul 9, 2017.

  1. fosmark13

    fosmark13

    Joined:
    Feb 16, 2015
    Posts:
    91
    hi i was wondering if anyone can guide me through how i can create shadow clones for my character?? i just don't know how to achieve just like Castlevania Symphony of the Night, the way richter moves, it's awesome but i can't figure out how they made it since the shadow clone reacts to the sprite moves richter does. Here is a reference image of what i'm trying to explain.

    If someone could tell me a method or some info to achieve this would be great, i'll be in touch, thanks Captura de pantalla 2017-07-09 a la(s) 16.14.57.png to all.
     
  2. jeffreyschoch

    jeffreyschoch

    Joined:
    Jan 21, 2015
    Posts:
    2,305
    This has been asked for several times, so I'll just pass along a script I wrote awhile back.

    Put this on anything with a sprite renderer, enable/disable the component to turn it on and off.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class SpriteAfterImage : MonoBehaviour {
    6.     [Tooltip("The color each after-image will fade to over its lifetime. Alpha of 0 is recommended")]
    7.     public Color finalColor = Color.clear;
    8.     [Tooltip("The amount of time an after-image will take to fade away.")]
    9.     public float trailLifetime = .25f;
    10.     [Tooltip("The distance this object must move to spawn one after-image.")]
    11.     public float distancePerSpawn = .1f;
    12.     [Tooltip("Optimization - number of after-images to create before the effect starts, to reduce the start-up load.")]
    13.     public int spawnOnStart = 0;
    14.     private SpriteRenderer mainSpriteRenderer;    // the sprite renderer to trail after
    15.     private List<SpriteRenderer> readyObjects;    // the list of objects ready to be shown
    16.     private float distanceTraveledSinceLastSpawn; // the distance this object has moved since the last object was shown
    17.     private Vector3 lastSpawnPosition;            // the position the last object was spawned
    18.     private Color initialColor;
    19.     private void Awake() {
    20.         // get the sprite renderer on this object
    21.         mainSpriteRenderer = GetComponent<SpriteRenderer>();
    22.         initialColor = mainSpriteRenderer.color;
    23.         // initialize the empty list
    24.         readyObjects = new List<SpriteRenderer>();
    25.         // optionally populate list beforehand with objects to use
    26.         for(int i = 0; i < spawnOnStart; i++) {
    27.             readyObjects.Add(makeSpriteObject());
    28.         }
    29.     }
    30.     private void OnEnable() {
    31.         StartCoroutine(trailCoroutine());
    32.     }
    33.     // function to create a sprite gameobject ready for use
    34.     private SpriteRenderer makeSpriteObject() {
    35.         // create a gameobject named "TrailSprite" with a SpriteRenderer component
    36.         GameObject spriteObject = new GameObject("TrailSprite", typeof(SpriteRenderer));
    37.         // parent the object to this object so that it follows it
    38.         spriteObject.transform.SetParent(transform);
    39.         // center it on this object
    40.         spriteObject.transform.localPosition = Vector3.zero;
    41.         // hide it
    42.         spriteObject.SetActive(false);
    43.         return spriteObject.GetComponent<SpriteRenderer>();
    44.     }
    45.     private IEnumerator trailCoroutine() {
    46.         // keep running while this component is enabled
    47.         while(enabled) {
    48.             // get the distance between the current position and the last position
    49.             // a trail object was spawned
    50.             distanceTraveledSinceLastSpawn = Vector2.Distance(lastSpawnPosition, transform.position);
    51.             // if that distance is greater than the specified distance per spawn
    52.             if(distanceTraveledSinceLastSpawn > distancePerSpawn) {
    53.                 // if there aren't any objects ready to show, spawn a new one
    54.                 if(readyObjects.Count == 0) {
    55.                     // add that object's sprite renderer to the trail list
    56.                     readyObjects.Add(makeSpriteObject());
    57.                 }
    58.                 // get the next object in the ready list
    59.                 SpriteRenderer nextObject = readyObjects[0];
    60.                 // set this trailSprite to reflect the current player sprite
    61.                 nextObject.sprite = mainSpriteRenderer.sprite;
    62.                 // this makes it so that the trail will render behind the main sprite
    63.                 nextObject.sortingLayerID = mainSpriteRenderer.sortingLayerID;
    64.                 nextObject.sortingOrder = mainSpriteRenderer.sortingOrder - 1;
    65.                 // set it loose in the world
    66.                 nextObject.transform.SetParent(null, true);
    67.                 // match the copy's scale to the sprite's world-space scale
    68.                 nextObject.transform.localScale = mainSpriteRenderer.transform.lossyScale;
    69.                 // show it
    70.                 nextObject.gameObject.SetActive(true);
    71.                 // start it fading out over time
    72.                 StartCoroutine(fadeOut(nextObject));
    73.                 // remove it from the list of ready objects
    74.                 readyObjects.Remove(nextObject);
    75.                 // save this position as the last spawned position
    76.                 lastSpawnPosition = transform.position;
    77.                 // reset the distance traveled
    78.                 distanceTraveledSinceLastSpawn = 0;
    79.             }
    80.             // wait until next frame to continue the loop
    81.             yield return null;
    82.         }
    83.         // reduce number of sprites back to original pool size
    84.         foreach(SpriteRenderer sprite in this.readyObjects) {
    85.             if(this.readyObjects.Count > spawnOnStart) {
    86.                 Destroy(sprite.gameObject);
    87.             } else {
    88.                 resetObject(sprite);
    89.             }
    90.         }
    91.     }
    92.     private IEnumerator fadeOut(SpriteRenderer sprite) {
    93.         float timeElapsed = 0;
    94.         // while the elapsed time is less than the specified trailLifetime
    95.         while(timeElapsed < trailLifetime) {
    96.             // get a number between 0 and 1 that represents how much time has passed
    97.             // 0 = no time has passed, 1 = trailLifetime seconds has passed
    98.             float progress = Mathf.Clamp01(timeElapsed / trailLifetime);
    99.             // linearly interpolates between the initial color and the final color
    100.             // based on the value of progress (0 to 1)
    101.             sprite.color = Color.Lerp(initialColor, finalColor, progress);
    102.             // track the time passed
    103.             timeElapsed += Time.deltaTime;
    104.             // wait until next frame to continue the loop
    105.             yield return null;
    106.         }
    107.         // reset the object so that it can be reused
    108.         resetObject(sprite);
    109.     }
    110.     // resets the object so that it is ready to use again
    111.     private void resetObject(SpriteRenderer sprite) {
    112.         // hide the sprite
    113.         sprite.gameObject.SetActive(false);
    114.         // reset the tint to default
    115.         sprite.color = initialColor;
    116.         // parent it to this object
    117.         sprite.transform.SetParent(transform);
    118.         // center it on this object
    119.         sprite.transform.localPosition = Vector3.zero;
    120.         // add it to the ready list
    121.         readyObjects.Add(sprite);
    122.     }
    123. }
     
  3. fosmark13

    fosmark13

    Joined:
    Feb 16, 2015
    Posts:
    91

    Dude this is just awesome!!! it works so amazing that i just can't describe how happy i am!!! you're really a master!!!
    I appreciate so much!!! thank you!!!!
     
    jeffreyschoch likes this.