Wood for the Trees!

I am making an experimental game and wondering if someone can shed some light on a few problems. This is where I am so far…

Step 1: Generate tree objects from coordinates in a txt file. DONE :smile:

Step 2: The ability to select trees using RectContains. DONE :smile:

Step 3: If RectContains, change the contained trees size/chop them etc. DONE :smile:

Step 4: Create handles and connect them with lines for visual representation of a selection tool. DONE :smile:

Step 5: Close the loop of the selection tool… Like in Illustrator, so by clicking on the first handle, the area is enclosed. NO LUCK :? Need help. Please.

Step 6: See if the trees are contained within the bounds of the handles/lines, instead of a RectContains, using PolyContains. NO IDEA :frowning: Need advice and help, pretty please…

Code so far… This is the Handle Editor which I put on an empty GO.

using UnityEngine;
using System.Collections;

public class HandleEditor : MonoBehaviour {

private static int h_count = 0;
public GameObject handle;

	void Update () {
		
		if (Input.GetMouseButtonUp (0)) {
			Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hitInfo;
			
		if (Physics.Raycast (worldRay, out hitInfo)) {
			
			UnityEngine.Object[] handles = FindObjectsOfType(typeof(Handle));
	        h_count = handles.Length;
					
			GameObject handleInstance = Instantiate(handle, hitInfo.point, Quaternion.identity) as GameObject;
			handleInstance.name = "Handle" + h_count.ToString("0");
			Handle handleScript = handleInstance.GetComponent("Handle") as Handle;
			handleScript.id = h_count;
			h_count++; 		    
		}
		}
	}
    }

This is the Handle Counter which I put on the handle prefab (which is just a small cube).

using UnityEngine;
using System.Collections;

public class Handle : MonoBehaviour {
	
	public static ArrayList handles = new ArrayList ();
	public int id;
	
	public static void reset () {
		handles = new ArrayList ();
	}
	
	public static void InitAll () {
		Handle handle;
		handles.Sort ();
		for (int i = 0; i < handles.Count; i++) {
			handle = (Handle)handles[i];

		}
	}
	
	public void Awake () {
		handles.Add(this);
	}
}

This is the line code which connects the handles together.

var receiver: Transform;

function Update () {            
      var id = GetComponent("Handle").id - 1; 
      receiver = GameObject.Find("Handle" + id).transform; 
      var line : LineRenderer = GetComponent(LineRenderer); 
      line.SetPosition(0, transform.position); 
      line.SetPosition(1, receiver.position); 
}

All the code works, but I can’t figure out how to close the shape ie, how to connect the line to the first instance of the handle when I click on it. This should then stop instantiating any more handles.

367839--12750--$screen_shot_2010_08_16_at_170409_695.png

You could put a trigger on your handles and raycast to see if the mouse is over a handle and if so then stop placeing handles and close the area.

Hi ackyth

This is the problem… I implemented a solution like this, by checking if the collider name was handle0, then the target was handle0, rather than handle id-1.

But all this did was to aim all my lines from all the previous handles at handle0.

Where should I put the if statement for it to work? On the prefab line maker? Or on the HandleEditor? Because the initial raycasting is done in the HandleEditor script.

Thanks

A small update. I have put an if statement so that the handles only instantiate when I click on a plane (which has it’s mesh renderer turned off). This means that when I click on the handles themselves, I can drag them around changing the shape of the polygon.

using UnityEngine;
using System.Collections;

public class HandleEditor : MonoBehaviour {

private static int h_count = 0;
public GameObject handle;

	void Update () {
		
		if (Input.GetMouseButtonUp (0)) {
			Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hit;
		
			if (Physics.Raycast (ray, out hit)) {
            if (hit.collider.gameObject.name.Equals("Handle0")) { 
		
		}
			
		    if (hit.collider.gameObject.name.Equals("Plane")) {
			
			UnityEngine.Object[] handles = FindObjectsOfType(typeof(Handle));
	        h_count = handles.Length;
					
			GameObject handleInstance = Instantiate(handle, hit.point, Quaternion.identity) as GameObject;
			handleInstance.name = "Handle" + h_count.ToString("0");
			Handle handleScript = handleInstance.GetComponent("Handle") as Handle;
			handleScript.id = h_count;
			h_count++; 		    
		}
		}
	}
    }
}

I have been messing around with the other code to get the loop to close but with variable success. The h_count referenced from the other script has allowed me to connect “Handle0” to the last handle, but then it overrides the other handles’ connections. How would I put an if statement here? if GameObject.name.Equals(“Handle0”) target = h_count. else as below…?

var receiver : Transform;

var h_count : int;


