[Help Needed] Change Script from JS to CS?

Hello Guys,

I am finding myself needing to modify a script that I found in an old tutorial the original script was in JS and apart from one small error (line 65) in the script that I can’t seem to fix it’s working and also the fact that JS is going to be retired soon so I need a newer version. This has been my go to script whenever I need to move a NPC.

Anyway, I have been trying to modify the script to CS and I keep running into errors and going batty reading the Unity docs and basically going nowhere. The script is quite long.

So, if anyone can help me modify it to get it working I would be most grateful. I realize that doing the whole script would be a burden on anyone, so, perhaps it would be better if I ask for specific help on the actual lines of code that I don’t understand.

This script is as follows:

#pragma strict


var player:             Transform;
var distanceToRobot:    float;
var anime:                 Animator;
var theBool:             boolean;
var agent:                UnityEngine.AI.NavMeshAgent;
// where we want our robot to move to
var wayPoints:            Transform[];
var wayPointIndex:        int = 0;

var currentSpeed:                 float;
var angularSpeed:                 float;

var angleResponseTime:            float = 0.6f;
var angularSpeedDampingTime:    float = 0.7f;
var angle:                        float;



public var pathEndThreshold:    float = 0.1f;
private var hasPath:            boolean = false;



function atEndOfPath(){
    //print("atEndOfPath");
    if (Vector3.Distance(transform.position, agent.destination) <= 1f){
        return true;
        }

    return false;//*/
    /*hasPath |= agent.hasPath;
    if (hasPath agent.remainingDistance <= agent.stoppingDistance + pathEndThreshold ){
        // Arrived
        hasPath = false;
        return true;
           }
    return false;//*/
    }



function Start () {
    anime = GetComponent(Animator);
    agent = GetComponent(UnityEngine.AI.NavMeshAgent);
    anime.SetLayerWeight(1, 1f);
    //this causes a problem I can't fix
    //anime.SetLayerWeight(2, 1f);
    theBool = false;
    }



function Update () {
    distanceToRobot = Vector3.Distance(player.position, transform.position);
    //print("Distance to Robot: "+distanceToRobot);

    //seems to be 2 ways of doing the destination thingy
    //and both seem to work
    //this is the first method I saw
    //navMesh.SetDestination(wayPoints[wayPointIndex].position);
    //this is the 2nd
    agent.destination = wayPoints[wayPointIndex].position;


    currentSpeed = Vector3.Project(agent.desiredVelocity,transform.forward).magnitude;
    //print("currentSpeed: "+currentSpeed);
    //currentSpeed = .5f;

    //if PlayerInSight
    var getVal: boolean;
    getVal = anime.GetBool("PlayerInSight");
    //print("getVal: " + getVal);
    if(getVal==true){
        agent.Stop();
        angle = FindAngle(transform.forward, player.position - transform.position, transform.up);
        //currentSpeed = 0f;
        var rotation = Quaternion.LookRotation(player.position - transform.position );
        transform.rotation = Quaternion.Slerp(transform.rotation,rotation, Time.deltaTime  * 4);
        angularSpeed = angle / angleResponseTime;
        //print("currentSpeed: "+currentSpeed);
        }
    else{
        agent.Resume();
        angle = FindAngle(transform.forward, agent.desiredVelocity, transform.up);   
        angularSpeed = angle / angleResponseTime;
        currentSpeed = Vector3.Project(agent.desiredVelocity,transform.forward).magnitude;
        }
   
    //it's a function - remember the "()" to call it not a variable
    //makes you wonder why it it called it in the first place
    if (atEndOfPath() == true){
        print("At end of Path! Give me somewhere to go you stupid carbon based life form!!!");
        if(wayPointIndex == wayPoints.Length-1){
            wayPointIndex = 0;
            }
        else{
            wayPointIndex += 1;
            }//end if
        }//end if
    print("wayPointIndex:"+wayPointIndex);


    //how to make robot walk to waypoint
    //instead of slide
    anime.SetFloat("Speed", currentSpeed);
    //anime.SetFloat("AngularSpeed",0f);
    anime.SetFloat("AngularSpeed", angularSpeed, angularSpeedDampingTime, Time.deltaTime);


    //print("Distance to Robot: "+distanceToRobot);

    if(distanceToRobot>15){
        theBool = false;
        anime.SetBool("PlayerInSight", theBool);
        }

    //print("Distance to Robot: "+distanceToRobot);

    if(distanceToRobot<15){
        theBool = true;
        anime.SetBool("PlayerInSight", theBool);
        }

    }//end update


