using UnityEngine; using System.Collections.Generic; using System; /// /// This component is responsible for creating scenery props randomly selected from sceneryPrefabs /// The randomness does not use the RandomSingleton. This is due to the fact that we don't have control /// of order of execution (unless we use Execution Order feature which we find hacky). So since it doesn't affect the /// gameplay as such, for now we decided to use Unity's random which is independent from RandomSingleton used to /// generate the enemies. /// public class SceneryGenerator : MonoBehaviour { public static SceneryGenerator Instance; /// /// Prefabs will be randomly selected from here with gamedesigner-set weights /// To create prefabs, the sprites will probably be normal textures, rather than part of an atlas. This is because /// they will be quite big and would defeat the purpose of putting them in an atlas. So in NGUI you can create /// a texture widget, where you just drag and drop the texture on the widget's texture field. You might need /// to change the shader so it's transparent as well. The widget's pivot needs to be set carefully. /// The horizontal pivolt must always be set to the right pivot. If it's a top-bottom prop, leave the vertical pivot to middle. /// Otherwise set it accordingly, e.g. if it's a prop coming from the top, set the vertical pivot to top. /// Reset the transform's position to zero /// public LootTable sceneryPrefabs; public int minSpacing = 300; public int maxSpacing = 600; /// /// Tweak this value to get a parallax effect /// public float speed = 150; /// /// This is the z value used for the generated props, where together with the appropriate speed /// will achieve a parallax effect. /// For foreground we are currently using -2 (in front of bullets) /// For midground we are currently using 9 (just in front of backgrounds) /// public float zValue; Transform _anchor; List _sceneryPropsTransforms = new List(); List _sceneryProps = new List(); float _nextSceneryX; float _originalSpeed; bool _isSpawning; public bool _isPlaying = false; const int STOP_SPAWNING_AT_TIME_LEFT = 18; #region Unity Callbacks void Awake() { Instance = this; _anchor = SkinDownloadManager.Instance.sceneryAnchor; _originalSpeed = speed; if (enabled) //for debugging purposes so we can disable the component at design time for a debug session { enabled = false; NotificationCenter.AddListener(OnGameStart, NotificationType.GameStart); NotificationCenter.AddListener(OnEndLife, NotificationType.EndLife); NotificationCenter.AddListener(OnGetLife, NotificationType.GetLife); NotificationCenter.AddListener(OnGameOver, NotificationType.GameOver); NotificationCenter.AddListener(OnChangeScrollingSpeed, NotificationType.ChangeScrollingSpeed); NotificationCenter.AddListener(OnTimeLeftUpdate, NotificationType.TimeLeftUpdate); } } private void OnGetLife(Notification note) { //_isPlaying = true; } private void OnEndLife(Notification note) { _isPlaying = false; } void OnDestroy() { NotificationCenter.RemoveListener(OnGameStart, NotificationType.GameStart); NotificationCenter.RemoveListener(OnGameOver, NotificationType.GameOver); NotificationCenter.RemoveListener(OnChangeScrollingSpeed, NotificationType.ChangeScrollingSpeed); NotificationCenter.RemoveListener(OnTimeLeftUpdate, NotificationType.TimeLeftUpdate); NotificationCenter.RemoveListener(OnEndLife, NotificationType.EndLife); NotificationCenter.RemoveListener(OnGetLife, NotificationType.GetLife); } void Update() { if (!BackgroundManager.Instance._isPlaying) { return; } float deltaX = speed * Time.deltaTime; if (_isSpawning) { _nextSceneryX += deltaX; //if the next scenery marker is visible, create the next prop if (_nextSceneryX > -GameConstants.GAME_WIDTH/2) { CreateNextSceneryProp(); } } for (int i = _sceneryPropsTransforms.Count-1; i >= 0; i--) { Transform sceneryPropTransform = _sceneryPropsTransforms[i]; SceneryProp sceneryProp = _sceneryProps[i]; //move scenery sceneryPropTransform.localPosition += new Vector3(deltaX, 0, 0); //check if needs to be removed if (sceneryPropTransform.localPosition.x + sceneryProp.MinX > GameConstants.GAME_WIDTH/2) { sceneryProp.Despawn(); _sceneryPropsTransforms.RemoveAt(i); _sceneryProps.RemoveAt(i); } } } #endregion #region Notification Callbacks void OnGameStart(Notification note) { enabled = true; _isSpawning = true; _isPlaying = true; _nextSceneryX -= UnityEngine.Random.Range(minSpacing, maxSpacing); } void OnGameOver(Notification note) { enabled = false; foreach (SceneryProp s in _sceneryProps) { s.Despawn(); } _sceneryPropsTransforms.Clear(); _sceneryProps.Clear(); } void OnChangeScrollingSpeed(Notification note) { float scrollingSpeedFactor = (float)note.data; speed = _originalSpeed * scrollingSpeedFactor; } void OnTimeLeftUpdate(Notification note) { float timeLeft = (float)note.data; //Stop spawning stuff so that it doesn't intermingle with the end of level scenery if (_isSpawning && timeLeft <= STOP_SPAWNING_AT_TIME_LEFT) { _isSpawning = false; } } #endregion void CreateNextSceneryProp() { Transform sceneryPropTransform = sceneryPrefabs.GetRandomItem(); SceneryProp sceneryProp = sceneryPropTransform.GetComponent(); Vector3 originalPos = sceneryPropTransform.localPosition; originalPos.x = _nextSceneryX - sceneryProp.MaxX; originalPos.z = zValue; Vector3 originalScale = sceneryPropTransform.localScale; sceneryPropTransform.parent = _anchor; sceneryPropTransform.localPosition = originalPos; sceneryPropTransform.localScale = originalScale; _sceneryPropsTransforms.Add(sceneryPropTransform); _sceneryProps.Add(sceneryProp); _nextSceneryX += sceneryProp.MinX; _nextSceneryX -= UnityEngine.Random.Range(minSpacing, maxSpacing); //add some randomness in flipping on the X axis bool isXFlipped = UnityEngine.Random.value < 0.5f; if (isXFlipped) { UITexture uiTexture = sceneryPropTransform.GetComponent(); if (uiTexture != null) //if it is null, it must be some composite scenery prop with multiple UITextures... just skip it in that case { Rect r = uiTexture.uvRect; r.x = 1; r.width = -1; uiTexture.uvRect = r; } } } }