selection box ... isometric overhead angled view game

Hello all - first post here. Lets get down to it :slight_smile:

I have a list that contains all the current units in my game world. What I’m trying to achieve is to take the current GUI mouse position, create a REct based upon the distance dragged and use its Contains method to check against all my game units to see if we’ve selected any (I know, so many posts on the forum concerning this - but none seem to help me).

I am aware of the differences between GUI, Screen coord systems but still cant quite figure this out.

I am using Event.current.mousePosition to get my mousing in the OnGUI event and doing this when trying to check for selection:

	private void TrySelectionBox(){
		
		//this is for getting the width, height of RECT
		float width =  currentMouse.x - startMouse.x;
		float height =  currentMouse.y - startMouse.y;

		//color of selection texture
		GUI.color = new Color(1.0f, 1.0f, 1.0f, 0.70f);	
		//create rect here
		Rect drawRect = new Rect(startMouse.x, startMouse.y, width, height);
		//draw texture
		GUI.DrawTexture(drawRect,healthBar, ScaleMode.StretchToFill);
			
		
		foreach(Unit u in GameManager.GameUnits){
			
			Vector3 worldToScreenPoint = Camera.main.WorldToScreenPoint(u.transform.position);
		
			if(drawRect.Contains(worldToScreenPoint)){
				print("Selection contains: " + u.Name);
			}		
		}
		
	}

I am getting selections, but like all the other posts out here, its just not quite right :slight_smile: I have to select below the unit to actually get it to select which tells me its that darn screen vs GUI coords discrepancy but I just cant get it!!! I hope someone can shed the light on my issue here :slight_smile: Thanks so much

Just draw everything for debugging purposes ... use Debug.DrawLine and the other Debug. commands (Look at the documentation page for Debug). (The "gizmo" commands can also be helpful.) 90% of the code I have ever typed out in Unity is "Debug.DrawLine ..." - exaggerating for humour but you get the point, it's totally central to doing things like that in Unity. It is one of those situations "If you teach a man to fish..." BTW you don't make clear WHAT the heck you're doing .. is this a 3D game, what "are" these units etc ? Cheers

Fattie - thx for the reply. This is a 3D game.A "Unit" is a soldier in this case. I'm attempting the typical RTS. Want to create a multi-selection box with mouse coords - same old story. Everything I've seen out here uses raytracing for detection, but I thought it might be easier to do it this way? Is that enough? thanks agin

Fattie: I'm trying to do an isometric-style game so the cam is offset. I'm currently drawing the "selection rectangle" in the GUI then attempting to convert tose coords to world and determine if the soldier units are within the rect created by the mouse-drag. So how would you create rays for EVERY single place that would fall withing a given rect? there has to be a better way to go about it, right?

oopos - just FYI - I noticed that I hadn't replaced "WorldToViewportPoint with WorldToScreenPoint. Either way, this still doesn't work.

Man I'm really trying to help someone help me! Here's another screenshot of my craziness: ![alt text][1] [1]: http://dl.dropbox.com/u/16876550/Screen%20Shot%202013-04-10%20at%205.36.03%20PM.png So my coordinates are flipped - You can see my selection box up at the top and the very bottom of the console reads "Selection contains PLAY 0...". So the question is how the heck do I get them right!??? Thanks to all super heroes out there :)

3 Answers

3

I think what I’d do is create two raycasts from screen to world - one at the start location of the drag rect and one at the end location of the drag rect.

Then, take the intersections (with the ground) and use the locations to create a box collider with edges that match the cast. Following that, test collision on the box to get a list of everything that collides with the box.

Typical of RTS’s is that a box dragged downward selects only those units fully inside it while boxes dragged upward select units that are inside OR cross the boundary of it.

This solution I propose handles the last (crossing or within) - to get the first, you’ll need an additional step of looping through all the units and seeing if their leftmost, rightmost, topmost and bottommost coordinates are all within the coordinates. If so, you keep them. If not, they’re partially outside and you drop them.