//A function that finds the correct angle we should be facing
//this is beyond my ability to comprehend
function FindAngle(fromVector : Vector3, toVector:Vector3, upVector:Vector3){
    //do something
    //print("FindAngle......................");
    //return 3;
    if(toVector == Vector3.zero){
        return 0f;
        }
    var myAngle: float;
    var normal: Vector3;

    myAngle = Vector3.Angle(fromVector, toVector);
    normal = Vector3.Cross( fromVector, toVector);

    myAngle *= Mathf.Sign(Vector3.Dot(normal, upVector));
    myAngle *= Mathf.Deg2Rad;
    return myAngle;
    }//end findangle()

Like I said, it is long and I only have the atEndofPath and Start functions done after that the code gets a bit funky :hushed:.

If you are willing to help, here is a huge thankyou in advance**!.**

Regards.

So, to be clear, you want someone to port this to C# for you?

I bet if you did a few hackerrank.com C# tutorials, you’d know what you need to in order to port code, yourself.

Not exactly! I can do the majority of the port but their are some things that I can’t do because there are some things in that code that are well above my paygrade! For example, look at the function FindAngle at line 132 and arguments it accepts I have no clue how to port that to C#.

Also, I have no clue how to get all those NavMeshAgent lines working. Like resume, stop, destination and whatever is wrong with line 65, all the rest should be “relatively” easy. Famous last words :slight_smile:

Regards.

Honestly I don’t know which vars should be public or not. Never used javascript inside unity.
So you can check that for yourself. But maybe this will get you a good starting point so you can figure out the rest for yourself.

I also changed the agent.Stop and Resume to isStopped since it’s deprecated.
Code compiles but I haven’t tested it. If you need a variable to display in the editor just
add public in front of it.

using UnityEngine;
using UnityEngine.AI;

public class Class1 : MonoBehaviour {

    Transform player;
    float distanceToRobot;
    Animator anime;
    bool theBool;
    NavMeshAgent agent;

    // where we want our robot to move to
    Transform[] wayPoints;
    int wayPointIndex = 0;

    float currentSpeed;
    float angularSpeed;

    float angleResponseTime = 0.6f;
    float angularSpeedDampingTime = 0.7f;
    float angle;

    public float pathEndThreshold = 0.1f;
    private bool hasPath = false;



    public bool AtEndOfPath() {
        //print("atEndOfPath");
        if (Vector3.Distance(transform.position, agent.destination) <= 1f) {
            return true;
        }

        return false;//*/
                     /*hasPath |= agent.hasPath;
                     if (hasPath agent.remainingDistance <= agent.stoppingDistance + pathEndThreshold ){
                         // Arrived
                         hasPath = false;
                         return true;
                            }
                     return false;//*/
    }



    private void Start() {
        anime = GetComponent<Animator>();
        agent = GetComponent<NavMeshAgent>();
        anime.SetLayerWeight(1, 1f);
        //this causes a problem I can't fix
        //anime.SetLayerWeight(2, 1f);
        theBool = false;
    }



