LocalScale is not taking effect at runtime
I am doing a simple block breaker type of game. (Unity 5.5.1f1)
I have a class (called PowerUpBase) that controls my powerUps which will drop from broken bricks.
I then I have all of my powerUps inherit from that class. All of my powerUps are working except for the ones that are supposed to increase and decrease the scale of my paddle in the X-axis The derived class for one of these is called IncreasePaddlePowerUp.
Everything compiles fine. When I run the game and pick up the power up nothing appears to happen - the scale does not get altered at runtime. However, when I stop the game, the editor shows that the paddle was scaled and the inspector says X axis scale = 1.25. See below, this value for x is what I coded. Again, nothing (nothing visual) appears in the game window.
Here is the class:
using UnityEngine;
using System.Collections;
//Make sure there is always an rigidbody,boxcollider and audiosource component on the GameObject where this script is added.
[RequireComponent(typeof(Rigidbody2D), typeof(BoxCollider2D), typeof(AudioSource))]
public class PowerUpBase : MonoBehaviour //This is the base class for all powerup. When creating new powerups, derive from this
{
public float DropSpeed = 5; //How fast does it drop?
public AudioClip Sound; //Sound played when the powerup is picked up
// Use this for initialization
void Start()
{
GetComponent<AudioSource>().playOnAwake = false;
}
// Update is called once per frame
protected virtual void Update()
{
transform.position += new Vector3(0, -DropSpeed, 0) * Time.deltaTime;
}
//Monobehaviour method, notice the IEnumerator which tells unity this is a coroutine
IEnumerator OnTriggerEnter2D(Collider2D other)
{
//Only interact with the paddle
if (other.name == "Paddle")
{
//Notify the derived powerups that its being picked up
OnPickup();
//Prevent furthur collisions
gameObject.GetComponent<SpriteRenderer>().enabled = false;
gameObject.GetComponent<BoxCollider2D>().enabled = false;
//Change the sound pitch if a slowdown powerup has been picked up
GetComponent<AudioSource>().pitch = Time.timeScale;
//Play audio and wait, without the wait the sound would be cutoff by the destroy
GetComponent<AudioSource>().PlayOneShot(Sound);
yield return new WaitForSeconds(Sound.length);
}
}
//Every powerup which derives from this class should implement this method!
{
}
}
And then here is the derived class that is on the powerUp prefab
using UnityEngine;
using System.Collections;
public class IncreasePaddlePowerUp : PowerUpBase {
public GameObject paddle;
public float revertCountdown;
private bool nowsAGoodtime = false;
protected override void OnPickup(){
//Call the default behaviour of the base class frist
base.OnPickup();
ScaleUp();
}
void ScaleUp()
{
paddle.transform.localScale += new Vector3(0.25f, 0f, 0f);
revertCountdown -= Time.deltaTime;
RevertToNormal();
Debug.Log("localScale = " + paddle.transform.localScale);
Debug.Log("revertCountdown = " + revertCountdown);
Debug.Log("RevertToNormal() was called.");
}
void RevertToNormal()
{
if (revertCountdown <= 0.0f)//this never happens because the
//revertCountDown stops at 9.98
{
paddle.transform.localScale = new Vector3(1f, 1f, 1f);
}
}
}
In ScaleUp(), I put some Debug.Log() in the derived class and its even more weird than I expected.
Instead of showing localScale.x to be 1.25 (I did ...+= new Vector3(o.25f...) as I expected, instead it shows 1.3? makes no sense!
Additionally, it shows 9.98 as the revertCountdown value. I assume this is because it leaves the method to go to RevertToNormal() before more than 0.02 seconds has elapsed?
I thought is was going to be simple to just scale the paddle for ten seconds and then downscale back to normal...have spent hours now trying a variety of different approaches to solve this...to no avail.
Thanks in advance for taking the time to look at this and answer!
Somehow I deleted a line of code when I was creating this question. Look at line 48 of the PowerUpBase class. That part of the text should be:
//Every powerup which derives from this class should implement this method!
protected virtual void OnPickup()
{
}
Answer by gameplay4all · Mar 01, 2017 at 01:45 PM
Since OnPickup()
is called only once, when picking up the powerup (I assume correctly?), you only go through the method ScaleUp once. This would not achieve the result you want. A useful technique for situations like these are Coroutines. Coroutines are however inherited (not sure if that's the correct term here) from monobehaviour. So you will need to do something like the following:
void ScaleUp()
{
paddle.GetComponent<BehaviourWithCoroutine>().StartCoroutine(ScaleUp(5.0f, 5f)); //Since IncreasePaddlePowerUp doesn't inherit from Monobehaviour you need to call it like this.
}
Now on the paddle object you have a monobehaviour, BehaviourWithCoroutine, with the following method:
IEnumerator ScaleUp(float amount, float duration)
{
Transform thisTransform = transform;//Likely you already have a variable like this, if not you should.
float originalScale = thisTransform.LocalScale.x;
thisTransform.LocalScale.x += amount;
yield return new WaitForSeconds(duration);
thisTransform.LocalScale.x = originalScale;
//Here's where you can call methods after the scaling is reverted
}
(All code is not checked for errors so you might need to adjust some spelling for it to compile)
Hopefully this works for you!
-Gameplay4all
Edit: I now notice your baseclass does inherit from Monobehaviour so you can call StartCoroutine directly from the powerup class.
Your answer
Follow this Question
Related Questions
function works script-wise; doesn't work visually(only in game) 0 Answers
Scaling Rigged Character at Runtime Through Script? 0 Answers
How can I make A Object have the same Scale as B Object? 0 Answers
Cannot scale an instantiated child 3D object on the Y axis 0 Answers
Saving default scale of an object c# 1 Answer