function Update () {  
		                
      var id = GetComponent("Handle").id - 1;
      receiver = GameObject.Find("Handle" + id).transform; 
      var line : LineRenderer = GetComponent(LineRenderer); 
      line.SetPosition(0, transform.position); 
      line.SetPosition(1, receiver.position);

      h_count = GameObject.Find("Editor").GetComponent("HandleEditor").h_count - 1;
}

Made a boolean to check if the first handle has been clicked and then passed it to the script which connects the lines. It works, in as much as it connects the last handle with the first, but all the other lines disappear. :frowning:

var initial : Transform;
var lastreceiver : Transform;

var receiver : Transform;
var first : boolean;
var h_count : int;


function Update () {  
		                
      var id = GetComponent("Handle").id - 1;
      receiver = GameObject.Find("Handle" + id).transform; 
      var line : LineRenderer = GetComponent(LineRenderer); 
      line.SetPosition(0, transform.position); 
      line.SetPosition(1, receiver.position);

      h_count = GameObject.Find("Editor").GetComponent("HandleEditor").h_count - 1;
      first = GameObject.Find("Editor").GetComponent("HandleEditor").first;
      
      if (first) {
      initial = GameObject.Find("Handle0").transform;
      receiver = GameObject.Find("Handle" + h_count).transform;
      line.SetPosition(0, receiver.position); 
      line.SetPosition(1, initial.position);
}
}
  1. I consider point number 5 a success!!!
    The polygon closes! Here’s my code.
var receiver : Transform;
var first : boolean;
var h_count : int;

function LateUpdate () {  
	
	  h_count = GameObject.Find("Editor").GetComponent("HandleEditor").h_count - 1;
      first = GameObject.Find("Editor").GetComponent("HandleEditor").first;
    if (first){
	if (gameObject.name.Equals("Handle0")){
		receiver = GameObject.Find("Handle" + h_count).transform;
	}
    }
	else{
		                
      var id = GetComponent("Handle").id - 1;
      receiver = GameObject.Find("Handle" + id).transform; 
      
	}
      var line : LineRenderer = GetComponent(LineRenderer); 
      line.SetPosition(0, transform.position); 
      line.SetPosition(1, receiver.position);
}

Now onto point number 6 to check if the trees are contained within the bounds of the handles/lines of my polygon. This is the code from the wiki…

// Array of points making up polygon
var polygonArray = [Vector2(0.0, 1.0), Vector2(0.0, 2.0), Vector2(2.0, 2.0), Vector2(2.0, 1.0), Vector2(1.0, 0.0)];
var point = Vector2(0.5, 0.5);   // See if this point is inside the polygon

function Start () {
   if (Poly.ContainsPoint(polygonArray, point)) {
      print ("Inside! Yay, I'm safe!");
   }
   else {
      print ("Outside! Brr, cold out here!");
   }
}

…and this…

static function ContainsPoint (polyPoints : Vector2[], p : Vector2) : boolean { 
   var j = polyPoints.Length-1; 
   var inside = false; 
   for (i = 0; i < polyPoints.Length; j = i++) { 
      if ( ((polyPoints[i].y <= p.y  p.y < polyPoints[j].y) || (polyPoints[j].y <= p.y  p.y < polyPoints[i].y))  
         (p.x < (polyPoints[j].x - polyPoints[i].x) * (p.y - polyPoints[i].y) / (polyPoints[j].y - polyPoints[i].y) + polyPoints[i].x)) 
         inside = !inside; 
   } 
   return inside; 
}

Now I need to implement it so the transforms of my handles fill the array instead of points. Anyone has any idea how? :? [/code]

Right, so now I have all my handles instantiate under a parent object, this way I can get their positions. Muddling through as I go along. The code below prints the first four handles positions as vector3, for example: (1.096, 13.2, 7.865)
The middle number is the same for all the handles, and I need to get rid of it. So then I will only have two numbers which will be my Vector2 to use in the PolyContains array.

Q1: How do I get these numbers to fill the array in another script?

function Update () { 
var handles = gameObject.GetComponentsInChildren(Transform); 
for ( var handle : Transform in handles ) { 
      print("Positions" + handles[1].position + handles[2].position + handles[3].position + handles[4].position); 
   } 
}

some info on arrays http://www.unifycommunity.com/wiki/index.php?title=Which_Kind_Of_Array_Or_Collection_Should_I_Use%3F

You need to get a pointer to the other script

then you can do a for loop and add each one to the other array

@NOT CODE JUST OUTLINE@

for ( var handle : Transform in handles )
{
new vector2 handletoaddtoarray

handletoaddtoarray.x = handle.x
handletoaddtoarray.y = handle.y

arrayinotherscript.add(handletoaddtoarray)
}

or just give that script a pointer to the array.

thatScript.array = thisScripts.array;

