I have a complex mobile project in Unity called Cake Sort 3D, which was my first freelance job. I think I may have made a few mistakes along the way.
Everything was working perfectly until I translated the plate movement code to handle screen touch input. I didn’t realize the issue until I started building the project. Unity’s issue tracker reported that the engine couldn’t enter Play mode, and I thought, "How is that possible? It was working fine before."
When I tested it myself, I discovered that if the PlateManager class runs at the start, the code gets stuck in an infinite loop and Play mode doesn’t start. For the past two days, I’ve been trying to figure out the source of the infinite loop, but I haven’t been able to pinpoint it yet.
Here are the PlateManager and input classes, along with other classes that might be causing the infinite loop.
Plate Moving Script
using System.Collections;
using UnityEngine;
public class DragAndDropMouse : MonoBehaviour
{
private bool _isDragging;
public GameObject[] plateHolders;
private GameObject draggingObj;
private GameObject holderToSnap;
[SerializeField] public bool isMoveable = true;
[SerializeField] private Plate plate;
[SerializeField] private GameObject plane;
[SerializeField] private PlateManager Manager;
private ScoreManager scm;
private SoundPlayer soundPlayer;
SkillManager sm;
SwitchController switchController;
private bool isThereUnused = false;
Vector3 StartPosition;
private bool canCreate = true;
private void Start()
{
plate = GetComponent<Plate>();
sm = GameObject.FindGameObjectWithTag("SkillManager").GetComponent<SkillManager>();
soundPlayer = GameObject.FindGameObjectWithTag("SoundPlayer").GetComponent<SoundPlayer>();
plateHolders = GameObject.FindGameObjectsWithTag("PlateHolder");
scm = GameObject.FindGameObjectWithTag("ScoreManager").GetComponent<ScoreManager>();
Manager = GameObject.FindGameObjectWithTag("PlateManager").GetComponent<PlateManager>();
plane = GameObject.FindGameObjectWithTag("Plane");
if (Manager != null)
{
switchController = Manager.GetComponent<SwitchController>();
Debug.Log(switchController);
}
plate.snappedHolder = null;
}
private void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
switch (touch.phase)
{
case TouchPhase.Began:
OnTouchDown(touch);
break;
case TouchPhase.Moved:
OnTouchDrag(touch);
break;
case TouchPhase.Ended:
OnTouchUp();
break;
}
}
}
private void OnTouchDown(Touch touch)
{
if (switchController == null)
{
switchController = Manager?.GetComponent<SwitchController>();
Debug.Log(switchController != null ? "SwitchController bulundu." : "SwitchController hala null.");
}
if (switchController != null && switchController.SwitchSkillActive)
{
Ray ray2 = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray2, out RaycastHit hit2) && hit2.collider.tag.StartsWith("Cake"))
{
draggingObj = hit2.collider.gameObject;
}
Manager.GetComponent<SwitchController>().MouseDownSwitchSkill(hit2.collider.gameObject);
return;
}
if (Manager == null)
{
Manager = GetComponent<Plate>().manager;
}
Ray ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider.tag.StartsWith("Cake") && isMoveable)
{
draggingObj = hit.collider.gameObject;
StartPosition = draggingObj.transform.position;
draggingObj.GetComponent<BoxCollider>().enabled = false;
_isDragging = true;
}
else if (sm.handSkill && plate.snappedHolder != null)
{
draggingObj = hit.collider.gameObject;
draggingObj.GetComponent<BoxCollider>().enabled = false;
_isDragging = true;
}
else if (sm.hammerSkill && plate.snappedHolder != null)
{
hit.collider.gameObject.GetComponent<Plate>().snappedHolder.GetComponent<PlateHolder>().isUsed = false;
Destroy(hit.collider.gameObject);
sm.hammerSkill = false;
sm.ExecuteSkill();
}
}
private void OnTouchDrag(Touch touch)
{
if (_isDragging && draggingObj != null)
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, LayerMask.GetMask("Ignore Raycast")) && hit.collider.gameObject == plane)
{
Vector3 newPos = hit.point;
draggingObj.transform.position = new Vector3(newPos.x, transform.position.y, newPos.z);
}
}
}
private void OnTouchUp()
{
if (switchController.SwitchSkillActive) return;
MouseUp(draggingObj);
}
public void SnapPlateToHolder(GameObject plateObj, GameObject targetHolder)
{
var plateComponent = plateObj.GetComponent<Plate>();
var targetHolderComponent = targetHolder.GetComponent<PlateHolder>();
if (plateComponent.snappedHolder != null)
{
plateComponent.snappedHolder.GetComponent<PlateHolder>().isUsed = false;
}
plateObj.transform.position = new Vector3(targetHolder.transform.position.x, plateObj.transform.position.y, targetHolder.transform.position.z);
plateComponent.snappedHolder = targetHolder;
targetHolderComponent.isUsed = true;
plateComponent.GetComponent<DragAndDropMouse>().isMoveable = false;
holderToSnap = targetHolder;
if (sm.remainingSkills == 0)
{
StartCoroutine(finishController(plateHolders));
}
StartCoroutine(plateComponent.CheckSurroundingPlates(plateObj));
}
public void MouseUp(GameObject draggingObj)
{
if ((draggingObj != null && isMoveable) || sm.handSkill)
{
draggingObj.GetComponent<BoxCollider>().enabled = true;
_isDragging = false;
GameObject closestHolder = SnapToClosestHolder();
if (closestHolder != null)
{
soundPlayer.PlaySound("Plate");
SnapPlateToHolder(draggingObj, closestHolder);
}
else
{
canCreate = false;
draggingObj.transform.position = StartPosition;
Debug.Log("No unused plateholder found.");
}
draggingObj = null;
sm.ExecuteSkill();
sm.handSkill = false;
}
}
private GameObject SnapToClosestHolder()
{
GameObject closestHolder = null;
float closestDistance = Mathf.Infinity;
foreach (GameObject holder in plateHolders)
{
if (!holder.GetComponent<PlateHolder>().isUsed)
{
float distance = Vector3.Distance(transform.position, holder.transform.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestHolder = holder;
}
}
}
return closestHolder;
}
private IEnumerator finishController(GameObject[] holders) // controls if game has no moves left
{
int counter = 0;
while (counter <= 5)
{
isThereUnused = false;
foreach (GameObject holder in holders)
{
if (!holder.GetComponent<PlateHolder>().isUsed)
{
isThereUnused = true;
break; // En az bir kullanılmayan holder bulunduğunda kontrolü bitir
}
}
if (!isThereUnused)
{
yield return new WaitForSeconds(1); // Belirli bir süre bekle
counter++; // Sayaç artır
}
else
{
yield break;
}
}
scm.ResetLevel();
GameObject.FindGameObjectWithTag("Lost").SetActive(true);
}
}
Plate Manager
using System.Collections;
using UnityEngine;
public class PlateManager : MonoBehaviour
{
[SerializeField] public GameObject[] cakePrefabs;
[SerializeField] private GameObject platePrefab;
[SerializeField] private Transform createReference;
[SerializeField] private Transform[] lerpPositions;
GameObject[] plates = new GameObject[3];
public bool isProcessing = false;
[SerializeField] private float moveSpeed = 2.0f;
public int plateNumber = 0;
void Start()
{
createNewPlates();
}
public void decreaseNumber()
{
plateNumber--;
if (plateNumber == 0)
{
createNewPlates();
}
}
public void createNewPlates()
{
for (int i = 0; i < 3; i++)
{
plates[i] = Instantiate(platePrefab, createReference.position, Quaternion.identity);
plates[i].GetComponent<Collider>().enabled = false;
StartCoroutine(plateMover(plates[i], i));
}
plateNumber = 3;
}
public IEnumerator plateMover(GameObject plate, int index)
{
int safetyCounter = 0;
int maxIterations = 1000;
// Move the plate until it is close enough to the target position
while (Vector3.Distance(lerpPositions[index].position, plate.transform.position) > 0.1f)
{
plate.transform.position = Vector3.Lerp(plate.transform.position, lerpPositions[index].position, Time.deltaTime * moveSpeed);
yield return null;
safetyCounter++;
if (safetyCounter > maxIterations)
{
Debug.LogError($"Plate {index} hedef pozisyona taşınamıyor. Emniyet sınırına ulaşıldı!");
yield break;
}
}
// Ensure the plate is exactly at the target position
plate.transform.position = lerpPositions[index].position;
plate.GetComponent<Collider>().enabled = true;
}
public GameObject[] getCakePrefab(string[] types)
{
GameObject[] typesToReturn = new GameObject[types.Length];
for (int i = 0; i < types.Length; i++)
{
string type = types[i];
if (type.StartsWith("Cake") && int.TryParse(type.Substring(4), out int cakeNumber))
{
if (cakeNumber >= 1 && cakeNumber <= cakePrefabs.Length)
{
typesToReturn[i] = cakePrefabs[cakeNumber - 1];
}
else
{
Debug.LogWarning("Belirtilen cakeNumber geçerli değil: " + cakeNumber);
typesToReturn[i] = null;
}
}
else
{
Debug.LogWarning("Geçersiz cake türü: " + type);
typesToReturn[i] = null;
}
}
return typesToReturn;
}
public GameObject getCakePrefab(string type)
{
if (type.StartsWith("Cake") && int.TryParse(type.Substring(4), out int cakeNumber))
{
if (cakeNumber >= 1 && cakeNumber <= 10)
{
return cakePrefabs[cakeNumber - 1];
}
}
return null;
}
}
Plate Class
using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Plate : MonoBehaviour
{
public GameObject snappedHolder;
public byte CakeIndex = 0;
public byte CakeIndex2 = 0;
public int TotalCakeIndex => CakeIndex + CakeIndex2;
public bool isEvenTyped;
public bool isSwapped = false;
public string[] cakeTypes;
public string cakeType;
private GameObject[] prefabs;
private GameObject prefab;
[SerializeField] public int maxCakeTypeIndex;
[SerializeField] public float[] rotations;
[SerializeField] public PlateManager manager;
public bool isWorking = false;
private CakeTransferRemastered cakeTransfer;
public bool canInstantiateCakes = true;
private void Start()
{
maxCakeTypeIndex = GameObject.FindGameObjectWithTag("ScoreManager").GetComponent<ScoreManager>().maxIndexOfCakes;
cakeTransfer = GetComponent<CakeTransferRemastered>();
manager = GameObject.FindGameObjectWithTag("PlateManager").GetComponent<PlateManager>();
if (canInstantiateCakes)
{
InitializePlate();
InstantiateCakeObjects();
}
else
{
GetComponent<DragAndDropMouse>().MouseUp(gameObject);
}
}
private void InitializePlate()
{
cakeTypes = new string[2];
gameObject.tag = "Cake" + Random.Range(1, 10);
}
private void InstantiateCakeObjects()
{
if (Random.Range(1, 3) == 2)
{
isEvenTyped = false;
CakeIndex = (byte)Random.Range(1, 4);
cakeType = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
prefab = manager?.getCakePrefab(cakeType);
InstantiateCakeLayers(prefab, CakeIndex,0);
}
else
{
isEvenTyped = true;
CakeIndex = 1;
CakeIndex2 = 3;
cakeTypes[0] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
cakeTypes[1] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
while (cakeTypes[0] == cakeTypes[1])
{
cakeTypes[1] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
}
prefabs = manager?.getCakePrefab(cakeTypes);
if (prefabs != null)
{
InstantiateCakeLayers(prefabs[0], CakeIndex, 0);
InstantiateCakeLayers(prefabs[1], CakeIndex2, CakeIndex);
if (cakeTransfer.isContainsSingleType(gameObject))
{
cakeTypes[1] = string.Empty;
}
}
else
{
Debug.LogWarning("Prefab bulunamadı veya PlateManager atanmamış.");
}
}
}
private void InstantiateCakeLayers(GameObject cakePrefab, int layers, int startRotationIndex)
{
for (int i = startRotationIndex; i < layers; i++)
{
GameObject cakeLayer = Instantiate(cakePrefab, transform);
cakeLayer.transform.localScale = new Vector3(60f, 2500f, 60f);
cakeLayer.transform.localPosition = Vector3.zero;
cakeLayer.transform.eulerAngles = new Vector3(0, rotations[i], 0);
}
}
public IEnumerator CheckSurroundingPlates(GameObject thisPlate)
{
isWorking = true;
List<string> controlledIds = new List<string>();
int processCount = 0;
Vector3[] directions = { Vector3.forward, Vector3.back, Vector3.left, Vector3.right };
Dictionary<GameObject, int> detectedPlates = new Dictionary<GameObject, int>();
ControlDirections(directions, ref detectedPlates);
bool isCommon = CheckForCommonCakes(thisPlate, detectedPlates);
while (detectedPlates.Count > 0 && isCommon && processCount <= 4)
{
var firstPlate = detectedPlates.OrderBy(x => x.Value).First();
foreach (GameObject detected in detectedPlates.Keys)
{
if (controlledIds.Contains(detected.GetInstanceID().ToString()))
{
processCount++;
}
else
{
controlledIds.Add(detected.GetInstanceID().ToString());
yield return StartCoroutine(cakeTransfer.StartTransfer(thisPlate, detected, isEvenTyped, detected.GetComponent<Plate>().isEvenTyped));
}
}
detectedPlates.Clear();
ControlDirections(directions, ref detectedPlates);
isCommon = CheckForCommonCakes(thisPlate, detectedPlates);
}
yield return new WaitForEndOfFrame();
isWorking = false;
}
private bool CheckForCommonCakes(GameObject thisPlate, Dictionary<GameObject, int> detectedPlates)
{
foreach (GameObject detectedPlate in detectedPlates.Keys)
{
if (cakeTransfer.ControlCommonCakes(thisPlate, detectedPlate) >= 1)
{
return true;
}
}
return false;
}
private void ControlDirections(Vector3[] directions, ref Dictionary<GameObject, int> detectedPlates)
{
detectedPlates = new Dictionary<GameObject, int>();
foreach (Vector3 direction in directions)
{
if (Physics.Raycast(transform.position, direction, out RaycastHit hit, 4.0f) && hit.collider.gameObject != gameObject)
{
Plate hitPlate = hit.collider.GetComponent<Plate>();
if (hitPlate != null)
{
detectedPlates.Add(hit.collider.gameObject, hitPlate.TotalCakeIndex);
}
}
}
}
private void OnDestroy()
{
manager.decreaseNumber();
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, Vector3.forward * 4);
Gizmos.DrawRay(transform.position, Vector3.back * 4);
Gizmos.DrawRay(transform.position, Vector3.left * 4);
Gizmos.DrawRay(transform.position, Vector3.right * 4);
}
}
DragAndDropMouse and Plate classes are attached to every plate object in the scene as prefabs.
I have a complex mobile project in Unity called Cake Sort 3D, which was my first freelance job. I think I may have made a few mistakes along the way.
Everything was working perfectly until I translated the plate movement code to handle screen touch input. I didn’t realize the issue until I started building the project. Unity’s issue tracker reported that the engine couldn’t enter Play mode, and I thought, "How is that possible? It was working fine before."
When I tested it myself, I discovered that if the PlateManager class runs at the start, the code gets stuck in an infinite loop and Play mode doesn’t start. For the past two days, I’ve been trying to figure out the source of the infinite loop, but I haven’t been able to pinpoint it yet.
Here are the PlateManager and input classes, along with other classes that might be causing the infinite loop.
Plate Moving Script
using System.Collections;
using UnityEngine;
public class DragAndDropMouse : MonoBehaviour
{
private bool _isDragging;
public GameObject[] plateHolders;
private GameObject draggingObj;
private GameObject holderToSnap;
[SerializeField] public bool isMoveable = true;
[SerializeField] private Plate plate;
[SerializeField] private GameObject plane;
[SerializeField] private PlateManager Manager;
private ScoreManager scm;
private SoundPlayer soundPlayer;
SkillManager sm;
SwitchController switchController;
private bool isThereUnused = false;
Vector3 StartPosition;
private bool canCreate = true;
private void Start()
{
plate = GetComponent<Plate>();
sm = GameObject.FindGameObjectWithTag("SkillManager").GetComponent<SkillManager>();
soundPlayer = GameObject.FindGameObjectWithTag("SoundPlayer").GetComponent<SoundPlayer>();
plateHolders = GameObject.FindGameObjectsWithTag("PlateHolder");
scm = GameObject.FindGameObjectWithTag("ScoreManager").GetComponent<ScoreManager>();
Manager = GameObject.FindGameObjectWithTag("PlateManager").GetComponent<PlateManager>();
plane = GameObject.FindGameObjectWithTag("Plane");
if (Manager != null)
{
switchController = Manager.GetComponent<SwitchController>();
Debug.Log(switchController);
}
plate.snappedHolder = null;
}
private void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
switch (touch.phase)
{
case TouchPhase.Began:
OnTouchDown(touch);
break;
case TouchPhase.Moved:
OnTouchDrag(touch);
break;
case TouchPhase.Ended:
OnTouchUp();
break;
}
}
}
private void OnTouchDown(Touch touch)
{
if (switchController == null)
{
switchController = Manager?.GetComponent<SwitchController>();
Debug.Log(switchController != null ? "SwitchController bulundu." : "SwitchController hala null.");
}
if (switchController != null && switchController.SwitchSkillActive)
{
Ray ray2 = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray2, out RaycastHit hit2) && hit2.collider.tag.StartsWith("Cake"))
{
draggingObj = hit2.collider.gameObject;
}
Manager.GetComponent<SwitchController>().MouseDownSwitchSkill(hit2.collider.gameObject);
return;
}
if (Manager == null)
{
Manager = GetComponent<Plate>().manager;
}
Ray ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider.tag.StartsWith("Cake") && isMoveable)
{
draggingObj = hit.collider.gameObject;
StartPosition = draggingObj.transform.position;
draggingObj.GetComponent<BoxCollider>().enabled = false;
_isDragging = true;
}
else if (sm.handSkill && plate.snappedHolder != null)
{
draggingObj = hit.collider.gameObject;
draggingObj.GetComponent<BoxCollider>().enabled = false;
_isDragging = true;
}
else if (sm.hammerSkill && plate.snappedHolder != null)
{
hit.collider.gameObject.GetComponent<Plate>().snappedHolder.GetComponent<PlateHolder>().isUsed = false;
Destroy(hit.collider.gameObject);
sm.hammerSkill = false;
sm.ExecuteSkill();
}
}
private void OnTouchDrag(Touch touch)
{
if (_isDragging && draggingObj != null)
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, LayerMask.GetMask("Ignore Raycast")) && hit.collider.gameObject == plane)
{
Vector3 newPos = hit.point;
draggingObj.transform.position = new Vector3(newPos.x, transform.position.y, newPos.z);
}
}
}
private void OnTouchUp()
{
if (switchController.SwitchSkillActive) return;
MouseUp(draggingObj);
}
public void SnapPlateToHolder(GameObject plateObj, GameObject targetHolder)
{
var plateComponent = plateObj.GetComponent<Plate>();
var targetHolderComponent = targetHolder.GetComponent<PlateHolder>();
if (plateComponent.snappedHolder != null)
{
plateComponent.snappedHolder.GetComponent<PlateHolder>().isUsed = false;
}
plateObj.transform.position = new Vector3(targetHolder.transform.position.x, plateObj.transform.position.y, targetHolder.transform.position.z);
plateComponent.snappedHolder = targetHolder;
targetHolderComponent.isUsed = true;
plateComponent.GetComponent<DragAndDropMouse>().isMoveable = false;
holderToSnap = targetHolder;
if (sm.remainingSkills == 0)
{
StartCoroutine(finishController(plateHolders));
}
StartCoroutine(plateComponent.CheckSurroundingPlates(plateObj));
}
public void MouseUp(GameObject draggingObj)
{
if ((draggingObj != null && isMoveable) || sm.handSkill)
{
draggingObj.GetComponent<BoxCollider>().enabled = true;
_isDragging = false;
GameObject closestHolder = SnapToClosestHolder();
if (closestHolder != null)
{
soundPlayer.PlaySound("Plate");
SnapPlateToHolder(draggingObj, closestHolder);
}
else
{
canCreate = false;
draggingObj.transform.position = StartPosition;
Debug.Log("No unused plateholder found.");
}
draggingObj = null;
sm.ExecuteSkill();
sm.handSkill = false;
}
}
private GameObject SnapToClosestHolder()
{
GameObject closestHolder = null;
float closestDistance = Mathf.Infinity;
foreach (GameObject holder in plateHolders)
{
if (!holder.GetComponent<PlateHolder>().isUsed)
{
float distance = Vector3.Distance(transform.position, holder.transform.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestHolder = holder;
}
}
}
return closestHolder;
}
private IEnumerator finishController(GameObject[] holders) // controls if game has no moves left
{
int counter = 0;
while (counter <= 5)
{
isThereUnused = false;
foreach (GameObject holder in holders)
{
if (!holder.GetComponent<PlateHolder>().isUsed)
{
isThereUnused = true;
break; // En az bir kullanılmayan holder bulunduğunda kontrolü bitir
}
}
if (!isThereUnused)
{
yield return new WaitForSeconds(1); // Belirli bir süre bekle
counter++; // Sayaç artır
}
else
{
yield break;
}
}
scm.ResetLevel();
GameObject.FindGameObjectWithTag("Lost").SetActive(true);
}
}
Plate Manager
using System.Collections;
using UnityEngine;
public class PlateManager : MonoBehaviour
{
[SerializeField] public GameObject[] cakePrefabs;
[SerializeField] private GameObject platePrefab;
[SerializeField] private Transform createReference;
[SerializeField] private Transform[] lerpPositions;
GameObject[] plates = new GameObject[3];
public bool isProcessing = false;
[SerializeField] private float moveSpeed = 2.0f;
public int plateNumber = 0;
void Start()
{
createNewPlates();
}
public void decreaseNumber()
{
plateNumber--;
if (plateNumber == 0)
{
createNewPlates();
}
}
public void createNewPlates()
{
for (int i = 0; i < 3; i++)
{
plates[i] = Instantiate(platePrefab, createReference.position, Quaternion.identity);
plates[i].GetComponent<Collider>().enabled = false;
StartCoroutine(plateMover(plates[i], i));
}
plateNumber = 3;
}
public IEnumerator plateMover(GameObject plate, int index)
{
int safetyCounter = 0;
int maxIterations = 1000;
// Move the plate until it is close enough to the target position
while (Vector3.Distance(lerpPositions[index].position, plate.transform.position) > 0.1f)
{
plate.transform.position = Vector3.Lerp(plate.transform.position, lerpPositions[index].position, Time.deltaTime * moveSpeed);
yield return null;
safetyCounter++;
if (safetyCounter > maxIterations)
{
Debug.LogError($"Plate {index} hedef pozisyona taşınamıyor. Emniyet sınırına ulaşıldı!");
yield break;
}
}
// Ensure the plate is exactly at the target position
plate.transform.position = lerpPositions[index].position;
plate.GetComponent<Collider>().enabled = true;
}
public GameObject[] getCakePrefab(string[] types)
{
GameObject[] typesToReturn = new GameObject[types.Length];
for (int i = 0; i < types.Length; i++)
{
string type = types[i];
if (type.StartsWith("Cake") && int.TryParse(type.Substring(4), out int cakeNumber))
{
if (cakeNumber >= 1 && cakeNumber <= cakePrefabs.Length)
{
typesToReturn[i] = cakePrefabs[cakeNumber - 1];
}
else
{
Debug.LogWarning("Belirtilen cakeNumber geçerli değil: " + cakeNumber);
typesToReturn[i] = null;
}
}
else
{
Debug.LogWarning("Geçersiz cake türü: " + type);
typesToReturn[i] = null;
}
}
return typesToReturn;
}
public GameObject getCakePrefab(string type)
{
if (type.StartsWith("Cake") && int.TryParse(type.Substring(4), out int cakeNumber))
{
if (cakeNumber >= 1 && cakeNumber <= 10)
{
return cakePrefabs[cakeNumber - 1];
}
}
return null;
}
}
Plate Class
using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Plate : MonoBehaviour
{
public GameObject snappedHolder;
public byte CakeIndex = 0;
public byte CakeIndex2 = 0;
public int TotalCakeIndex => CakeIndex + CakeIndex2;
public bool isEvenTyped;
public bool isSwapped = false;
public string[] cakeTypes;
public string cakeType;
private GameObject[] prefabs;
private GameObject prefab;
[SerializeField] public int maxCakeTypeIndex;
[SerializeField] public float[] rotations;
[SerializeField] public PlateManager manager;
public bool isWorking = false;
private CakeTransferRemastered cakeTransfer;
public bool canInstantiateCakes = true;
private void Start()
{
maxCakeTypeIndex = GameObject.FindGameObjectWithTag("ScoreManager").GetComponent<ScoreManager>().maxIndexOfCakes;
cakeTransfer = GetComponent<CakeTransferRemastered>();
manager = GameObject.FindGameObjectWithTag("PlateManager").GetComponent<PlateManager>();
if (canInstantiateCakes)
{
InitializePlate();
InstantiateCakeObjects();
}
else
{
GetComponent<DragAndDropMouse>().MouseUp(gameObject);
}
}
private void InitializePlate()
{
cakeTypes = new string[2];
gameObject.tag = "Cake" + Random.Range(1, 10);
}
private void InstantiateCakeObjects()
{
if (Random.Range(1, 3) == 2)
{
isEvenTyped = false;
CakeIndex = (byte)Random.Range(1, 4);
cakeType = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
prefab = manager?.getCakePrefab(cakeType);
InstantiateCakeLayers(prefab, CakeIndex,0);
}
else
{
isEvenTyped = true;
CakeIndex = 1;
CakeIndex2 = 3;
cakeTypes[0] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
cakeTypes[1] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
while (cakeTypes[0] == cakeTypes[1])
{
cakeTypes[1] = "Cake" + Random.Range(1, maxCakeTypeIndex+1);
}
prefabs = manager?.getCakePrefab(cakeTypes);
if (prefabs != null)
{
InstantiateCakeLayers(prefabs[0], CakeIndex, 0);
InstantiateCakeLayers(prefabs[1], CakeIndex2, CakeIndex);
if (cakeTransfer.isContainsSingleType(gameObject))
{
cakeTypes[1] = string.Empty;
}
}
else
{
Debug.LogWarning("Prefab bulunamadı veya PlateManager atanmamış.");
}
}
}
private void InstantiateCakeLayers(GameObject cakePrefab, int layers, int startRotationIndex)
{
for (int i = startRotationIndex; i < layers; i++)
{
GameObject cakeLayer = Instantiate(cakePrefab, transform);
cakeLayer.transform.localScale = new Vector3(60f, 2500f, 60f);
cakeLayer.transform.localPosition = Vector3.zero;
cakeLayer.transform.eulerAngles = new Vector3(0, rotations[i], 0);
}
}
public IEnumerator CheckSurroundingPlates(GameObject thisPlate)
{
isWorking = true;
List<string> controlledIds = new List<string>();
int processCount = 0;
Vector3[] directions = { Vector3.forward, Vector3.back, Vector3.left, Vector3.right };
Dictionary<GameObject, int> detectedPlates = new Dictionary<GameObject, int>();
ControlDirections(directions, ref detectedPlates);
bool isCommon = CheckForCommonCakes(thisPlate, detectedPlates);
while (detectedPlates.Count > 0 && isCommon && processCount <= 4)
{
var firstPlate = detectedPlates.OrderBy(x => x.Value).First();
foreach (GameObject detected in detectedPlates.Keys)
{
if (controlledIds.Contains(detected.GetInstanceID().ToString()))
{
processCount++;
}
else
{
controlledIds.Add(detected.GetInstanceID().ToString());
yield return StartCoroutine(cakeTransfer.StartTransfer(thisPlate, detected, isEvenTyped, detected.GetComponent<Plate>().isEvenTyped));
}
}
detectedPlates.Clear();
ControlDirections(directions, ref detectedPlates);
isCommon = CheckForCommonCakes(thisPlate, detectedPlates);
}
yield return new WaitForEndOfFrame();
isWorking = false;
}
private bool CheckForCommonCakes(GameObject thisPlate, Dictionary<GameObject, int> detectedPlates)
{
foreach (GameObject detectedPlate in detectedPlates.Keys)
{
if (cakeTransfer.ControlCommonCakes(thisPlate, detectedPlate) >= 1)
{
return true;
}
}
return false;
}
private void ControlDirections(Vector3[] directions, ref Dictionary<GameObject, int> detectedPlates)
{
detectedPlates = new Dictionary<GameObject, int>();
foreach (Vector3 direction in directions)
{
if (Physics.Raycast(transform.position, direction, out RaycastHit hit, 4.0f) && hit.collider.gameObject != gameObject)
{
Plate hitPlate = hit.collider.GetComponent<Plate>();
if (hitPlate != null)
{
detectedPlates.Add(hit.collider.gameObject, hitPlate.TotalCakeIndex);
}
}
}
}
private void OnDestroy()
{
manager.decreaseNumber();
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, Vector3.forward * 4);
Gizmos.DrawRay(transform.position, Vector3.back * 4);
Gizmos.DrawRay(transform.position, Vector3.left * 4);
Gizmos.DrawRay(transform.position, Vector3.right * 4);
}
}
DragAndDropMouse and Plate classes are attached to every plate object in the scene as prefabs.
Share Improve this question edited Nov 16, 2024 at 7:30 DevOfDreams asked Nov 16, 2024 at 7:15 DevOfDreamsDevOfDreams 113 bronze badges 6 | Show 1 more comment1 Answer
Reset to default 0From DevOfDreams (QP) in the comments:
Finally, I found the problem. When the plates were instantiated, there was a controller that checks if the first type matches the second type. For some reason, I had limited the maximum number of cake types to 1. As a result, even though the plates had two types, they ended up being assigned a single type, since there was no other type available. This caused an endless loop of attempts to find another cake type. Thanks for help. Problem solved.
createNewPlates();
to see if the game can start? – shingo Commented Nov 16, 2024 at 7:37createNewPlates
, you can gradually try statement by statement until you find the line with the problem. – shingo Commented Nov 16, 2024 at 7:55