- Home /
Converting a JS script into C# - hit a wall with arrays...
Hey folks. Unity newbie, trying to learn C# before I get too comfortable with JS.
I've got some code which moves a camera to the position of a gameobject if the player gets within a certain radius of the gameobject.
There are two scripts - CameraControllerRevCsharp.cs and NodeControllerRevCsharp.cs.
CameraControllerRevCsharp is attached to the Main Camera.
NodeControllerRevCsharp is attached to gameobjects (4 in this example) named CameraNode.
On Awake, a NodeControllerRevCsharp script takes the position and activation range from the CameraNode it's attached to and pushes it into an array on the CameraControllerRevCsharp attached to the Main Camera.
The CameraControllerRevCsharp regularly iterates through the array containing the Camera Nodes, identifies which one is closest to the player character and moves the Main Camera to the identified node.
(There's a delay in the code to stop the while loop from eating up the processor, but it's currently commented out until I can get the code to compile)
That's how it should work. BUT IT AIN'T! I've eliminated as many bugs as I can (learning about different C# arrays and the need to make bools explicit in functions, etc), but the durn thing just won't compile. I have the following errors:
Assets/Scripts/CameraControllerRevCsharp.cs(53,182): error CS0030: Cannot convert type
System.Collections.ArrayList' to >
CameraControllerRevCsharp.CameraNode'Assets/Scripts/CameraControllerRevCsharp.cs(53,117): error CS1502: The best overloaded method match for
UnityEngine.Vector3.Distance(UnityEngine.Vector3, > UnityEngine.Vector3)' has some invalid > arguments > > Assets/Scripts/CameraControllerRevCsharp.cs(53,117): > error CS1503: Argument
#2' cannot convertobject' expression to type >
UnityEngine.Vector3'Assets/Scripts/CameraControllerRevCsharp.cs(59,65): error CS0246: The type or namespace name `cameraNode' could not be found. Are you missing a using directive or an assembly reference?
Code for NodeControllerRevCsharp follows, with the original Javascript (which I had working just fine) commented out at the end of each script:
================================================================================
using UnityEngine; using System.Collections;
public class NodeControllerRevCsharp : MonoBehaviour {
public float range;
void OnDrawGizmosSelected() {
Gizmos.color = Color.red;
Gizmos.DrawWireSphere (transform.position, range);
}
void Start () {
CameraNode myNode = new CameraNode(transform.position, range);
gameObject.Find("Main Camera").GetComponent(CameraControllerRevCsharp).cameraNodes.push(myNode);
}
}
/* //#pragma strict
var range : float;
function OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere (transform.position, range); }
function Start () { var myNode : CameraNode = new CameraNode(transform.position, range); gameObject.Find("Main Camera").GetComponent(CameraController).cameraNodes.push(myNode); } */
================================================================================
Code for CameraControllerRevCsharp follows (again, working javascript follows after c#, commented out):
================================================================================
using UnityEngine;
using System.Collections;
public class CameraControllerRevCsharp : MonoBehaviour {
//Went with ArrayList because it lets me find the .Count - NOTE THE CAPITAL 'C'!
ArrayList cameraNodes = new ArrayList();
//List<CameraNode> cameraNodes = new List<CameraNode>();
//Declare Inspector slot for controllable character
public Transform target;
//Boolean switch to turn the tracking on and off
public bool loophandle = true;
// Local access for CameraNode objects, passing range
// (set in the CameraNode script) and position
// (read from CameraNode object)
public class CameraNode{
public Vector3 position;
public float range;
//I think the 'this' keyword is being used to qualify
// members hidden by similar names, ie. the 'position'
// variable in THIS scope
public CameraNode(Vector3 position, float range){
this.position = position;
this.range = range;
}
}
// Have switched to the convention of putting curly braces at the end of
// lines so I'm not tempted to check braces by their indentation
void Start () {
// This is declaring the Transform variable 'target' again?
// Finds the transform of the GameObject named 'Player' -
// potentially something for a public var?
Transform target = GameObject.Find("Player").transform;
// While the public boolean variable 'loophandle' is set to true...
while (loophandle){
// Made this '> 0' as c# seems to freakout if you offhandedly use any variable as a boolean
// ALSO: ArrayList wants you to use 'Count' instead of 'Length'. Note the capital 'C'!
if(cameraNodes.Count > 0){
int node = 0;
for (int i = 0; i < cameraNodes.Count; i++){
//Get the range from the CameraNode object (set in the inspector), see if it's greater
//than the distance between the character controller and the CameraNode
if( ((CameraControllerRevCsharp.CameraNode)cameraNodes[i]).range >= Vector3.Distance(target.position, ((CameraControllerRevCsharp.CameraNode)cameraNodes)[i].position)){
// Assign the index number - which corresponds to the camera number - to node.
node = i;
}
}
// Move the camera to the position of the CameraNode which is indicated by node/i
transform.position = ( (cameraNode)cameraNodes[node]).position;
}
// 'WaitASecond' - This makes the code wait a set time before executing again
// - which saves unity from crashing Would something connected to
// time.Deltatime make more sense? So it only executes once perframe? (see the
// IEnumerator function 'WaitASec' below)
// COMMENTING OUT LINE BELOW BECAUSE I HAVE ENOUGH PROBLEMS TO WORRY ABOUT RIGHT NOW
// StartCoroutine(WaitASec(1.0));
}
}
// Update is called once per frame
void Update () {
// Makes the camera turn to face the object set up in the target variable.
transform.LookAt(target);
}
//IEnumerator<float> WaitASec(float waitTime){
// yield return new WaitForSeconds(waitTime);
// Debug.Log ("Waited a sec");
//}
}
// **ORIGINAL JAVASCRIPT**
//#pragma strict
/*
var cameraNodes : Array = new Array();
var target : Transform;
var loopHandle : boolean = true;
class CameraNode {
var position : Vector3;
var range : float;
function CameraNode (position : Vector3, range : float)
{
this.position = position;
this.range = range;
}
}
function Start () {
target = gameObject.Find("Player").transform;
while(loopHandle)
{
if(cameraNodes.length)
{
var node : int;
for(var i = 0; i < cameraNodes.length; i++)
{
if(cameraNodes[i].range >= Vector3.Distance(target.position, cameraNodes[i].position))
{
node = i;
}
}
transform.position = cameraNodes[node].position;
}
yield WaitForSeconds(1.0);
}
}
function Update ()
{
transform.LookAt(target);
}
*/
================================================================================
Really having a tough time with this script. As mentioned, I had this working in Javascript and it's driving me crazy that I can't get it to work in C#. If anybody can provide a solution & explanation (GRR C# ARRAYS NNNNNNGH) I'd very much appreciate it. I've read this page - http://robotduck.wordpress.com/2009/11/04/88/ - many times, but I'm still unsure whether I chose the right array for this issue. I'm determined to learn C#, but arrays are a major speedbump.
Thanks for taking the time to look at the script!
1- No such thing as 'too familiar with JS' I've used it until C# came naturally. Use whichever language you prefer, don't rush over to C#.
2- Clean up the formatting of your code, it hurt my eyes to try and decipher your scripts/classes/methods. I'll take a look again when I get home in a hour (unless its solved already).
Thanks for the response. I'm sorta new at this - clean up the formatting how, exactly? $$anonymous$$ore spacing, more (fewer?) comments? Would be delighted to oblige (always in favour of best practices), but, uh, somewhat at sea. =)
I have just cleared Errors and formatted the code. The Array is now List ins$$anonymous$$d of an ArrayList. I never used ArrayList however Lists work just fine, dont forget adding "using System.Collections.Generic;" on top of your script.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class CameraControllerRevCsharp : $$anonymous$$onoBehaviour
{
private List<CameraNode> cameraNodes = new List<CameraNode>();
public class CameraNode{
public Vector3 position;
public float range;
public CameraNode(Vector3 position, float range){
this.position = position;
this.range = range;
}
}
public bool loophandle = true;
public void Start () {
Transform target = GameObject.Find("Player").transform;
while (loophandle)
{
if(cameraNodes.Count > 0)
{
int node = 0;
for (int i = 0; i < cameraNodes.Count; i++)
{
if(cameraNodes[i].range >= Vector3.Distance(target.position, cameraNodes[i].position))
{
node = i;
}
}
transform.position = ( (CameraNode)cameraNodes[node]).position;
}
}
}
}
$$anonymous$$y concern was that the question is over 200 lines long, that's WAY too long. There's a lot of irrelevant code and comments, which takes focus off the real problem. It becomes difficult to deduce what the problematic code region is, hence many people will navigate to another question.
That being said, at first glance Branx's solution looks like it could work and/or you might want to take a look at this page from UnifyCommunity, it helped me a lot in the past: http://www.unifycommunity.com/wiki/index.php?title=Which_$$anonymous$$ind_Of_Array_Or_Collection_Should_I_Use%3F
Answer by mweldon · Apr 03, 2012 at 08:29 PM
Syntax error on line 53.
This: ((CameraControllerRevCsharp.CameraNode)cameraNodes)[i].position Should be this: ((CameraControllerRevCsharp.CameraNode)cameraNodes[i]).position
Another one on line 59.
This: ( (cameraNode)cameraNodes[node]).position Should be this: ( (CameraControllerRevCsharp.CameraNode)cameraNodes[node]).position
Also, if you had stuck with List instead of ArrayList, you wouldn't have to do all those ugly and mistake-prone casts in the first place.
I believe I'd tried using a List before, but couldn't seem to get the thing to return a .length or .count - probably because I was EITHER using System.Collections; or using System.Collections.Generic; but not both as in Branx' example above. List seems the way to go - still stumbling around in the dark, though. =)
Stupid bloody syntax errors. Thank you. Will try to remember those in future. Obliged!
(Though I have a follow-up question, to do with using a coroutine to make a While loop pause temporarily (using WaitForSeconds) - should I create a separate page for this?)
yes, every thread should consist of one(1) question and very hopefully a marked answer. and you may take a look around, there's been lot of questions about coroutines :)
"yes, every thread should consist of one(1) question"
10-4.
"and very hopefully a marked answer"
10-4. =) No way to mark two answers?
I've absolutely poked around for answers on coroutines, but either have found nothing that satisfies my particular issue or haven't found something that I can understand. =) I'll get right on that...
http://answers.unity3d.com/questions/235104/c-using-an-ienumerator-yield-waitforseconds-to-tem.html