Im having trouble compiling an AI script, and can't find the issue. Double check my work?

Im working on a very simple AI script for class and Im having trouble actually compiling it. Ive read through everything and tried researching online already. Ive been able to narrow it down to the CanSeeTarget function with the targetTag and string targetTag, The error Im receiving is a “‘(’ was unexpected, looking for…” kind of thing, but I don’t have enough experience to really figure this out. Ive included everything relevant to the script below, so I apologize for the lengthy-ness. Any help, if possible, would be greatly appreciated.

//The speed to use when in "Ramming" mode
[SerializeField] float RamSpeed = 5.0f; 

//The different ID's for the AI states
enum AIMode { Normal, Ramming, SteerTowards }; 

//The variable which holds the current AI state
private AIMode CurrentAIState; 

void Start () {

	//Always start in the normal state
	CurrentAIState = AIMode.Normal;

}

//Update the enmy when in a "normal" state
void UpdateNormal () { 
	//Move the object in the direction it is facing
	//over a period of time at a regular speed
	transform.position += transform.up * Time.deltaTime * MoveSpeed; 
	} 

//Applies the AI ramming movement
void UpdateRamming () {
	// Move the object in the direction it is facing
	// over a period of time at the ramming speed
	transform.position += transform.up * Time.deltaTime * RamSpeed; 
	}

//Handles the movement and rotation towards the player
void UpdateSteerTowards () {
	// Subtract the enemies current position from the player's
	Vector3 directionToPlayer = PlayerShipCtrl.transform.position - transform.position; 

	//Rotate the enemies movement direction towards the 
	//direction to the player.
	transform.up = Vector3.RotateTowards (transform.up, directionToPlayer,
	                                     Time.deltaTime * MoveSpeed, 0.0f); 

	//Apply the normal movement update
	UpdateNormal (); 
} 

void CanSeeTarget () {
	// Contains data about the collision
	RaycastHit hitInfo; 

	// Performs a raycast
	bool hitAny = Physics.Raycast (transform.position, transform.up, out hitInfo); 

	// Only respond to the hit info if anything was actually hit
	if (hitAny) 
	{
		if (hitInfo.collider.gameObject.tag == targetTag)
		{
			return true; 
		} 
	}

	bool CanSeeTarget (string targetTag)
	{
		return false; 
	} 
}

void DetermineAIState () {

//Subtract the enemies current position from the player’s

//current location to create a directional vector.

//This vector points from the enemy to the player.

Vector3 directionToPlayer = PlayerShipCtrl.transform.position - transform.position;

	//Store the normalized version of the direction to remove
	// its length. It now only represents a direction (no distance).
	Vector3 DirToPlayerNorm = directionToPlayer.normalized; 

	//Dot-products of two vectors represent a cosine between them.
	float product = Vector3.Dot(transform.up, DirToPlayerNorm); 
	
	//Convert the cosine value to a radian angle.
	float angle = Mathf.Acos (product); 

	//Convert the radian angle into a degree angle
	angle = angle * Mathf.Rad2Deg; 

	//Use our helper function to determine of the player ship
	// is in the line of sight of the enemy ship
	bool canSee = CanSeeTarget ("PlayerShip"); 

	//Check if the player ship is close enough
	//to be considered in front of the player. 
	if (canSee) {
		//If so, change to ramming mode
		CurrentAIState = AIMode.Ramming; 
		//Add a little visual feedback and change it to red
		renderer.material.color = Color.red; 
	} 
	//Check if the player ship is outside the enemy's vision
	else if (product > 0 && angle < 90) 
	{
		//Change the state to SteerToward
		CurrentAIState = AIMode.SteerTowards;
		//Change its color to green to denote
		// that it found the player. 
		renderer.material.color = Color.green; 
	}
	else {
		//If not, return to the normal state
		CurrentAIState = AIMode.Normal; 
		//Restore the color back to normal
		renderer.material.color = Color.white; 
	}
}

// Update is called once per frame
void Update () {

	//Decides which AI state should be currently active
	DetermineAIState (); 

	//Depending on the current AI mode, call the the corresponding update function. 
	switch (CurrentAIState) {
	//Normal State
	case AIMode.Normal: 
		UpdateNormal(); 
	break; 
		
	//Ramming State
	case AIMode.Ramming:
		UpdateRamming(); 
	break; 

	//Steer towards the player
	case AIMode.SteerTowards:
		UpdateSteerTowards(); 
	break; 
		
	//unknown
	default: 
		Debug.Log("Unknown AI state: " + CurrentAIState); 
	break; 
	}
}

}

"The error Im receiving is a "'(' was unexpected, looking for..." kind of thing" You may not realise this yet, but error messages aren't just a load of random garbage that Unity spits out when it can't cope. They are specifically created by the Unity developers and they generally tell you exactly where, and how, your code is wrong. Look at the error message again and, if you don't understand it, post it here in its entireity and we'll explain to you what it means. That way neither you nor we need to trawl through a lot of unnecessary scripts.... :)

2 Answers

2

Now we know which line causes the error, it becomes apparent what the problem is :slight_smile:

On line 29 of your first script, you begin to define a CanSeeTarget method (with void return type). Within that, on life 45, you’re now trying to declare CanSeeTarget again, this time with a bool return type. You can’t declare the same method twice, and nor can you nest one method definition within another.

You can declare the same method twice. Its called overloading. Its the nested method that the compiler is complaining about. To use overloading simply add another } on line 44.

The C# specification states overloaded methods can differ in their parameters, not in their return types: http://msdn.microsoft.com/en-us/library/ms229029.aspx Either way, I don't think it's what the OP intended... :)

@ tanoshimi Overloaded methods must differ in their parameters. They can differ in their return type as well. This is why you can have both a float and int version of methods like Random.Range I struggled with writing the comment, because I had no idea what the OP was intending to do. In retrospect it probably wasn't overloading.

@tanoshimi Overloaded methods must differ in their parameters. They can differ in their return type as well. This is why you can have both a float and int version of methods like Random.Range I struggled with writing the comment, because I had no idea what the OP was intending to do. In retrospect it probably wasn't overloading.

Thanks guys. I played around with it a little more and tried both the overloading as well as the removal and moving around of functions. I kind of took a chance that I didn’t think made much sense, but it somehow worked. Heres the final script I made for that part.

bool CanSeeTarget (string targetTag) 
{
	// Contains data about the collision
	RaycastHit hitInfo; 
	
	// Performs a recast
	bool hitAny = Physics.Raycast (transform.position, transform.up, out hitInfo); 
	
	// Only respond to the hit info if anything was actually hit
	if (hitAny) {
		if (hitInfo.collider.gameObject.tag == targetTag) {
			return true; 
		} 
	}
	return false; 
}