    private void Update() {
        distanceToRobot = Vector3.Distance(player.position, transform.position);
        //print("Distance to Robot: "+distanceToRobot);

        //seems to be 2 ways of doing the destination thingy
        //and both seem to work
        //this is the first method I saw
        //navMesh.SetDestination(wayPoints[wayPointIndex].position);
        //this is the 2nd
        agent.destination = wayPoints[wayPointIndex].position;


        currentSpeed = Vector3.Project(agent.desiredVelocity, transform.forward).magnitude;
        //print("currentSpeed: "+currentSpeed);
        //currentSpeed = .5f;

        //if PlayerInSight
        bool getVal = anime.GetBool("PlayerInSight");
        //print("getVal: " + getVal);
        if (getVal == true) {
            agent.isStopped = true;
            angle = FindAngle(transform.forward, player.position - transform.position, transform.up);
            //currentSpeed = 0f;
            var rotation = Quaternion.LookRotation(player.position - transform.position);
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * 4);
            angularSpeed = angle / angleResponseTime;
            //print("currentSpeed: "+currentSpeed);
        } else {
            agent.isStopped = false;
            angle = FindAngle(transform.forward, agent.desiredVelocity, transform.up);
            angularSpeed = angle / angleResponseTime;
            currentSpeed = Vector3.Project(agent.desiredVelocity, transform.forward).magnitude;
        }

        //it's a function - remember the "()" to call it not a variable
        //makes you wonder why it it called it in the first place
        if (AtEndOfPath() == true) {
            print("At end of Path! Give me somewhere to go you stupid carbon based life form!!!");
            if (wayPointIndex == wayPoints.Length - 1) {
                wayPointIndex = 0;
            } else {
                wayPointIndex += 1;
            }//end if
        }//end if
        print("wayPointIndex:" + wayPointIndex);


        //how to make robot walk to waypoint
        //instead of slide
        anime.SetFloat("Speed", currentSpeed);
        //anime.SetFloat("AngularSpeed",0f);
        anime.SetFloat("AngularSpeed", angularSpeed, angularSpeedDampingTime, Time.deltaTime);


        //print("Distance to Robot: "+distanceToRobot);

        if (distanceToRobot > 15) {
            theBool = false;
            anime.SetBool("PlayerInSight", theBool);
        }

        //print("Distance to Robot: "+distanceToRobot);

        if (distanceToRobot < 15) {
            theBool = true;
            anime.SetBool("PlayerInSight", theBool);
        }

    }//end update


    //A function that finds the correct angle we should be facing
    //this is beyond my ability to comprehend
    public float FindAngle(Vector3 fromVector, Vector3 toVector, Vector3 upVector) {
        //do something
        //print("FindAngle......................");
        //return 3;
        if (toVector == Vector3.zero) {
            return 0f;
        }
        float myAngle;
        Vector3 normal;

        myAngle = Vector3.Angle(fromVector, toVector);
        normal = Vector3.Cross(fromVector, toVector);

        myAngle *= Mathf.Sign(Vector3.Dot(normal, upVector));
        myAngle *= Mathf.Deg2Rad;
        return myAngle;
    }//end findangle()
}
1 Like

Mate, did you do the whole code!

That is just totally fantastic, I can’t thank you enough, that is just a total lifesaver!!!

You have no idea how much this means to me, and I can’t put it into words. At the dojo I would bow and say “domo arigatou gozaimasu”.

Warmest Regards.

Most things just stay the same.
All logic stuff like the calculations are the same syntax in C# and Javascript.
Only variable and function declerations are different.

It probably took 5 minutes. Anyway I hope everything works as expected.

1 Like

Just had the time to use your modified code and ran into a curious error below:

As far as I can tell your code is correct by checking it out with the Unity docs and the assembly reference is also correct:

  • using UnityEngine.AI;

So once again Unity has me stumped, might have to create a new post to figure this one out. Thanks again for all your hard work! It is very much appreciated :sunglasses:.

Warmest Regards.

You’re likely using an older version of Unity than he did when doing the conversion- simply change it back to agent.Stop(); for the first instance, and agent.Resume(); for the second (or comment the existing lines out- you’ll need to switch it back if you upgrade Unity).

1 Like

Good call! I never would have thought of that. I was using Unity 5.5.1, so, I upgraded it just a few moments ago to Unity 5.6.1, and sure enough i worked first go. So, thankyou Lysander for pointing this out!

And once again many thanks to Jildert for taking the time to modify that code - I’m still blown away by that. Now I have NPC code that works without any errors at all, and no JavaScript - always a good thing :sunglasses:.