- Home /
Scaling objects over time
I'm having issues properly scaling object in my game. Specifically, I'm trying to scale my player to a certain amount when he or she collides with certain objects. For example, colliding into a ball will cause the player to scale down to half its normal size; meanwhile, colliding into a square will scale the player to twice its size.
As of right now, I've set up a single function to scale the player based on a value other objects set as one of the function's parameters. When I first made the function, I initially mistook the magnitude to be a single value from the Vector3 I need to create inside the function. Here is the function in full:
//*used in other scripts
//changes player's scale based on amount used for each player
public void AlterPlayerScale(float scaleValue, float initMagnitude, float scalingDuration){
//set scaling amount for scaling player
Vector3 newScale = new Vector3(initMagnitude+scaleValue,
initMagnitude+scaleValue,
initMagnitude+scaleValue);
Debug.Log ("new Scale: "+ newScale);
//scaling step
scaleStep += Time.deltaTime/scalingDuration;
Debug.Log ("player's scale: " + transform.localScale.x);
//alter player's scale
transform.localScale = Vector3.Lerp(transform.localScale,
newScale,
scaleStep);
}
I have two objects that alter the player's scale: a collectable, which should increase the player's scale; and a enemy, which decreases the player's scale. Both objects have scripts referencing the function above via OnTriggerEnter() or OnCollisionEnter(), respectively: when the objects collides with the player, the object finds the player's current local scale magnitude to compare with in the AlterPlayerScale() function above.
However, an issue occurs when the player collides with an enemy after colliding with a collectable: the vector the enemy calculates causes the function to create a positive vector.
I've thought of just using one of the three coordinates from a minimum player scale I've set up in another script to use for the 'initMagnitude' variable instead. However, the vector that comes out as a result will not be relative to the player's current scale.
As of right now, I still need help scaling the player down properly even after colliding with a collectable. If my description of the problem was confusing, please let me know so I may clarify the problem ASAP.
I'm trying to puzzle out the correct behavior for your game. I'm visualizing three states, 'small', 'normal', and 'large'. I'm I'm visualizing that 'collectables' increase the size, so if the size is 'normal', it becomes 'large'. If the size is 'small', it becomes 'normal.' Likewise, if the player collides with an enemy, the scale is reduced by one state...'large' becomes 'normal', and 'normal' becomes small. Is this the behavior you are looking for?
It wasn't entirely how I envisioned it when I made the script during a game jam, but now that I think of it, this is the basic philosophy. The way the script works now relies too heavily on math to get the scaling to work properly.
For example, if the player (given a maximum scale of 5 units, a $$anonymous$$imum scale of 1 unit, and a current scale of 2) touches a collectable, the player should scale from 2 to 3; touching an enemy should scale the down to 1.
If I were to adopt your states model, I would still have to find out how to scale the player based on which object he or she touches.
Answer by robertbu · Nov 25, 2013 at 09:10 PM
There are a couple of ways of looking at this problem. You can do as you've done and have the object that your player collide with tell the player to grow or shrink based, or you could have the player recognize what it is colliding with and do the right thing. I would lean towards the latter, but since your code does the former, here is a bit of untested code outline how I might approach the problem:
using UnityEngine;
using System.Collections;
public class Scaling : MonoBehaviour {
public int startSize = 3;
public int minSize = 1;
public int maxSize = 6;
public float speed = 2.0f;
private Vector3 targetScale;
private Vector3 baseScale;
private int currScale;
void Start() {
baseScale = transform.localScale;
transform.localScale = baseScale * startSize;
currScale = startSize;
targetScale = baseScale * startSize;
}
void Update() {
transform.localScale = Vector3.Lerp (transform.localScale, targetScale, speed * Time.deltaTime);
// If you don't want an eased scaling, replace the above line with the following line
// and change speed to suit:
// transform.localScale = Vector3.MoveTowards (transform.localScale, targetScale, speed * Time.deltaTime);
if (Input.GetKeyDown (KeyCode.UpArrow))
ChangeSize (true);
if (Input.GetKeyDown (KeyCode.DownjArrow))
ChangeSize (false);
}
public void ChangeSize(bool bigger) {
if (bigger)
currScale++;
else
currScale--;
currScale = Mathf.Clamp (currScale, minSize, maxSize+1);
targetScale = baseScale * currScale;
}
}
It's not working as intended: the targetScale, which is the scale variable that the lerp function hinges on, is not initialized. This means targetScale is initialized to zero, causing the player's scale to lerp between the starting scale to zero.
I thought setting the targetScale to an initial value would help in this, but no luck.
From further testing, however, I've found that the script does not work at all (except to scale the player up to a starting size).
Any suggestions?
I found a bug with targetScale and fixed it, but it should not have caused a complete failure of the code. I added Up and Down arrow input so you can test the code. Start with an empty scene and put this script on a cube. Run the scene and use the arrow keys to increase and decrease the size of the cube.
I just got a barrage of stack overflow errors after adding your alterations to the script, and now the project won't even open anymore.
Before you add it to your project, start with a new scene, create a block, add the script to the block, run the app, and use the up and down arrow keys to size the block. As for your stack overflow problem, I'd have to see your code to give you feedback.
I just tried it on a test project, and it works (generally) as intended. I'm still not sure why you use Time.deltaTime for the lerp step, as it causes the scale to reach the end of the lerp slower than having a simple step going from 0 to 1.
I've actually seen this in almost all of the tutorials online talking about lerping between two variables. Am I missing something here?
Answer by NiaG-A · Aug 19, 2017 at 08:50 AM
I have a YouTube video about this https://www.youtube.com/watch?v=Wymchsif758 it only requires a few lines of code