unity3d 从光线投射检测命中的池中调用对象后,得分计数器不增加

ruarlubt  于 2022-11-16  发布在  其他
关注(0)|答案(1)|浏览(121)

上下文

你好,又是我。我一直在玩“对象池”,它可以保存大量的CPU性能,这很有趣。但是,我遇到了一个新的“功能”,它为被调用和通过管道的对象评分一次。
在我的对象池中,我有一个正在被示例化的管道游戏对象,并设置它的方法Active(false),直到它被产生。一旦产生,我的预制件将根据对象池的大小填充。

问题

一旦它产卵,它做它应该做的,得分和相同的机制“Flappy Bird”。然而,一旦对象再次进入活动状态,它似乎不再得分,因为它被一个球员通过。我所做的是有一个标志,检查球员是否(鸟)过不过管子,但是我过的时候,它会将其更新为6次(每帧一分)。你可能会问“你是否为管道本身做了另一个标志?”那么答案是。我也试过这种方法,但它只会保持一次分数,不会增加超过5分。
我对对象池的方法已经没有什么想法了。如果它是没有对象池的话,它似乎工作得很好,但是这里的缺陷是它会降低我的CPU性能。

它可以将该值仅增加1,也可以将其增加6倍(因为对于对象位于光线中的每一帧,它都将计算另一个点)。

次尝试

我浏览了Unity学习中心,了解如何进行对象池化,结果并不像我想的那么糟糕。后来,我发现了这个问题,我认为这是我的逻辑问题(可能是)。我已经花了几个小时(第一个错误)认为这是一个容易修复的问题,但显然这不是我花时间弄清楚它为什么不工作的😅原因。我一直在摆弄我的RayCastDetectionSpawnManagerObjectPoolingPlayerControl逻辑,这些逻辑按照我想要的方式进行交互,但是 nada

代码

ObjectPooling.cs

public static ObjectPooling sharedInstance;
public List<GameObject> pooledObjects;
public GameObject objectToPool;
private PlayerControl playerControllerScript;
public int amountToPool;

void Awake()
{
    sharedInstance = this;
}
void Start()
{
    playerControllerScript = GameObject.Find("Player").GetComponent<PlayerControl>();
    pooledObjects = new List<GameObject>();
    GameObject tmp;

    for (int i = 0; i < amountToPool; i++) //Add objects to the pool and turns them invisible (false)
    {
        tmp = Instantiate(objectToPool);
        tmp.SetActive(false);
        playerControllerScript.passedBeam = false;
        pooledObjects.Add(tmp);
    }
}
public GameObject GetPooledObject()
{
    for (int i = 0; i < amountToPool; i++)
    {
        if (!pooledObjects[i].activeInHierarchy)
            return pooledObjects[i];
    }
    return null;
}

RayCastDetection.cs(第一次)

public class RayCastDetection : MonoBehaviour
{
    public UIManager UIManagerScript;
    public PlayerControl playerControlScript;
    private RaycastHit hit;
    public bool passed;

    void Start()
    {
        UIManagerScript = GameObject.Find("UI_Manager").GetComponent<UIManager>(); //Used for scoring
        playerControlScript = GameObject.Find("Player").GetComponent<PlayerControl>(); //used for player passing through the pipe
        passed = false;
        playerControlScript.passedBeam = false;
    }

    void Update()
{
    Vector3 beamDown = transform.TransformDirection(Vector3.down);
    Ray ray = new Ray(transform.position, beamDown);

    if (!passed)
    {
        if (Physics.Raycast(ray, out hit))
        {
            if (hit.collider.tag == "Player" && !playerControlScript.passedBeam)
            {
                playerControlScript.passedBeam = !playerControlScript.passedBeam;
                UIManagerScript.score++;
            }
            Debug.DrawRay(transform.position, hit.point - transform.position);
        }
    }
    else
        playerControlScript.passedBeam = false;
}
}

SpawnManager.cs

public class SpawnManager : MonoBehaviour
{
    public GameObject[] obstaclesPrefab;
    private PlayerControl playerControllerScript;
    private float startDelay = 1.69f;
    private float repeatRate = 1.1f;

    void Start()
    {
        playerControllerScript = GameObject.Find("Player").GetComponent<PlayerControl>();
        InvokeRepeating("SpawnObstacle", startDelay, repeatRate);
    }

