Shooting star system
Project:
Programming language:
C#
Engine:
Untiy 3D
Description
Creates a shooting star effect at randomized time intervals, randomized locations on a dome around the player and randomized downward facing directions. ShootingStar handles the effects while ShootingStarManager handles the spawning. An object pool is used for the spawning of shooting stars so that the same objects are being reused, avoiding the instantiate and destroy performance penalty.
ShootingStarManager.cs
using UnityEngine;
using System.Collections;
public class ShootingStarManager : MonoBehaviour
{
public Transform shootingStarPrefab;
public float maxTimeBetween = 5.0f;
public float distanceFromPlayer = 80.0f;
public float travelDistance = 60.0f;
public int poolSize = 3;
private GameObject player;
private float currentTimeBetween = 5.0f;
private float timer;
// use a pool to reuse shooting star objects
private GameObject[] shootingStars;
private void Start()
{
player = GameObject.FindGameObjectWithTag(Tags.player);
if (!player)
{
Camera[] cams = GameObject.FindObjectsOfType<Camera>();
if (cams.Length > 0)
{
player = cams[0].gameObject;
}
}
shootingStars = new GameObject[poolSize];
for (int i = 0; i < poolSize; ++i)
{
shootingStars[i] = ((Transform)Object.Instantiate(shootingStarPrefab,
Vector3.zero, Quaternion.identity)).gameObject;
shootingStars[i].SetActive(false);
}
currentTimeBetween = Random.Range(0.0f, maxTimeBetween);
}
private void Update()
{
timer += Time.deltaTime;
if (timer >= currentTimeBetween)
{
timer = 0.0f;
ExecuteShootingstar(ChooseFreeShootingStar());
// execute shooting start randomly but within maxTimeBetween
currentTimeBetween = Random.Range(0.0f, maxTimeBetween);
}
}
private GameObject ChooseFreeShootingStar()
{
foreach (GameObject star in shootingStars)
{
if (!star.activeSelf)
{
return star;
}
}
return null;
}
private void ExecuteShootingstar(GameObject shootingStar)
{
if (shootingStar == null) return;
// spawn a shooting start distanceFromPlayer away from the player in a random
// direction, but only above the player
Vector3 direction = new Vector3(Random.Range(-1.0f, 1.0f), Random.Range(0.0f, 0.9f),
Random.Range(-1.0f, 1.0f));
shootingStar.transform.position = player.transform.position + direction.normalized *
distanceFromPlayer;
// directions are relative to the player
Vector3 directionToStar = shootingStar.transform.position
- player.transform.position;
Vector3 directionRight = Vector3.Cross(directionToStar, Vector3.up).normalized;
// rotate the right vector so it points in an arc downwards
Quaternion rotation = Quaternion.AngleAxis(Random.Range(10.0f, 170.0f),
directionToStar);
ShootingStar starComponent = shootingStar.GetComponent<ShootingStar>();
// ensure the shooting star travels downwards relative to the player's horizon
starComponent.endPos = shootingStar.transform.position
+ (rotation * directionRight).normalized * travelDistance;
shootingStar.SetActive(true);
starComponent.StartEffect();
}
}
ShootingStar.cs
using UnityEngine;
using System.Collections;
public class ShootingStar : MonoBehaviour
{
class AnimationParameters
{
public Vector3 scale;
public float starTransparency;
public float trailTransparency;
public float flareBrightness;
};
public Vector3 startPos;
public Vector3 endPos;
public float minFlareBrightness = 0.0f;
public float maxFlareBrightness = 1.0f;
// the shooting star grows and shrinks during travel
public float growTime = 1.0f;
public float shrinkTime = 1.5f;
public Vector3 minScale = new Vector3(0.5f, 0.5f, 0.5f);
public Vector3 maxScale = new Vector3(2, 2, 2);
private TrailRenderer tr;
private bool travelling = false;
private bool growing = true;
private float timer = 0.0f;
private LensFlare flare;
private Material starMat;
private Material trailMat;
private float origTrailTime;
private AnimationParameters maxValues;
private AnimationParameters minValues;
private void Start()
{
flare = GetComponent<LensFlare>();
startPos = transform.position;
starMat = GetComponent<Renderer>().material;
trailMat = GetComponent<TrailRenderer>().material;
starMat.SetFloat("_Transparency", 0.0f);
trailMat.SetFloat("_Transparency", 0.0f);
flare.brightness = minFlareBrightness;
tr = gameObject.GetComponent<TrailRenderer>();
origTrailTime = tr.time;
maxValues = new AnimationParameters() { scale = maxScale, starTransparency = 1.0f,
trailTransparency = 1.0f, flareBrightness = maxFlareBrightness };
minValues = new AnimationParameters() { scale = minScale, starTransparency = 0.0f,
trailTransparency = 0.0f, flareBrightness = minFlareBrightness };
}
private void Update()
{
if (travelling)
{
timer += Time.deltaTime;
// move shooting star
transform.position = Vector3.Lerp(startPos, endPos,
timer / (growTime + shrinkTime));
// setting the time parameter to 0 for a frame effectively restarts the trail
// rendered, preventing the problematic trail between the end of a shooting
// star and the start of a reused one here we restore it to its oroginal value
if (tr.time != origTrailTime && timer != 0)
{
tr.time = origTrailTime;
}
if (growing)
{
InterpolateEffects(timer / growTime, minValues, maxValues);
}
else
{
InterpolateEffects((timer - growTime) / shrinkTime, maxValues, minValues);
}
// stop grow, begin shrink
if (timer >= growTime)
{
growing = false;
}
// end effect
if (timer >= growTime + shrinkTime)
{
timer = 0.0f;
travelling = false;
growing = true;
gameObject.SetActive(false);
// reset the trail renderer
tr.time = 0;
}
}
}
private void InterpolateEffects(float t, AnimationParameters fromParameters,
AnimationParameters toParameters)
{
transform.localScale = Vector3.Lerp(fromParameters.scale, toParameters.scale, t);
starMat.SetFloat("_Transparency", Mathf.Lerp(fromParameters.starTransparency,
toParameters.starTransparency, t));
trailMat.SetFloat("_Transparency", Mathf.Lerp(fromParameters.trailTransparency,
toParameters.trailTransparency, t));
flare.brightness = Mathf.Lerp(fromParameters.flareBrightness,
toParameters.flareBrightness, t);
}
public void StartEffect()
{
startPos = transform.position;
travelling = true;
}
}