0
\$\begingroup\$

I've been trying to script some basic AI for a Unity Roll-A-Ball game, which involves two balls collecting cubes for points (one controlled by the player and the other controlled by AI. Everything went as intended, except for the portion of the code that involved the bool Cube.activeSelf. Even after the AI controlled ball deactivated a cube, it still seemed to attempt to stay around the deactivated cube's position, as if the cube still existed in the scene. Can someone explain why activeSelf returns true for even the cubes that have been deactivated, and/or how I can program the ball to go after other cubes?

void Update()
{

    foreach (GameObject Cube in Cubes)//iterates through each cube in list of Cubes
    {
        if (Cube.activeSelf == true) //activeSelf seems to be true no matter what (shouldn't the code stop following the for statement and iterate through the rest of the Cubes)
        {
            SelfPos = transform.position; //position of Computer controlled ball
            Vector3 cubePos = Cube.transform.position; //position of the current cube the foreach statement is focusing on
            offset = cubePos - SelfPos; //the difference between the ball and the current cube's positions
            xoffset = offset.x; //the difference on the x-axis
            zoffset = offset.z; //the difference on the y axis
            CombinedOffset = Mathf.Sqrt((xoffset * xoffset) + (zoffset * zoffset)); //Pythagorean theorem to calculate distance cube is away from ball
            if (CombinedOffset < LowestValue)//if the Cube is closer than any other cubes that have been iterated through
            {
                LowestValue = CombinedOffset;//new record lowest value
                NearestCube = Cube; //the associated cube to that distance is the new nearest cube
                if (Cube.activeSelf == false)
                {
                    Debug.Log("Whats wrong!");
                }

            }
        }
    }
}


private void FixedUpdate()
{
    Direct = Direction.CompareDirectionOf(self, NearestCube); //CompareDirectionOf() tells function DirectionID_Reader() the direction the ball has to go to get to the nearest cube using variable Direct
    WayToMove = Direction.DirectionID_Reader(Direct); //DirectionID_Reader() calculates the required Vector value to get to the nearest cube, then tells Unity's rigidbody.AddForce() to move the ball at the calculated Vector using WayToMove
    rigidbody.AddForce(WayToMove * speed); //Moves the ball
}

Edit: someone suggested that I used the method SetActive to deactivate the cube, but that was used in a different file.

void OnTriggerEnter(Collider o)
{
    collider = o;
    if (collider.gameObject.CompareTag("Cube"))
    {
        collider.gameObject.SetActive(false);
        Audio.Play();
    }


}

The purpose of activeSelf was to check if the cube was active, and only go after it if it was. The problem was, the ball still went after the cube despite activeSelf being set to false by SetActive().

Update: I found what I did wrong. I pre-defined the variable "LowestValue" in the Start() void instead of the Update() void. Therefore, when the closest cube deactivated, the AI never found the next closest cube.

\$\endgroup\$
  • \$\begingroup\$ Can you show us where you populate your Cubes array, and where you SetActive(false) once a cube has been collected? \$\endgroup\$ – DMGregory Nov 5 '18 at 13:02
  • \$\begingroup\$ @DMGregory The cube array is stored using Cubes = GameObject.FindGameObjectsWithTag("Cube"); \$\endgroup\$ – Golden_Eagle Nov 5 '18 at 15:26
  • \$\begingroup\$ Where do you declare the variable collider used in your OnTriggerEnter function? Why do you choose to rename o like that? There's a built-in, deprecated getter built-into MonoBehaviours called collider, so you might be getting snared on that. \$\endgroup\$ – DMGregory Nov 6 '18 at 12:26
0
\$\begingroup\$

The variable activeSelf is read-only. No matter how you try to change it, it's impossible. Yes, neither Unity nor C# does anything when you assign a value to it, which in my opinion is wrong, but that's how it is.

From the documentation:

public bool activeSelf;

Description

The local active state of thisGameObject. (Read Only)

Use the SetActive method instead. Example:

Cube.SetActive(true);

Then use the activeSelf inside if statements to check its value.


If the problem is that your cubes are deactivated, but the AI just keeps chasing them, that is because when you deactivate an Object it does not disappear from the game, it's still there, you can still access it, it just doesn't draw itself and doesn't update any of its scripts. This means that if you pass it as a parameter to your AI and tell it "go chase that", the AI will happily do that.

My suggested alternatives are:

  • Destroy the object, using Destroy(gameObject)
  • Remove the deactivated Cube from the Cubes array that from what I understand is what the AI takes to start chasing cubes. Assuming that's a List.
  • If Cubes is an array, you can simply change the value of the specific Cube that was touched to null, to handle it inside your loop

Example:

for (GameObject Cube in Cubes) {
    if (Cube == null) { continue; /* The cube has been deactivated, ignore */ }

Depending on your situation, pick the one that suits you best.

\$\endgroup\$
  • \$\begingroup\$ Good point, but that was only a portion of one of many scripts. I did use SetActive to disable the object in a different file \$\endgroup\$ – Golden_Eagle Nov 5 '18 at 15:17
  • \$\begingroup\$ @Golden_Eagle I edited my answer with more information to cover that \$\endgroup\$ – TomTsagk Nov 5 '18 at 15:37

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.