Getting there slowly… :wink: So this code now prints an array of handle positions, for example like so: (0.0, 0.0, 0.0),(-7.1, 13.2, 14.3),(2.0, 13.2, 22.8),(11.6, 13.2, 23.6),(19.9, 13.2, 19.9),(18.6, 13.2, 13.4),(7.9, 13.2, 6.4),(-4.4, 13.2, 7.4)

It always prints (0.0, 0.0, 0.0) at first because the handles appear under the parent object which is set to that position. The question is how to remove that first position in the array?

Secondly, I’m still not clear of how to remove the middle number (which is always the same) to turn this Vector3 array into a Vector2 array?

function LateUpdate () { 

var temphandles = new Array();
var handles = gameObject.GetComponentsInChildren(Transform);
 

for ( var handle : Transform in handles ) {
    var positions = handle.position;    
	temphandles.Add(positions);
	
print(temphandles);
    
   } 
}

Small update… Managed to get rid of the middle number by doing this:

function LateUpdate () { 

var temphandles = new Array();
var handles = gameObject.GetComponentsInChildren(Transform);
 

for ( var handle : Transform in handles ) {
    var positionx = handle.position.x;
    var positionz = handle.position.z;    
    
	temphandles.Add(positionx, positionz);
    print(temphandles);
}
}

Now it prints out this, adding a pair of values each time I instantiate a handle: 0,0,3.819551,20.19551,10.01504,28.39099,21.36842,24.40603,24.45113,7.789491,11.06767,-6.045092,-5.473683,5.007539

Still adds 0,0 at the beginning though. And still no luck with getting these numbers to populate the array in the other script. But will plug away regardless.

Getting warmer…

This prints a list of Vector2 like this: (0.0, 0.0),(7.9, 33.6),(22.9, 22.7),(25.1, 3.5),(10.1, -6.9),(-8.1, 2.7),(-10.1, 22.5)
So surely it should be easy to get THESE numbers into my polyArray? Still stumped

function Update () { 

var outVector2 : Vector2; 
var temphandles : Array = new Array();
var handles = gameObject.GetComponentsInChildren(Transform); 

for ( var handle : Transform in handles ) {
    outVector2.x = handle.position.x;
    outVector2.y = handle.position.z;    
    
	temphandles.Add(outVector2); 
	print(temphandles);
}
}

:roll:

I think I’m so nearly there… This code gives me an error saying:
“Assets/Scripts/Highlight/HandlePositions.js(21,31): BCE0017: The best overload for the method ‘Poly.ContainsPoint((UnityEngine.Vector2), UnityEngine.Vector2)’ is not compatible with the argument list ‘((Array), UnityEngine.Vector2)’.”

But I thought that my temphandles is a Vector2 array since I’m adding Vector2 info to it every time I create a handle. Am I wrong?

var point : Vector2;   // See if this point is inside the polygon

function Update () { 

var outVector2 : Vector2; 
var temphandles : Array = new Array();
var handles = gameObject.GetComponentsInChildren(Transform); 
var polygonArray = [temphandles];

for ( var handle : Transform in handles ) {
    outVector2.x = handle.position.x;
    outVector2.y = handle.position.z;    
    
	temphandles.Add(outVector2); 
	print(temphandles);
	
	
	
	if (Poly.ContainsPoint(polygonArray, point)) { 
      print ("Inside! Yay, I'm safe!"); 
   } 
   else { 
      print ("Outside! Brr, cold out here!"); 
   } 
}
}

I cant really see anything wrong with it, though javascript’s way of dynamic casting things instead of having everything definded is confuseing me. (C# is what im used to)

SUCCESS!!! :smile:

This code detects whether a point is within the polygon! With the small problem of the (0,0) first Vector2 in the array still bugging me. Can I do something like…
polyPoints = temphandles - [0]; ???

So on to the next question, If I have multiple points, such as trees, how do I check whether they are inside/outside the poly. Do I now need to create a vector2 array for all the points? Or can I check each tree position like this…

treeScreenPos = Camera.main.WorldToScreenPoint(tree*.position);*
In the meantime I’m just happy this part works! Yay!

```
*var point : Vector2;

function Update () {

var polyPoints : Vector2;
var outVector2 : Vector2;
var temphandles : Array = new Array();
var handles = gameObject.GetComponentsInChildren(Transform);

for ( var handle : Transform in handles ) {
outVector2.x = handle.position.x;
outVector2.y = handle.position.y;

temphandles.Add(outVector2);
polyPoints = temphandles;	

if (Poly.ContainsPoint(polyPoints, point)) {
print (“Inside! Yay, I’m safe!”);
}
else {
print (“Outside! Brr, cold out here!”);
}
}
}*
```