This solution has an additional benefit in that you can make the collider visible (by adding a mesh at the same location) and see the selection in 3D.

And yes, you can make the box be aligned with the camera so that it seems more 2D than it is.

http://wiki.unity3d.com/index.php?title=CameraFacingBillboard

Indeed -- one point Drac regarding your first paragraph. Not so much start and end. You just do it continually as you drag, so it's start + "wherever you are dragging now" Your third paragraph is a great gamer insight, thanks for that.

I think your underlying problem with your initial approach is that you are trying to use Event.current.mousePosition and believe that it is in screen coordinates. It is not. The GUI system does all sorts of weird layout stuff to do with positions and rectangles and you have to convert it’s coordinates into screen coordinates using GUIUtility.GUIToScreenPoint.

It seems reasonable to me to convert unit positions to screen positions and then check your selection that way.

Indeed. One should not concern one's self with the GUI system at all - wherever possible!

Not if you are converting the objects position to screen coordinates no. Yep - input mouse position is in screen coordinates. The only other thing would be to convert all of the coordinates of the AABB associated with the object to screen space (by getting the bounds and doing WorldToScreenPoint on all of the 8 points) I'd suggest drawing a small icon where the WorldToScreenPoint comes out at for your initial position for testing purposes straight away - that might give you a clue as to where it thinks the object is.

similar questions http://answers.unity3d.com/questions/449217/how-can-i-convert-this-to-area-mouse-drag-selectio.html

What I did for the above was give the objects in question a specific tag (in this case “selectable”) I then created an array of all selectable objects in the scene and then checked if a raycast of it’s screen co-ordinates fell inside the box.

I’ve just cut out the specific bit in question but this is the code I implement:

void Update() {
if(Input.GetMouseButtonDown(0)) {
    start_box = Input.mousePosition;
}

if(Input.GetMouseButtonUp(0)) {
    end_box = Input.mousePosition;
makeBox();
GameObject[] csel = GameObject.FindGameObjectsWithTag("Selectable");
for (int i = 0; i < csel.Length; i++) {
					Vector3 objectlocation = Camera.main.WorldToScreenPoint(new Vector3(csel<em>.transform.position.x,csel_.transform.position.y,csel*.transform.position.z));*_</em>

* //If the object falls inside the box set its state to selected so we can use it later*
* if(boundbox.Contains(objectlocation)) {*
_ csel*.SendMessage(“setisSelected”, true);
}
}
}
}
private void makeBox() {
//Ensures the bottom left and top right values are correct*

* //regardless of how the user boxes units*
* float xmin = Mathf.Min(start_box.x, end_box.x);
float ymin = Mathf.Min(start_box.y, end_box.y);
float width = Mathf.Max(start_box.x, end_box.x) - xmin;
float height = Mathf.Max(start_box.y, end_box.y) - ymin;*

* boundbox = new Rect(xmin, ymin, width, height);
}*_

Be careful with world co-ordinate boxing because of the depth of the selection sometimes it's not square (often it isn't) and the base and be angular often times your object might appear inside the 2D representation but not the 3D projection.

gRntaus: I guess where I'm loosing it is how to create - in your example - boundBox

I've tried to make the code more robust above in my answer I have a LOT of other stuff going on so I've tried to pluck up the very basics for you, keep in mind I only wanted "selectable" units so I've created a tag to get them. I guess you could search for objects by name as well, or filter your results by name etc, but for what I wanted it works great.

Thank you! This helped me a lot. For anyone that is confused about how to use this, the variables at the top should be: > private Rect boundbox; private Rect objectlocation; private Vector3 start_box; private Vector3 end_box; and you need a script on the Object that you are selecting. Something like this will work: public class Select : MonoBehaviour { void setisSelected(bool Selected) { Debug.Log(Selected); } }