    void Update()
    {
        
    }
    void SpawnObstacle()
    {
        // int obstaclesIndex = Random.Range(0, obstaclesPrefab.Length); //This is used only if I don't want to deal with object pooling, but the whole point is to use it. This is just a reference if I want to go back
        
        if (playerControllerScript.gameOver == false)
        {
            float randomY = Random.Range(-2f, 2f);
            Vector3 randomHeight = new Vector3(35, randomY, -7);
            GameObject pipe = ObjectPooling.sharedInstance.GetPooledObject();
            if (pipe != null)
            {
                pipe.transform.position = randomHeight;
                pipe.SetActive(true);
                //My guess is that I want to instantiate the object pipe's beam to false here 
            }
        }
            // Instantiate(obstaclesPrefab[obstaclesIndex], randomHeight, obstaclesPrefab[obstaclesIndex].transform.rotation); //This is used only if I don't want to deal with object pooling, but the whole point is to use it. This is just a reference if I want to go back
    }
}

请随时留下一些建议,我已经错过了或任何问题,在有关填写。谢谢您的时间!

3df52oht

3df52oht1#

我想分享一些好消息。我的问题已经解决了!
在我开始着手解决方案之前,非常感谢rogers,并分享了他使用的方法。实际上,我很固执,在解决方案到来时,我想在某种程度上感到自己是 * 独特的 *。我不得不退后一步,看看大局

反射

如果你曾经挣扎,花了像8- 12小时像我一样的一些逻辑废话,你觉得它在舌尖,是时候后退一点,当你不去任何地方后1小时。
有几个建议要做(我没有这样做,但我希望我现在这样做)是有图纸在你如何描绘它的精神。没有画的第一次是我的第一个错误。我觉得挑战我自己的头脑和破坏自己的工作继续固执。

代码解决方案

现在,解决方案是我将我的UIManager脚本与我的SpawnManagerRayCastDetection添加到一起,以便使其工作。

UIManager.cs

public class UIManager : MonoBehaviour
{
    public Text scoreBoardDisplay;
    public Text scoreBoardDisplayShadowed;
    public AudioSource sound_score;
    public string scoreText;
    public int score;
    public int oldScore;
    public bool success;
    public bool incrementScore;
    
    void Start()
    {
        success = false; //NEW
        incrementScore = false; //NEW
    }

    void Update()
    {
        if (score != oldScore)
        {
            sound_score.Play();
            scoreText = score.ToString();
            scoreBoardDisplay.text = scoreText;
            scoreBoardDisplayShadowed.text = scoreText;
            oldScore = score;
        }
    }
}

SpawnManager.cs(四个月前)

public class SpawnManager : MonoBehaviour
{
    public GameObject[] obstaclesPrefab;
    private PlayerControl playerControllerScript;
    public UIManager UIManagerScript; //NEW
    private float startDelay = 1.69f;
    private float repeatRate = 1.1f;
    void Start()
    {
        playerControllerScript = GameObject.Find("Player").GetComponent<PlayerControl>();
        UIManagerScript = GameObject.Find("UI_Manager").GetComponent<UIManager>();
        InvokeRepeating("SpawnObstacle", startDelay, repeatRate);
    }

    void SpawnObstacle()
    {
        if (playerControllerScript.gameOver == false)
        {
            float randomY = Random.Range(-2f, 2f);
            Vector3 randomHeight = new Vector3(35, randomY, -7);
            GameObject pipe = ObjectPooling.sharedInstance.GetPooledObject();
            if (pipe != null)
            {
                pipe.transform.position = randomHeight;
                pipe.SetActive(true);
                UIManagerScript.incrementScore = false; //NEW, where my problem happens to be solved
                UIManagerScript.success = false; //NEW, where my problems happens to be solved
            }
        }
    }
}

RayCastDetection.cs

public class RayCastDetection : MonoBehaviour
{
    public UIManager UIManagerScript;
    public PlayerControl playerControlScript;
    private RaycastHit hit;
    public bool passed;
    void Start()
    {
        UIManagerScript = GameObject.Find("UI_Manager").GetComponent<UIManager>();
        playerControlScript = GameObject.Find("Tomato").GetComponent<PlayerControl>();
        passed = false;
    }

    void Update()
    {
        Vector3 beamDown = transform.TransformDirection(Vector3.down);
        Ray ray = new Ray(transform.position, beamDown);

        if (!passed)
        {
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.collider.tag == "Player" && !UIManagerScript.success) //Setting a condition to check if the beam hasn't been touched YET
                {
                    //Once touched, turn this true and increment
                    UIManagerScript.incrementScore = true;
                    UIManagerScript.score++;
                }
//If I already incremented my score, then there is no need to re-increment it again from the same ray. Thus, a flag for success is handled
                if (UIManagerScript.incrementScore)
                    UIManagerScript.success = true;
                Debug.DrawRay(transform.position, hit.point - transform.position);
            }
        }
    }
}

再次,非常感谢你引导我走上正确的轨道:)。如果我认为有什么要添加的,我会在我的 * 反射 * 标题下更新它。
如果你想玩或使用代码,请随意在我的Git中玩它

相关问题