Search Unity

Script for making a character grow and shrink like in Alice in Wonderland.

Discussion in 'Scripting' started by hh3000, Oct 26, 2017.

  1. hh3000

    hh3000

    Joined:
    Oct 3, 2015
    Posts:
    57
    Hi all,
    Like in Alice in Wonderland I'm looking for a script that will make the player grow and shrink, so when they drink the potion the shrink, and when the eat the cookie they grow. If anyone has any ideas please let me know, thanks.
     
  2. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    Make a FixedUpdate() where you change transform.localScale over time until desired value. Don't forget to also move the camera to the character's new head position.
     
  3. hh3000

    hh3000

    Joined:
    Oct 3, 2015
    Posts:
    57
    Thanks FMark, I'm new to scripting and still learning do you have an example of the script itself?
     
  4. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    No problem. Here's something I use for my projects. it can switch between 3 scale states (grown, original scale and shrunken) on 3 different triggers.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ShrinkOrGrow : MonoBehaviour {
    6.  
    7.     //Public variables
    8.     //When triggering shrink() GameObject will scale down to [shrunkScale] over [time]
    9.     public Vector3 shrunkScale;
    10.     //When triggering grow() GameObject will scale up to [grownScale] over [time]
    11.     public Vector3 grownScale;
    12.     //Growth/shriuking time (MILLISECONDS)
    13.     public float time;
    14.     //Private variables
    15.     private bool active = false;
    16.     private Vector3 originalScale;
    17.     //private bool shrinking;
    18.     private float timePassed = 0.0f;
    19.     private float progress;
    20.     private enum State { SHRUNKEN, ORIGINAL_SIZE, GROWN }
    21.     private State state = State.ORIGINAL_SIZE;
    22.     private enum Actions { SHRINKING, NORMALIZING, GROWING }
    23.     private Actions action = Actions.NORMALIZING;
    24.  
    25.     // Use this for initialization
    26.     void Start ()
    27.     {
    28.         originalScale = transform.localScale;
    29.     }
    30.  
    31.     private void FixedUpdate()
    32.     {
    33.         if (active)
    34.         {
    35.             timePassed += Time.deltaTime * 1000.0f;
    36.             //0 - 1 with time
    37.             progress = (timePassed / time);
    38.         }
    39.         switch (action) {
    40.             case Actions.NORMALIZING:
    41.                 switch (state) {
    42.                     case State.SHRUNKEN:
    43.                         transform.localScale = new Vector3(
    44.                             (1 - progress) * shrunkScale.x + progress * originalScale.x,
    45.                             (1 - progress) * shrunkScale.y + progress * originalScale.y,
    46.                             (1 - progress) * shrunkScale.z + progress * originalScale.z
    47.                         );
    48.                         break;
    49.                     case State.GROWN:
    50.                         transform.localScale = new Vector3(
    51.                             (1 - progress) * grownScale.x + progress * originalScale.x,
    52.                             (1 - progress) * grownScale.y + progress * originalScale.y,
    53.                             (1 - progress) * grownScale.z + progress * originalScale.z
    54.                         );
    55.                         break;
    56.                     default:
    57.                         break;
    58.                 }
    59.                 break;
    60.             case Actions.GROWING:
    61.                 switch (state)
    62.                 {
    63.                     case State.SHRUNKEN:
    64.                         transform.localScale = new Vector3(
    65.                             (1 - progress) * shrunkScale.x + progress * grownScale.x,
    66.                             (1 - progress) * shrunkScale.y + progress * grownScale.y,
    67.                             (1 - progress) * shrunkScale.z + progress * grownScale.z
    68.                         );
    69.                         break;
    70.                     case State.ORIGINAL_SIZE:
    71.                         transform.localScale = new Vector3(
    72.                             (1 - progress) * originalScale.x + progress * grownScale.x,
    73.                             (1 - progress) * originalScale.y + progress * grownScale.y,
    74.                             (1 - progress) * originalScale.z + progress * grownScale.z
    75.                         );
    76.                         break;
    77.                     default:
    78.                         break;
    79.                 }
    80.                 break;
    81.             case Actions.SHRINKING:
    82.                 switch (state)
    83.                 {
    84.                     case State.ORIGINAL_SIZE:
    85.                         transform.localScale = new Vector3(
    86.                             (1 - progress) * originalScale.x + progress * shrunkScale.x,
    87.                             (1 - progress) * originalScale.y + progress * shrunkScale.y,
    88.                             (1 - progress) * originalScale.z + progress * shrunkScale.z
    89.                         );
    90.                         break;
    91.                     case State.GROWN:
    92.                         transform.localScale = new Vector3(
    93.                             (1 - progress) * grownScale.x + progress * shrunkScale.x,
    94.                             (1 - progress) * grownScale.y + progress * shrunkScale.y,
    95.                             (1 - progress) * grownScale.z + progress * shrunkScale.z
    96.                         );
    97.                         break;
    98.                     default:
    99.                         break;
    100.                 }
    101.                 break;
    102.             default:
    103.                 break;
    104.         }
    105.         if (progress >= 1)
    106.         {
    107.             active = false;
    108.             switch (action) {
    109.                 case Actions.GROWING:
    110.                     state = State.GROWN;
    111.                     break;
    112.                 case Actions.NORMALIZING:
    113.                     state = State.ORIGINAL_SIZE;
    114.                     break;
    115.                 case Actions.SHRINKING:
    116.                     state = State.SHRUNKEN;
    117.                     break;
    118.             }
    119.         }
    120.     }
    121.  
    122.     public void grow()
    123.     {
    124.         active = true;
    125.         action = Actions.GROWING;
    126.         timePassed = 0.0f;
    127.     }
    128.  
    129.     public void shrink()
    130.     {
    131.         active = true;
    132.         action = Actions.SHRINKING;
    133.         timePassed = 0.0f;
    134.     }
    135.  
    136.     public void originalSize()
    137.     {
    138.         active = true;
    139.         action = Actions.NORMALIZING;
    140.         timePassed = 0.0f;
    141.     }
    142. }
    143.  
     
    ArtAes and GuchMan21 like this.
  5. hh3000

    hh3000

    Joined:
    Oct 3, 2015
    Posts:
    57
    Great :) Next question. Where am I putting the scripts, in the character? The trigger boxes that would be situated around the bottle and biscuit ?
     
  6. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    Yes. As you see the script I gave you references transform component, so It will affect only the game object it is attached to and it's children. Put it in character's components.

    There are numerous ways to go about checking collisions and triggering actions on collisions. I recommend you look at this part of Roll-a-Ball tutorial, as I don't know enough about your scene setup to give you concrete answers.
     
  7. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    After you have everything tagged, and all colliders and rigidbodies applied, attach a script like this to character. Modify as necessary:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Events;
    6.  
    7. public class ActionOnTrigger : MonoBehaviour {
    8.  
    9.     void OnTriggerEnter(Collider other)
    10.     {
    11.         if (other.gameObject.CompareTag("grow"))
    12.         {
    13.             GetComponent<ShrinkOrGrow>().grow();
    14.         }
    15.         if (other.gameObject.CompareTag("shrink"))
    16.         {
    17.             GetComponent<ShrinkOrGrow>().shrink();
    18.         }
    19.         if (other.gameObject.CompareTag("normal_size"))
    20.         {
    21.             GetComponent<ShrinkOrGrow>().originalSize();
    22.         }
    23.     }
    24. }
    25.  
     
    GuchMan21 likes this.
  8. GuchMan21

    GuchMan21

    Joined:
    Feb 5, 2018
    Posts:
    1
    Thanks, FMark92! Was looking for something like this for a class project for the Udacity VR course I"m taking. Do you mind if I used it as long as I credit you?
     
  9. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    You don't have to credit me, use it however you want.
     
  10. ArtAes

    ArtAes

    Joined:
    Sep 8, 2018
    Posts:
    2
    So hopefully FMark is still around here to help.

    I'm in a beginning game dev class and I wanted to implement this exact mechanic into my game (shrinking/growing the player upon collection of item) but I've played around with this code for two days now and can't get it working in my game.

    One of my issues is that it tells me:

    Tag: normal_size is not defined.
    UnityEngine.GameObject:CompareTag(String)
    ActionOnTrigger:OnTriggerEnter(Collider) (at Assets/Grappling Hook/Scripts/ActionOnTrigger.cs:20)

    I've been looking over the code trying to plug in a defined size for my original size of my player but nothing has worked thus far.

    I'm sure I am missing more but this is my primary hang up. If someone could shed some light I would be grateful.
     
  11. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    @ArtAes
    Hello there.
    Sounds to me like you didn't create the tag or misspelled it's name.

    021.png

    022.png

    You don't have to use them but they have to be defined if you want to use the full code I posted.
    Tell me if this worked for you.
     
    ArtAes likes this.
  12. ArtAes

    ArtAes

    Joined:
    Sep 8, 2018
    Posts:
    2
    Thanks for checking back in! I appreciate it. This is the best looking option I have found for this mechanic, and it appears to be working for other people so hopefully I can figure this thing out.

    I did not add the tag for normal_size so I added it in but so far nothing has changed for me.

    I tried to tag the player with it as well and no such luck T_T

    I am super noobish so I might not be able to pull this off, though I am determined to try.

    What I am trying to accomplish is having the grow or shrink mechanic trigger on an item pick up. the attached image shows how I built out the "pellet sphere" in the inspector which houses the tag "shrink". On collider impact I want it to trigger the shrink or grow.

    I have attached a screen shot for reference.

    (for context you start as an elemental particle that grows gradually as you look for a way to escape a lab)

    I noticed in the main code "ShrinkOrGrow" portion there are fields for "shrunken" and "grown" have the same code/text for the x, y and z fields. Do these fields need to be modified individually? I saw that the code made the values adjustable in the inspector for the script so I assumed that was that.

    I haven't played around too much with the code (though I have made some attempts) as I tend to break more than I fix at the moment.

    I am wondering if there will be additional code I will need to write to adjust the camera height after shrinking or growing as well.



    Screen Shot 2018-10-04 at 8.55.22 PM.png
     
  13. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    @ArtAes
    Hmm.

    >I tried to tag the player with it as well and no such luck T_T
    "ActionOnTrigger" script only looks at the tag of the object it is colliding with.

    That's the correct way of going about it. But, looking at the screenshot, you've attached "ActionOnTrigger" script to the sphere. Both scripts I posted (ShrinkOrGrow, ActionOnTrigger) are to be attached to the character which will be
    shrunken or grown.

    If the sphere is a pickup that shrinks or grows the character, it only need to be tagged.

    Sorry the scripts I posted permit only 1 stage of growth. Just as you suspect here:

    Those values need to be defined manually and they set the character size when grown and shrunken.
    If you want character to grow every time you need to modify the script a bit.

    Here's a quick start:
    Code (CSharp):
    1.     //ShrinkOrGrow.cs
    2.     //new public variable
    3.     public float growingFactor = 1.1f;
    4.     public void grow()
    5.     {
    6.         active = true;
    7.         action = Actions.GROWING;
    8.         timePassed = 0.0f;
    9.         //modified part of the growth method
    10.         state = State.ORIGINAL_SIZE;
    11.         grownScale = grownScale * growingFactor;
    12.     }
    I also assume you only want growth pickup to affect the character once:
    Code (CSharp):
    1.         //ActionOnTrigger.cs
    2.         if (other.gameObject.CompareTag("grow"))
    3.         {
    4.             GetComponent<ShrinkOrGrow>().grow();
    5.             //modified part
    6.             //Remove tagged from other so that charater is only affected by this specific object ONCE
    7.             other.tag = "Untagged";
    8.         }

    I suggest you get into it. It's super fun when you know the basics.

    Easiest thing would be to have the camera object be a child of character object. That way camera will scale with the character.
     
    ArtAes likes this.
  14. Harfatum

    Harfatum

    Joined:
    May 28, 2018
    Posts:
    9
    Thanks a lot for the contribution, FMark92. I have modified the code in two ways for my own purposes, and thought it would be useful to share.

    First, I made the scaling method generalizable - there are no grown or shrunk presets or states, simply pass in a scaling factor or Vector3 to Scale() to scale the object. OriginalSize() still works as before.

    Second, I pulled out the easing function and replaced the linear easing with one that grows or shrinks at a speed proportional to the scale at each step; this gives a transition that feels more natural, but you can easily replace it with another if you like.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Scalable : MonoBehaviour
    5. {
    6.     //Public variables
    7.     //Growth/shrinking time (MILLISECONDS)
    8.     public float time;
    9.     //Private variables
    10.     private bool active = false;
    11.     private Vector3 originalScale;
    12.     private Vector3 prevScale;
    13.     private Vector3 targetScale;
    14.     private float timePassed = 0.0f;
    15.     private float progress;
    16.  
    17.     // Use this for initialization
    18.     void Start()
    19.     {
    20.         originalScale = transform.localScale;
    21.         prevScale = transform.localScale;
    22.     }
    23.  
    24.     // This function eases between initial and final values as progress goes from 0 to 1,
    25.     // such that the speed is proportional to the value at each given time.
    26.     private float ProportionalEasing(float progress, float initial, float final)
    27.     {
    28.         return 2 * (final - initial)/(final + initial) * (0.5f*(final - initial)*progress*progress + initial*progress) + initial;
    29.     }
    30.  
    31.     private void FixedUpdate()
    32.     {
    33.         if (active)
    34.         {
    35.             timePassed += Time.deltaTime * 1000.0f;
    36.             //0 - 1 with time
    37.             progress = (timePassed / time);
    38.         }
    39.         var currentScale = new Vector3(
    40.             ProportionalEasing(progress, prevScale.x, targetScale.x),
    41.             ProportionalEasing(progress, prevScale.y, targetScale.y),
    42.             ProportionalEasing(progress, prevScale.z, targetScale.z)
    43.         );
    44.         transform.localScale = currentScale;
    45.         if (progress >= 1)
    46.         {
    47.             active = false;
    48.             prevScale = currentScale;
    49.         }
    50.     }
    51.  
    52.     public void Scale(Vector3 scale)
    53.     {
    54.         targetScale = scale;
    55.         active = true;
    56.         timePassed = 0.0f;
    57.     }
    58.  
    59.     public void Scale(float ratio)
    60.     {
    61.         Scale(ratio * originalScale);
    62.     }
    63.  
    64.     public void OriginalSize()
    65.     {
    66.         Scale(originalScale);
    67.     }
    68. }
     
    Last edited: Nov 7, 2019
    kproduce22 likes this.