Home > Mobile >  UnityEngine.MonoBehaviour:.ctor ()
UnityEngine.MonoBehaviour:.ctor ()

Time:11-23

I am trying to build a system that finds the nearest position of an object and uses it to transform the Player to a specific position. I understand the issue but I couldn't eliminate the yellow exclamation mark. The program is somehow working, but I'd like to see the solution.

The issue according to UnityConsole is: You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all UnityEngine.MonoBehaviour:.ctor ()

Scripts are: #1

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.Linq;

public class ScoreMultiplerFinder : MonoBehaviour

{
    private static ScoreMultiplerFinder instance;

    private List<GameObject> checkpoints = new List<GameObject>();

    public List<GameObject> Checkpoints { get { return checkpoints; } }

    public static ScoreMultiplerFinder Singleton
    {
        get
        {
            if (instance == null)
            {
                instance = new ScoreMultiplerFinder();
                instance.Checkpoints.AddRange(
                    GameObject.FindGameObjectsWithTag("Checkpoint"));

                instance.checkpoints = instance.checkpoints.OrderBy(waypoint => waypoint.name).ToList();
            }
            return instance;
        }
    }
}

#2(inPlayerObject)

 public void FindClosestMultiplier()
    {
        float lastDist = Mathf.Infinity;
        for (int i = 0; i < ScoreMultiplerFinder.Singleton.Checkpoints.Count; i  )
        {
            GameObject thisWP = ScoreMultiplerFinder.Singleton.Checkpoints[i];
            float distance = Vector3.Distance(transform.position, thisWP.transform.position);
            if (distance < lastDist)
            {
                currentIndex = i;
                lastDist = distance;
                lastScoreMultip.position = ScoreMultiplerFinder.Singleton.Checkpoints[currentIndex].transform.position;               
            }
        }      
    }

Thanks in advance and have a great day!

CodePudding user response:

see here

The error/warning is pretty much telling you what to do instead. A correct way to lazy initialize the Singleton would be

private List<GameObject> checkpoints;

// First of all be consequent and let nobody change the content of this
public IReadOnlyList<GameObject> Checkpoints => checkpoints;


public static ScoreMultiplerFinder Singleton
{
    get
    {
        if(instance) return instance;
        
        // before creating one check if there maybe is one already first
        instance = FindObjectOfType<ScoreMultiplerFinder>();

        if(instance) return instance;

        // GameObject is one of the very few UnityEngine.Object types where using 
        // "new" is actually okey 
        instance = new GameObject(nameof(ScoreMultiplerFinder)).AddComponent<ScoreMultiplerFinder>();
        
        return instance;
    }
}

private void Awake ()
{
    // Without this your "Singleton" is not complete and you rather only have a 
    // lazy factory property.
    // For a valid singleton pattern you have to make sure that there actually 
    // exists only one single instance at a time!
    if(instance && instance != this)
    {
        Destroy (gameObject);
        return;
    }

    instance = this;

    checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint").OrderBy(waypoint => waypoint.name).ToList();
}

And then if you already use Linq you are already familiar with OrderBy.

Your second script can be shrinked down to

public void FindClosestMultiplier()
{
    // Simply get the waypoints
    // - "OrderBy" them by distance. using the "sqrMagnitude" is faster and for ordering has exactly the same effect as 
    //   "Distance" which uses the more expensive "magnitude"
    // - use "FirstOrDefault" to get either the closest item or "null" if there wasn't any at all
    var closest = ScoreMultiplerFinder.Singleton.Checkpoints.OrderBy(c => (transform.position - c.transform.position).sqrMagnitude).FirstOrDefault();
   
    // Was there any at all? 
    if(!closest) return; 

    // Otherwise "closest" is the closest waypoint -> do something with it
    lastScoreMultip.position = closest.position;  
}

Actually as mentioned I don't think you need a MonoBehaviour at all.

You could as well simply have

public static class ScoreMultiplerFinder
{
    private static List<GameObject> checkpoints;

    public static IReadOnlyList<GameObject> Checkpoints 
    { 
         get 
         { 
             if(checkpoints == null) checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint").OrderBy(waypoint => waypoint.name).ToList(); 

             return checkpoints;
         } 
     }
}

and then accordingly do

public void FindClosestMultiplier()
{
    var closest = ScoreMultiplerFinder.Checkpoints.OrderBy(c => (transform.position - c.transform.position).sqrMagnitude).FirstOrDefault();
   
    if(!closest) return; 

    lastScoreMultip.position = closest.position;  
}
  • Related