- Home /
Debugging - Scale Collectible
Hi guys,
I've been working on a script that grows / shrinks a rigid body asset (including the player) on trigger. I currently have 2 scripts; "Collectible" for the the trigger to apply the effect and "Effects" which is added to the rigid body collision object and makes the scale change.
I've been working on it a while and hit a maths wall with how to stack these effects smoothly - resizing to normal is fine, but when adding new collectibles the animation jumps back towards normal size. Can anyone see where I've gone wrong? I think I've isolated it to the following section;
// Start Transition
if(timer > duration - transitionDuration) {
if(modifier != prevModifier) {
prevModifier = modifier * (duration - timer);
transform.localScale = defaultScale * (1 + prevModifier);
}
}
(On stacking, timer is set back to duration and modifier is increased / decreased.)
Also, any tips on making this generic to any variable (speed etc) without too much code repetition? (eg. Is variable reference forwarding possible?)
I have included the rest of my code below and hope other find it useful.
Effects
using UnityEngine;
using System.Collections;
public class Effects : MonoBehaviour {
// The types of attribute effects available
public enum EffectTypes {Scale}
public EffectTypes effectType = EffectTypes.Scale;
// Modifier controls
public float modifier = 0.5f; // The modifier to aim for
private float prevModifier = 0; // The staggered modifier previously used in calculations
public float minModifier = -0.5f; // Minimum modifier value (avoids gameObject flipping etc)
public float maxModifier = 1.0f; // Maximum modifier value (avoids growing endlessly)
// Essential controls
public bool stackEffects = true; // Do the effects stack?
public float stackAmount = 0.25f; // Percent of new modifier added when stacking
private float timer = 5; // Controls the countdown
// Transition durations
public float duration = 5; // Length the effect lasts in seconds
public float transitionDuration = 1;// Length of the start / end transitions
// Type specific stored values
private Vector3 defaultScale;
// Preset the stored animations
void Awake() {
// Initialise the game object variables
defaultScale = transform.localScale;
// Ensure the variables are valid
modifier = Mathf.Clamp(modifier, minModifier,maxModifier);
stackAmount = Mathf.Clamp (stackAmount, 0.01f, 1);
transitionDuration = Mathf.Clamp (transitionDuration, 0.01f, duration / 2);
}
// Apply the effect and control timer
void Update() {
if(effectType == EffectTypes.Scale) {
ApplyScale();
}
timer -= Time.deltaTime;
}
// Apply the effect to the scale variable
public void ApplyScale() {
// Start Transition
if(timer > duration - transitionDuration) {
if(modifier != prevModifier) {
prevModifier = modifier * (duration - timer);
transform.localScale = defaultScale * (1 + prevModifier);
}
}
// Inbetween transitions
else if(timer > transitionDuration ) { }
// End transition
else if(timer > 0) {
transform.localScale = defaultScale + defaultScale * modifier * timer;
}
// Destroy script on completion
else {
transform.localScale = defaultScale;
Destroy (this);
}
}
// Directly set the modifier to a value
public void SetModifier(float mod) {
modifier = Mathf.Clamp(mod, minModifier, maxModifier);
timer = duration;
}
// Reset the timer, and if stackable, stack
public void CombineEffects(float mod) {
timer = duration;
// If stack effects is enabled, stack by the stack amount
if(stackEffects)
SetModifier(modifier + mod * stackAmount);
}
}
Collectible
using UnityEngine;
using System.Collections;
public class Collectible : MonoBehaviour {
public Effects.EffectTypes effect;
public float modifier = 0.5f;
void OnTriggerEnter(Collider col) {
if(col.gameObject.GetComponent<Rigidbody>() != null) {
Effects[] eff = col.gameObject.GetComponents<Effects>();
bool found = false;
// Determine if the effect has already been applied
if(eff != null) {
for(int i = 0; i < eff.Length; i ++){
// If the effect is the same, reset the duration and end the loop
if(eff[i].effectType == effect){
eff[i].CombineEffects(modifier);
found = true;
i = eff.Length;
// Destroy the collectable
Destroy(gameObject);
}
}
}
// If there is no effect, apply it
if(!found || eff == null) {
Effects newEffect = col.gameObject.AddComponent(typeof(Effects)) as Effects;
if(modifier != 0) {
newEffect.SetModifier(modifier);
}
// Destroy the collectable
Destroy(gameObject);
}
}
}
}
Edit: Cleanup to shorten and refine Effects script. *Edit: Figured out clamping to remove flipping problem.
For ease of testing, I'll also attach my current respawn code. Just set the respawnTime to positive.
using UnityEngine;
using System.Collections;
public class SpawnPoint : $$anonymous$$onoBehaviour {
public GameObject spawns; // Object to spawn
public float respawnTime = -1; // Default time between spawning
public float respawnRandom = 2; // Time variation between spawning
public float respawnHeight = 1; // The height at which the collectable spawns
private float timer = -1; // count down timer
private GameObject currInstance;
void Start () {
Spawn();
}
// Update is called once per frame
void Update () {
if(respawnTime != -1 && currInstance == null) {
if(timer > 0) {
timer -= Time.deltaTime;
}
else {
Spawn();
timer = Random.Range(respawnTime - respawnRandom/2, respawnTime + respawnRandom/2);
}
}
}
// Instantiate the object
public void Spawn() {
if(!currInstance) {
currInstance = Instantiate(spawns) as GameObject;
currInstance.transform.parent = transform;
Vector3 newPosition = transform.position;
newPosition.y += respawnHeight;
currInstance.transform.position = newPosition;
}
}
}