Search code examples
c#unity-game-enginenullreferenceexceptionraycastingml-agent

How do you use a variable declared inside a function in another function? (C#) UnassignedReferenceException: The variable inRay has not ben assigned


Represents wat i want

So i'm playing around in Unity MLAgents, and wanted to add the position off objects that a Raycast hits to the agent's observations. This has really been an adventure for me as i don't know anything about Unity or C#, and i know this sounds easy and it probably is:

I'm getting error CS0103: The name 'inRay' does not exist in the current context.

And ok, i tried to declare in the global scope and the error is gone but then when running the code it gives me:

UnassignedReferenceException: The variable inRay has not ben assigned.

This is in one Script and i can't think of anything else i could do to solve the reference issue.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;


public class AgentBasicController : Agent
{
    private Rigidbody rigidA;
    private float yThrust = 0.125f;
    private float moveSpeed = 5f;
    private float timer = 60f;
    public Transform inRay;

    
    public override void Initialize()
    {
        rigidA = GetComponent<Rigidbody>();
    }

    public override void OnEpisodeBegin()
    {
        timer = 60f;

        if (timer <= 0f)
        {
            SetReward(-1F);
            timer = 60f;
        }
    }

    public override void CollectObservations(VectorSensor sens)
    {
        sens.AddObservation(transform.localPosition);
        sens.AddObservation(inRay.localPosition);
    }
    
    public override void OnActionReceived(ActionBuffers acts)
    {
        int moveX = acts.DiscreteActions[0];
        int moveZ = acts.DiscreteActions[1];
        
        if (Mathf.FloorToInt(acts.DiscreteActions[2]) == 1)
        {
            Jump();
        }

        if (Mathf.FloorToInt(acts.DiscreteActions[3]) == 1)
        {
            SensRay();
        }

        Vector3 addForce = new Vector3(0, 0, 0);

        switch (moveX)
        {
            case 0: addForce.x = 0f; break;
            case 1: addForce.x = -1f; break;
            case 2: addForce.x = +1f; break;
        }

        switch (moveZ)
        {
            case 0: addForce.z = 0f; break;
            case 1: addForce.z = -1f; break;
            case 2: addForce.z = +1f; break;
        }

        rigidA.velocity = addForce * moveSpeed + new Vector3(0, rigidA.velocity.y, 0);
    }

    public override void Heuristic(in ActionBuffers actsOut)
    {
        ActionSegment<int> discreteActs = actsOut.DiscreteActions;

        switch (Mathf.RoundToInt(Input.GetAxisRaw("Horizontal")))
        {
            case -1: discreteActs[0] = 1; break;
            case 0: discreteActs[0] = 0; break;
            case +1: discreteActs[0] = 2; break;
        }

        switch (Mathf.RoundToInt(Input.GetAxisRaw("Vertical")))
        {
            case -1: discreteActs[1] = 1; break;
            case 0: discreteActs[1] = 0; break;
            case +1: discreteActs[1] = 2; break;
        }

        discreteActs[2] = 0;

        if (Input.GetKey(KeyCode.Space))
        {
            discreteActs[2] = 1;
        }

        discreteActs[3] = 0;

        if(Input.GetKey(KeyCode.R))
        {
            discreteActs[3] = 1;
        }
    }

    private void Jump()
    {
        if (transform.localPosition.y <= 1f)
        {
            rigidA.AddForce(new Vector3(0, yThrust , 0), ForceMode.Impulse);
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Goal"))
        {
            SetReward(+1f);
            EndEpisode();
        }
    
        if (other.CompareTag("Rift"))
        {
            SetReward(-1f);
            EndEpisode();
        }
    }

    public void SensRay()
    {
        RaycastHit rayHit;
        if (Physics.Raycast(transform.localPosition, (transform.TransformDirection(Vector3.forward)), out rayHit) || 
        Physics.Raycast(transform.localPosition, (transform.TransformDirection(Vector3.right)), out rayHit) ||
        Physics.Raycast(transform.localPosition, (transform.TransformDirection(Vector3.left)), out rayHit) ||
        Physics.Raycast(transform.localPosition, (transform.TransformDirection(Vector3.back)), out rayHit))
        {
            var inRay = rayHit.transform;

            if (inRay.CompareTag("Goal"))
            {
                Vector3 target = rayHit.transform.localPosition;
                Vector3 current = transform.localPosition;

                transform.localPosition = Vector3.MoveTowards(current, target, moveSpeed);
            }
        }
        Debug.DrawRay(transform.position, (transform.TransformDirection(Vector3.forward)), Color.yellow);
        Debug.DrawRay(transform.position, (transform.TransformDirection(Vector3.right)), Color.yellow);
        Debug.DrawRay(transform.position, (transform.TransformDirection(Vector3.left)), Color.yellow);
        Debug.DrawRay(transform.position, (transform.TransformDirection(Vector3.back)), Color.yellow);
    }

    private void Update()
    {
        if (timer <= 0f)
        {
            SetReward(-1F);
            timer = 60f;
        }
    }
    
}

Solution

  • var inRay = rayHit.transform;

    You're creating a new local variable instead of assigning your member variable here. Remove the var.

    You should still check that your member variable is assigned before using it, maybe if (inRayr != null) could help.