0
\$\begingroup\$

I looked around for a fix because I am sure it's either super simple of a fix or something that is commonly run across but nonetheless it's about time I asked straight up.

This is my code in the script. It's growing plants based on time but I'm mostly just Trying out Time based events and ran into a bit of a problem. When I click on one plant, the other 2 get harvested. Here is the code I ended up with:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class betterPlantGrowthController : MonoBehaviour
{
    // This is a small location where to keep all pre-read and mostly prm Varables such as Time or Public Varables.
    // ======================Varables=============================

    public SpriteRenderer spriteRenderer;
    public Sprite[] spriteArray;
    public float time_ = 0;
    public double growthTime = 0;

    private int currentArrayNumber = 0;
    private bool currentlyGrowing = true;

    // ===========================================================

    void Update() // This updates every frame of the game/programe and will be where most your code ends up
    {
        if (currentlyGrowing == true)
        {
            time_ += Time.deltaTime; // Updates ever Sec

            if (time_ >= growthTime)
            {
                time_ = 0;
                currentArrayNumber += 1;
            }

            spriteRenderer.sprite = spriteArray[currentArrayNumber]; // Renders The Current Sprite/Plant-stage

            if (currentArrayNumber == 4) { currentlyGrowing = false; }
        }

        if (currentlyGrowing == false)
        {
            if (Input.GetMouseButtonDown(0))
            {
                Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                Vector2 mousePos2D = new Vector2(mousePos.x, mousePos.y);

                RaycastHit2D hit = Physics2D.Raycast(mousePos2D, Vector2.zero);

                if (hit.collider != null)
                {
                    currentArrayNumber = 0;
                    spriteRenderer.sprite = spriteArray[currentArrayNumber]; // Reseting the Render
                    currentlyGrowing = true;
                }
            }
        }
    }
}

It's a super simple wait till it grows and then clicks on it. Again, when they all reach stage 4 (the last stage) then click on it, they all revert to stage 0 (first stage) even tho there are multiple objects running in the game. Any ideas? Or suggestions on how to make it so that only the one clicked is updated/changed?

\$\endgroup\$
0
2
\$\begingroup\$

Philipp points out the way how to do it with the IPointerClickHandler, this approach uses the OnMouseDown suggested from DMGregory and some small improvements - mainly readablility, dont be afraid to name your variables longer, once you come back in the future you wont have a hard time trying to figure out what you meant.

using UnityEngine;

public class PlantController: MonoBehaviour {
    
    public SpriteRenderer spriteRenderer;
    public Sprite[] plantGrowStateSprites;
    
    [SerializeField]
    private double growthTimePerStage = 0;

    private float _timeInCurrentGrowState = 0;
    private GrowState _currentGrowState = GrowState.Seed;
    private bool _currentlyGrowing = true;

    enum GrowState {Seed = 0, Growing = 1, Blossom = 2, Unripe = 3, Mature = 4};
  
    void Update() {
        Growing();
    }

    private void Growing() {
        if (!_currentlyGrowing) return;
        _timeInCurrentGrowState += Time.deltaTime;
        if (_timeInCurrentGrowState >= growthTimePerStage) {
            _timeInCurrentGrowState = 0;
            _currentGrowState += 1;
        }
        spriteRenderer.sprite = plantGrowStateSprites[(int) _currentGrowState]; 
        if (_currentGrowState == GrowState.Mature) { _currentlyGrowing = false; }
    }

    private void Harvest() {
        if (_currentGrowState == GrowState.Mature) {
            _currentGrowState = GrowState.Seed;
            spriteRenderer.sprite = plantGrowStateSprites[(int) _currentGrowState]; 
            _currentlyGrowing = true;
        }
    }

    public void OnMouseDown() {
        Harvest();
    }
}
\$\endgroup\$
1
\$\begingroup\$

The problem is that when you do a raycast using the mouse position, you are just checking if that raycast hit anything, not if it hit the collider of this particular plant. The collider does not even need to be the collider of a different plant. Any collider you have in your scene will satisfy the condition if (hit.collider != null).

You need to make sure that the collider you are checking against is the one of this particular plant.

How do you get that collider?

When this script is on the same object it controls, then you can do so with GetComponent<Collider>(). But it seems like you've built a controller script which is designed to receives the object it controls in a public property, so the script is not necessarily on the object it controls. So you might have to make the controller of the plant another public field.


But while this should work, you should also be aware that your solution is rather inefficient. It probably works fine with just 3 plants in the scene. But when you have 1000 plants in your scene, then you have 1000 controllers which will all perform the exact same raycast and receive the exact same result which they will then compare against their particular collider. This could cause a notable stutter each time the player clicks. A better solution could be to have a script which only exists once in the scene which is responsible for handling all mouse clicks and notifies the object that was clicked. There is actually a build-in solution for this: The PhysicsRaycaster/PhysicsRaycaster2D component on the camera, an EventSystem component somewhere in the scene (gets created automatically as soon as you add an UI canvas, by the way) and MonoBehaviours implementing the IPointerClickHandler interface.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .