using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; public class GamePlayer : MonoBehaviour { public static GamePlayer Instance; private readonly float spawnRate = 1f; private float nextSpawnTime; internal int score; private int attempts; private float boostLeft; private float slownessLeft; private float speedyLeft; private float antiLeft; private float goldenLeft; [SerializeField] private Text scoreText; [SerializeField] private Text boostText; [SerializeField] internal AudioSource backgroundMusic; [SerializeField] private GameObject berryParent; [SerializeField] private Image bird; [SerializeField] private GameObject berryTemplate; [SerializeField] private Rigidbody2D rb; [SerializeField] private RectTransform canvasRect; [SerializeField] private BoxCollider2D groundCollider; public readonly List berries = new List(); private readonly List noGravityBerries = new List(); private bool hasJumped = false; internal bool IsGrounded() { CircleCollider2D birdCol = bird.GetComponent(); Vector2 feetPos = (Vector2)bird.transform.position + Vector2.down * (birdCol.radius + 0.05f); return groundCollider.OverlapPoint(feetPos); } public void Awake() { Instance = this; } public void Start() { UpdateStats(0, 1); } void MoveBird() { float speedModifier = 1f; bool doMoveRight = false; bool doMoveLeft = false; bool doJump = false; bool doRestart = false; if (boostLeft > 0f || speedyLeft > 0f) speedModifier = 1.39f; else if (slownessLeft > 0f) speedModifier = 0.56f; if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.J)) { doMoveLeft = true; } if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.L)) { doMoveRight = true; } if (Input.GetKey(KeyCode.Space) || Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.K) || Input.GetKey(KeyCode.I) || Input.GetMouseButton(0)) { doJump = true; } if (Input.GetKey(KeyCode.R)) { doRestart = true; } if (doMoveLeft && !doMoveRight) { bird.transform.position += new Vector3(-(576f * (speedModifier * canvasRect.lossyScale.x) * Time.deltaTime), 0f, 0f); ClampPosition(bird); bird.transform.localScale = new Vector3(1f, 1f, 1f); } if (doMoveRight && !doMoveLeft) { bird.transform.position += new Vector3(576f * (speedModifier * canvasRect.lossyScale.x) * Time.deltaTime, 0f, 0f); ClampPosition(bird); bird.transform.localScale = new Vector3(-1f, 1f, 1f); } if (doMoveLeft || doMoveRight) groundCollider.transform.position = new Vector2(bird.transform.position.x, groundCollider.transform.position.y); if (doJump && IsGrounded() && !hasJumped) { hasJumped = true; AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Jump"), Camera.main.transform.position, 0.75f); if (boostLeft > 0f || speedyLeft > 0f) rb.velocity = new Vector2(rb.velocity.x, 480f * canvasRect.lossyScale.y); else if (slownessLeft > 0f) rb.velocity = new Vector2(rb.velocity.x, 300f * canvasRect.lossyScale.y); else rb.velocity = new Vector2(rb.velocity.x, 380f * canvasRect.lossyScale.y); } if (!IsGrounded()) hasJumped = false; if (doRestart) { if (score != 0) Respawn(); } if (antiLeft > 0f || goldenLeft > 0f) { List berryTags = new List() { "NormalBerry", "SlowBerry", "UltraBerry", "SpeedyBerry", "RandomBerry", "AntiBerry", "GoldenBerry" }; if (antiLeft > 0f) berryTags.Add("PoisonBerry"); float scale = (canvasRect.lossyScale.x + canvasRect.lossyScale.y) / 2f; float radius = antiLeft > 0f ? 250f * scale : 325f * scale; float speed = antiLeft > 0f ? (300f * scale * Time.deltaTime) : -(420f * scale * Time.deltaTime); foreach (string tag in berryTags) { foreach (var berry in GameObject.FindGameObjectsWithTag(tag)) { RectTransform berryRect = berry.GetComponent(); Vector3 dir = berryRect.position - bird.GetComponent().position; if (dir.magnitude < radius) { berryRect.position += speed * dir.normalized; ClampPosition(berry.GetComponent()); noGravityBerries.Add(berry.GetInstanceID()); } else noGravityBerries.Remove(berry.GetInstanceID()); } } } else if (noGravityBerries.Count() != 0) noGravityBerries.Clear(); } void ClampPosition(Image image) { RectTransform birdRect = image.GetComponent(); float halfW = canvasRect.rect.width / 2f; float halfBirdW = birdRect.rect.width / 2f; Vector2 pos = birdRect.anchoredPosition; pos.x = Mathf.Clamp(pos.x, -halfW + halfBirdW, halfW - halfBirdW); birdRect.anchoredPosition = pos; } void SpawnBerries() { if (Time.time < nextSpawnTime) { return; } if (speedyLeft > 0) { nextSpawnTime = Time.time + 1f / (spawnRate * 1.875f); } else { nextSpawnTime = Time.time + 1f / spawnRate; } float spawnProbability = UnityEngine.Random.value; Image newBerry = Instantiate(berryTemplate).GetComponent(); newBerry.transform.SetParent(berryParent.transform, false); if (spawnProbability <= 0.425f) { newBerry.sprite = Resources.Load("Berries/Berry"); newBerry.tag = "NormalBerry"; } else if (spawnProbability <= 0.60f) { newBerry.sprite = Resources.Load("Berries/PoisonBerry"); newBerry.tag = "PoisonBerry"; } else if (spawnProbability <= 0.65f) { newBerry.sprite = Resources.Load("Berries/SlowBerry"); newBerry.tag = "SlowBerry"; } else if (spawnProbability <= 0.75f) { newBerry.sprite = Resources.Load("Berries/UltraBerry"); newBerry.tag = "UltraBerry"; } else if (spawnProbability <= 0.85f) { newBerry.sprite = Resources.Load("Berries/SpeedyBerry"); newBerry.tag = "SpeedyBerry"; } else if (spawnProbability <= 0.90f) { newBerry.sprite = Resources.Load("Berries/BerryNoColor"); newBerry.tag = "RandomBerry"; RainbowImage randomBerryRainbowImage = newBerry.gameObject.AddComponent(); randomBerryRainbowImage.frequency = 5f; } else if (spawnProbability <= 0.95f) { newBerry.sprite = Resources.Load("Berries/AntiBerry"); newBerry.tag = "AntiBerry"; } else { newBerry.sprite = Resources.Load("Berries/GoldenBerry"); newBerry.tag = "GoldenBerry"; } float spawnPositionX = UnityEngine.Random.Range(-(canvasRect.rect.width / 2 - newBerry.rectTransform.rect.width), canvasRect.rect.width / 2 - newBerry.rectTransform.rect.width); newBerry.transform.localPosition = new Vector3(spawnPositionX, (canvasRect.rect.height / 2) + newBerry.rectTransform.rect.height, 0f); newBerry.gameObject.SetActive(true); berries.Add(newBerry.gameObject); } public void Update() { if (rb.gravityScale != 100f * canvasRect.lossyScale.y) rb.gravityScale = 100f * canvasRect.lossyScale.y; SpawnBerries(); MoveBird(); if (boostLeft > 0f) { boostLeft -= Time.deltaTime; boostText.text = "Boost expires in " + string.Format("{0:0.0}", boostLeft) + "s"; } else if (slownessLeft > 0f) { slownessLeft -= Time.deltaTime; boostText.text = "Slowness expires in " + string.Format("{0:0.0}", slownessLeft) + "s"; } else if (speedyLeft > 0f) { speedyLeft -= Time.deltaTime; boostText.text = "Speed expires in " + string.Format("{0:0.0}", speedyLeft) + "s"; } else if (antiLeft > 0f) { antiLeft -= Time.deltaTime; boostText.text = "Berry repellent expires in " + string.Format("{0:0.0}", antiLeft) + "s"; } else if (goldenLeft > 0f) { goldenLeft -= Time.deltaTime; boostText.text = "Berry magnet expires in " + string.Format("{0:0.0}", goldenLeft) + "s"; } else { boostText.text = ""; } foreach (GameObject berry in berries.ToList()) { if (berry == null) { berries.Remove(berry); continue; } if (berry.GetComponent().anchoredPosition.y < -(canvasRect.rect.height / 2) - berry.GetComponent().rect.height) { noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); } else { CircleCollider2D birdCol = bird.GetComponent(); CircleCollider2D berryCol = berry.GetComponent(); Vector2 birdPos = bird.transform.position; Vector2 berryPos = berry.transform.position; float distance = Vector2.Distance(birdPos, berryPos); float radiusSum = (birdCol.radius / 2) + (berryCol.radius / 2); if (distance <= radiusSum) { switch (berry.tag) { case "NormalBerry": DoNormalBerry(berry); break; case "PoisonBerry": DoPoisonBerry(); break; case "SlowBerry": DoSlowBerry(berry); break; case "UltraBerry": DoUltraBerry(berry); break; case "SpeedyBerry": DoSpeedyBerry(berry); break; case "RandomBerry": DoRandomBerry(berry); break; case "AntiBerry": DoAntiBerry(berry); break; case "GoldenBerry": DoGoldenBerry(berry); break; } } } if (berry != null) berry.GetComponent().velocity = noGravityBerries.Contains(berry.GetInstanceID()) ? Vector2.zero : new Vector2(0f, speedyLeft == 0.0f ? (-300f * canvasRect.lossyScale.y) : (-550f * canvasRect.lossyScale.y)); } } void Respawn() { bird.GetComponent().anchoredPosition = new Vector3(0f, 64f, 0f); groundCollider.GetComponent().anchoredPosition = new Vector2(0f, -2.5f); bird.transform.localScale = new Vector3(1f, 1f, 1f); rb.velocity = new Vector3(); score = 0; boostLeft = 0f; slownessLeft = 0f; speedyLeft = 0f; antiLeft = 0f; UpdateStats(0, 1); foreach (GameObject berry in berries) Destroy(berry); berries.Clear(); noGravityBerries.Clear(); } void UpdateStats(int scoreAddAmount, int attemptAddAmount) { score += scoreAddAmount; attempts += attemptAddAmount; scoreText.text = string.Format("Score: {0} \u2022 Attempts: {1}", score, attempts); } void DoNormalBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Eat"), Camera.main.transform.position, 1.2f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); UpdateStats(1, 0); } void DoPoisonBerry() { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Death"), Camera.main.transform.position, 1.2f); Respawn(); UpdateStats(0, 0); } void DoSlowBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Downgrade"), Camera.main.transform.position, 0.35f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); boostLeft = 0f; slownessLeft = 10f; speedyLeft = 0f; antiLeft = 0f; goldenLeft = 0f; if (score > 0) { UpdateStats(-1, 0); } } void DoUltraBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Powerup"), Camera.main.transform.position, 0.35f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); speedyLeft = 0f; antiLeft = 0f; goldenLeft = 0f; if (slownessLeft > 0f) { slownessLeft = 0f; UpdateStats(1, 0); } else { boostLeft += 10f; UpdateStats(5, 0); } } void DoSpeedyBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/SpeedyPowerup"), Camera.main.transform.position, 0.35f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); boostLeft = 0f; slownessLeft = 0f; speedyLeft = 10f; antiLeft = 0f; goldenLeft = 0f; UpdateStats(10, 0); } void DoRandomBerry(GameObject berry) { Action[] funcs = { () => DoNormalBerry(berry), () => DoSlowBerry(berry), () => DoUltraBerry(berry), () => DoSpeedyBerry(berry), () => DoAntiBerry(berry), () => DoGoldenBerry(berry) }; funcs[UnityEngine.Random.Range(0, funcs.Length)](); } void DoAntiBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Downgrade"), Camera.main.transform.position, 0.35f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); boostLeft = 0f; slownessLeft = 0f; speedyLeft = 0f; antiLeft = 10f; goldenLeft = 0f; UpdateStats(0, 0); } void DoGoldenBerry(GameObject berry) { AudioSource.PlayClipAtPoint(Resources.Load("Sounds/Powerup"), Camera.main.transform.position, 0.35f); berries.Remove(berry); noGravityBerries.Remove(berry.GetInstanceID()); Destroy(berry); boostLeft = 0f; slownessLeft = 0f; speedyLeft = 0f; antiLeft = 0f; goldenLeft = 10f; UpdateStats(4, 0); } }