// GameManager.cs - Main game controller using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class GameManager : MonoBehaviour { [Header("Game Settings")] public int gridWidth = 8; public int gridHeight = 10; public float gemMoveSpeed = 10f; public int scoreMultiplier = 10; [Header("UI References")] public Text scoreText; public Text movesText; public Text levelText; public GameObject gameOverPanel; public Button restartButton; [Header("Prefabs")] public GameObject[] gemPrefabs; public GameObject explosionEffect; [Header("Audio")] public AudioSource audioSource; public AudioClip matchSound; public AudioClip moveSound; private Gem[,] grid; private int score = 0; private int moves = 30; private int level = 1; private bool isProcessingMove = false; void Start() { InitializeGame(); } void InitializeGame() { grid = new Gem[gridWidth, gridHeight]; CreateInitialGrid(); UpdateUI(); restartButton.onClick.AddListener(RestartGame); } void CreateInitialGrid() { for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { Vector2 position = new Vector2(x - gridWidth / 2f + 0.5f, y - gridHeight / 2f + 0.5f); CreateGem(x, y, position); } } // Ensure no initial matches while (HasMatches()) { for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { if (grid[x, y] != null && IsPartOfMatch(x, y)) { Destroy(grid[x, y].gameObject); Vector2 pos = new Vector2(x - gridWidth / 2f + 0.5f, y - gridHeight / 2f + 0.5f); CreateGem(x, y, pos); } } } } } void CreateGem(int x, int y, Vector2 position) { int gemType = Random.Range(0, gemPrefabs.Length); GameObject gemObj = Instantiate(gemPrefabs[gemType], position, Quaternion.identity); gemObj.transform.SetParent(transform); Gem gem = gemObj.GetComponent(); gem.Initialize(x, y, gemType, this); grid[x, y] = gem; } public void SwapGems(Gem gem1, Gem gem2) { if (isProcessingMove || moves <= 0) return; StartCoroutine(ProcessSwap(gem1, gem2)); } IEnumerator ProcessSwap(Gem gem1, Gem gem2) { isProcessingMove = true; // Swap positions in grid Vector2Int pos1 = new Vector2Int(gem1.gridX, gem1.gridY); Vector2Int pos2 = new Vector2Int(gem2.gridX, gem2.gridY); grid[pos1.x, pos1.y] = gem2; grid[pos2.x, pos2.y] = gem1; gem1.SetGridPosition(pos2.x, pos2.y); gem2.SetGridPosition(pos1.x, pos1.y); // Animate swap yield return StartCoroutine(MoveGemToPosition(gem1, GetWorldPosition(pos2.x, pos2.y))); yield return StartCoroutine(MoveGemToPosition(gem2, GetWorldPosition(pos1.x, pos1.y))); audioSource.PlayOneShot(moveSound); // Check for matches if (HasMatches()) { moves--; yield return StartCoroutine(ProcessMatches()); } else { // Invalid move - swap back grid[pos1.x, pos1.y] = gem1; grid[pos2.x, pos2.y] = gem2; gem1.SetGridPosition(pos1.x, pos1.y); gem2.SetGridPosition(pos2.x, pos2.y); yield return StartCoroutine(MoveGemToPosition(gem1, GetWorldPosition(pos1.x, pos1.y))); yield return StartCoroutine(MoveGemToPosition(gem2, GetWorldPosition(pos2.x, pos2.y))); } UpdateUI(); CheckGameOver(); isProcessingMove = false; } IEnumerator ProcessMatches() { bool foundMatches = true; while (foundMatches) { List matchedGems = FindAllMatches(); if (matchedGems.Count > 0) { // Add score score += matchedGems.Count * scoreMultiplier; audioSource.PlayOneShot(matchSound); // Create explosion effects and destroy gems foreach (Gem gem in matchedGems) { if (explosionEffect) { Instantiate(explosionEffect, gem.transform.position, Quaternion.identity); } grid[gem.gridX, gem.gridY] = null; Destroy(gem.gameObject); } yield return new WaitForSeconds(0.3f); // Drop gems down yield return StartCoroutine(DropGems()); // Fill empty spaces yield return StartCoroutine(FillEmptySpaces()); } else { foundMatches = false; } } } List FindAllMatches() { HashSet matches = new HashSet(); // Check horizontal matches for (int y = 0; y < gridHeight; y++) { for (int x = 0; x < gridWidth - 2; x++) { if (grid[x, y] != null && grid[x + 1, y] != null && grid[x + 2, y] != null) { if (grid[x, y].gemType == grid[x + 1, y].gemType && grid[x, y].gemType == grid[x + 2, y].gemType) { matches.Add(grid[x, y]); matches.Add(grid[x + 1, y]); matches.Add(grid[x + 2, y]); } } } } // Check vertical matches for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight - 2; y++) { if (grid[x, y] != null && grid[x, y + 1] != null && grid[x, y + 2] != null) { if (grid[x, y].gemType == grid[x, y + 1].gemType && grid[x, y].gemType == grid[x, y + 2].gemType) { matches.Add(grid[x, y]); matches.Add(grid[x, y + 1]); matches.Add(grid[x, y + 2]); } } } } return new List(matches); } bool HasMatches() { return FindAllMatches().Count > 0; } bool IsPartOfMatch(int x, int y) { if (grid[x, y] == null) return false; int gemType = grid[x, y].gemType; // Check horizontal int horizontalCount = 1; // Check left for (int i = x - 1; i >= 0; i--) { if (grid[i, y] != null && grid[i, y].gemType == gemType) horizontalCount++; else break; } // Check right for (int i = x + 1; i < gridWidth; i++) { if (grid[i, y] != null && grid[i, y].gemType == gemType) horizontalCount++; else break; } if (horizontalCount >= 3) return true; // Check vertical int verticalCount = 1; // Check down for (int i = y - 1; i >= 0; i--) { if (grid[x, i] != null && grid[x, i].gemType == gemType) verticalCount++; else break; } // Check up for (int i = y + 1; i < gridHeight; i++) { if (grid[x, i] != null && grid[x, i].gemType == gemType) verticalCount++; else break; } return verticalCount >= 3; } IEnumerator DropGems() { for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { if (grid[x, y] == null) { // Find gem above to drop for (int aboveY = y + 1; aboveY < gridHeight; aboveY++) { if (grid[x, aboveY] != null) { grid[x, y] = grid[x, aboveY]; grid[x, aboveY] = null; grid[x, y].SetGridPosition(x, y); StartCoroutine(MoveGemToPosition(grid[x, y], GetWorldPosition(x, y))); break; } } } } } yield return new WaitForSeconds(0.5f); } IEnumerator FillEmptySpaces() { for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { if (grid[x, y] == null) { Vector2 startPos = GetWorldPosition(x, gridHeight + 1); Vector2 endPos = GetWorldPosition(x, y); CreateGem(x, y, startPos); StartCoroutine(MoveGemToPosition(grid[x, y], endPos)); } } } yield return new WaitForSeconds(0.5f); } IEnumerator MoveGemToPosition(Gem gem, Vector2 targetPosition) { while (Vector2.Distance(gem.transform.position, targetPosition) > 0.1f) { gem.transform.position = Vector2.MoveTowards(gem.transform.position, targetPosition, gemMoveSpeed * Time.deltaTime); yield return null; } gem.transform.position = targetPosition; } Vector2 GetWorldPosition(int x, int y) { return new Vector2(x - gridWidth / 2f + 0.5f, y - gridHeight / 2f + 0.5f); } void UpdateUI() { scoreText.text = "Score: " + score.ToString(); movesText.text = "Moves: " + moves.ToString(); levelText.text = "Level: " + level.ToString(); } void CheckGameOver() { if (moves <= 0) { gameOverPanel.SetActive(true); } } public void RestartGame() { score = 0; moves = 30; level = 1; // Clear existing grid for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { if (grid[x, y] != null) { Destroy(grid[x, y].gameObject); } } } gameOverPanel.SetActive(false); CreateInitialGrid(); UpdateUI(); } } // Gem.cs - Individual gem behavior using UnityEngine; public class Gem : MonoBehaviour { public int gridX; public int gridY; public int gemType; private GameManager gameManager; private bool isDragging = false; private Vector2 startTouchPos; private Gem targetGem; public void Initialize(int x, int y, int type, GameManager manager) { gridX = x; gridY = y; gemType = type; gameManager = manager; } public void SetGridPosition(int x, int y) { gridX = x; gridY = y; } void OnMouseDown() { if (Input.touchCount > 0) { startTouchPos = Camera.main.ScreenToWorldPoint(Input.touches[0].position); } else { startTouchPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); } isDragging = true; } void OnMouseDrag() { if (!isDragging) return; Vector2 currentPos; if (Input.touchCount > 0) { currentPos = Camera.main.ScreenToWorldPoint(Input.touches[0].position); } else { currentPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); } Vector2 diff = currentPos - startTouchPos; if (diff.magnitude > 0.5f) { // Determine swipe direction if (Mathf.Abs(diff.x) > Mathf.Abs(diff.y)) { // Horizontal swipe if (diff.x > 0 && gridX < gameManager.gridWidth - 1) { targetGem = gameManager.grid[gridX + 1, gridY]; } else if (diff.x < 0 && gridX > 0) { targetGem = gameManager.grid[gridX - 1, gridY]; } } else { // Vertical swipe if (diff.y > 0 && gridY < gameManager.gridHeight - 1) { targetGem = gameManager.grid[gridX, gridY + 1]; } else if (diff.y < 0 && gridY > 0) { targetGem = gameManager.grid[gridX, gridY - 1]; } } if (targetGem != null) { gameManager.SwapGems(this, targetGem); isDragging = false; } } } void OnMouseUp() { isDragging = false; targetGem = null; } } // ExplosionEffect.cs - Particle effect for matches using UnityEngine; public class ExplosionEffect : MonoBehaviour { void Start() { // Auto-destroy after animation Destroy(gameObject, 1f); } } // AudioManager.cs - Manages game audio using UnityEngine; public class AudioManager : MonoBehaviour { public static AudioManager Instance; [Header("Audio Sources")] public AudioSource musicSource; public AudioSource sfxSource; [Header("Audio Clips")] public AudioClip backgroundMusic; public AudioClip matchSound; public AudioClip moveSound; public AudioClip gameOverSound; void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } void Start() { PlayBackgroundMusic(); } public void PlayBackgroundMusic() { if (backgroundMusic && musicSource) { musicSource.clip = backgroundMusic; musicSource.loop = true; musicSource.Play(); } } public void PlaySFX(AudioClip clip) { if (clip && sfxSource) { sfxSource.PlayOneShot(clip); } } public void SetMusicVolume(float volume) { if (musicSource) musicSource.volume = volume; } public void SetSFXVolume(float volume) { if (sfxSource) sfxSource.volume = volume; } } // SceneTransition.cs - Handles scene transitions using UnityEngine; using UnityEngine.SceneManagement; using System.Collections; public class SceneTransition : MonoBehaviour { public Animator transitionAnimator; public void LoadScene(string sceneName) { StartCoroutine(LoadSceneCoroutine(sceneName)); } IEnumerator LoadSceneCoroutine(string sceneName) { if (transitionAnimator) { transitionAnimator.SetTrigger("Start"); yield return new WaitForSeconds(1f); } SceneManager.LoadScene(sceneName); } public void RestartCurrentScene() { LoadScene(SceneManager.GetActiveScene().name); } public void QuitGame() { Application.Quit(); } } // TouchInputHandler.cs - Enhanced touch input for mobile using UnityEngine; public class TouchInputHandler : MonoBehaviour { public float swipeThreshold = 50f; public float tapThreshold = 0.1f; private Vector2 startTouchPosition; private Vector2 endTouchPosition; private float touchStartTime; void Update() { HandleTouch(); } void HandleTouch() { if (Input.touchCount > 0) { Touch touch = Input.touches[0]; switch (touch.phase) { case TouchPhase.Began: startTouchPosition = touch.position; touchStartTime = Time.time; break; case TouchPhase.Ended: endTouchPosition = touch.position; float touchDuration = Time.time - touchStartTime; float swipeDistance = Vector2.Distance(startTouchPosition, endTouchPosition); if (touchDuration < tapThreshold && swipeDistance < swipeThreshold) { // Tap detected HandleTap(touch.position); } else if (swipeDistance > swipeThreshold) { // Swipe detected HandleSwipe(); } break; } } // Mouse input for testing in editor #if UNITY_EDITOR if (Input.GetMouseButtonDown(0)) { startTouchPosition = Input.mousePosition; touchStartTime = Time.time; } else if (Input.GetMouseButtonUp(0)) { endTouchPosition = Input.mousePosition; float touchDuration = Time.time - touchStartTime; float swipeDistance = Vector2.Distance(startTouchPosition, endTouchPosition); if (touchDuration < tapThreshold && swipeDistance < swipeThreshold) { HandleTap(Input.mousePosition); } else if (swipeDistance > swipeThreshold) { HandleSwipe(); } } #endif } void HandleTap(Vector2 screenPosition) { Vector2 worldPosition = Camera.main.ScreenToWorldPoint(screenPosition); RaycastHit2D hit = Physics2D.Raycast(worldPosition, Vector2.zero); if (hit.collider != null) { Gem gem = hit.collider.GetComponent(); if (gem != null) { // Handle gem selection Debug.Log("Gem tapped: " + gem.gemType); } } } void HandleSwipe() { Vector2 swipeDirection = endTouchPosition - startTouchPosition; swipeDirection.Normalize(); // Determine swipe direction if (Mathf.Abs(swipeDirection.x) > Mathf.Abs(swipeDirection.y)) { if (swipeDirection.x > 0) { Debug.Log("Swipe Right"); } else { Debug.Log("Swipe Left"); } } else { if (swipeDirection.y > 0) { Debug.Log("Swipe Up"); } else { Debug.Log("Swipe Down"); } } } } // LevelManager.cs - Manages different levels and difficulty using UnityEngine; using System.Collections.Generic; [System.Serializable] public class LevelData { public int levelNumber; public int targetScore; public int movesAllowed; public int gemTypes; public Color backgroundColor; } public class LevelManager : MonoBehaviour { public List levels; public int currentLevel = 0; public LevelData GetCurrentLevel() { if (currentLevel < levels.Count) return levels[currentLevel]; // Generate endless levels LevelData endlessLevel = new LevelData { levelNumber = currentLevel + 1, targetScore = 1000 + (currentLevel * 500), movesAllowed = 30 - (currentLevel / 5), gemTypes = Mathf.Min(6, 4 + (currentLevel / 3)), backgroundColor = Color.HSVToRGB((currentLevel * 0.1f) % 1f, 0.3f, 0.8f) }; return endlessLevel; } public void NextLevel() { currentLevel++; } public void ResetToLevel(int level) { currentLevel = level; } } // PowerUp.cs - Special gem power-ups using UnityEngine; using System.Collections; public enum PowerUpType { Bomb, LineHorizontal, LineVertical, Rainbow } public class PowerUp : MonoBehaviour { public PowerUpType powerUpType; public GameObject explosionPrefab; public void ActivatePowerUp(int gridX, int gridY, GameManager gameManager) { switch (powerUpType) { case PowerUpType.Bomb: ActivateBomb(gridX, gridY, gameManager); break; case PowerUpType.LineHorizontal: ActivateLineHorizontal(gridY, gameManager); break; case PowerUpType.LineVertical: ActivateLineVertical(gridX, gameManager); break; case PowerUpType.Rainbow: ActivateRainbow(gameManager); break; } } void ActivateBomb(int centerX, int centerY, GameManager gameManager) { for (int x = centerX - 1; x <= centerX + 1; x++) { for (int y = centerY - 1; y <= centerY + 1; y++) { if (x >= 0 && x < gameManager.gridWidth && y >= 0 && y < gameManager.gridHeight) { if (gameManager.grid[x, y] != null) { if (explosionPrefab) { Instantiate(explosionPrefab, gameManager.grid[x, y].transform.position, Quaternion.identity); } Destroy(gameManager.grid[x, y].gameObject); gameManager.grid[x, y] = null; } } } } } void ActivateLineHorizontal(int row, GameManager gameManager) { for (int x = 0; x < gameManager.gridWidth; x++) { if (gameManager.grid[x, row] != null) { if (explosionPrefab) { Instantiate(explosionPrefab, gameManager.grid[x, row].transform.position, Quaternion.identity); } Destroy(gameManager.grid[x, row].gameObject); gameManager.grid[x, row] = null; } } } void ActivateLineVertical(int column, GameManager gameManager) { for (int y = 0; y < gameManager.gridHeight; y++) { if (gameManager.grid[column, y] != null) { if (explosionPrefab) { Instantiate(explosionPrefab, gameManager.grid[column, y].transform.position, Quaternion.identity); } Destroy(gameManager.grid[column, y].gameObject); gameManager.grid[column, y] = null; } } } void ActivateRainbow(GameManager gameManager) { // Destroy all gems of the most common type int[] gemCounts = new int[6]; for (int x = 0; x < gameManager.gridWidth; x++) { for (int y = 0; y < gameManager.gridHeight; y++) { if (gameManager.grid[x, y] != null) { gemCounts[gameManager.grid[x, y].gemType]++; } } } int mostCommonType = 0; int maxCount = 0; for (int i = 0; i < gemCounts.Length; i++) { if (gemCounts[i] > maxCount) { maxCount = gemCounts[i]; mostCommonType = i; } } for (int x = 0; x < gameManager.gridWidth; x++) { for (int y = 0; y < gameManager.gridHeight; y++) { if (gameManager.grid[x, y] != null && gameManager.grid[x, y].gemType == mostCommonType) { if (explosionPrefab) { Instantiate(explosionPrefab, gameManager.grid[x, y].transform.position, Quaternion.identity); } Destroy(gameManager.grid[x, y].gameObject); gameManager.grid[x, y] = null; } } } } }