I'm trying to find some information on raycasting but everything i've read is way over my head. Essentially i have a first person perspective targeting reticle that i want to use to select an enemy in the distance. I know i need to set up some sort of ray casting system, but i'm totaly lost on where to even begin, I know that the enemy must have some sort of colider, and the reticle must emit a ray, but beyond that i'm lost any help / posting of a rudimentary script would be most appreciated...
A couple of links to get you started: Camera.ScreenPointToRay() Physics.Raycast() In brief, the steps are: 1. Create a ray corresponding to the current mouse position using ScreenPointToRay(). 2. Perform the raycast using Physics.Raycast(). 3. Do whatever you want to with the results.
thanks so much, i'l have a look at those links as soon as i get home tonight, i'm sure i'l have plenty more questions heheheh
ok, so i've been fidling with this for a better pat of the day and i'm still unsure how to implement the actual raycast. As far as i understand (correct me if i'm wrong) camera.screenPointToRay is setting the direction of the cast, and Physics.Raycast is actually casting the ray. this is what i've put down so far and got the ray projecting through debug.DrawRay the way i want, but i'm unsure how to pass this on to the actual raycast then receive info on what has been hit Code (csharp): function Update() { var ray = camera.ScreenPointToRay (Vector3(371,210,0)); Debug.DrawRay (ray.origin, ray.direction * 400, Color.blue); }
Check out the documentation for Physics.Raycast() again. Towards the middle of the page, under the second overload of the function, is an example showing how to perform a raycast and then access the returned data. To see how to get the necessary info from the ray in order to pass it to the raycast function, check out the documentation for Ray. To see what information is returned by the raycast, check out the documentation for RaycastHit. The documentation is usually a good place to start for this sort of thing; I find that typing whatever I'm interested in in the script reference 'search' box usually leads me to the information that I need. (Other good resources are the forums and Unity Answers; searching for 'raycast' on either site will most likely turn up many examples.)
Thanks Jesse, i got it working just the way i need it. Perhaps you could shed some light on the next step... how do i go about collecting information from the object assigned to the collider that the raycast has hit, then send it back to perform a new function based on the results of the gathered information?
You can acquire a reference to the game object through several of RaycastHit's member fields, such as 'collider' or 'transform' (which you may already know). Once you have access to the game object, there are many ways you can 'communicate' with it. One is to acquire references to components using GetComponent() and interact with the components directly. Another would be to use the GameObject messaging functions to invoke functions that you've associated with the game object via scripts (see the GameObject documentation for info and examples). Beyond that, it really depends on what you want to do with the object exactly. If you have a particular example in mind and can describe it, someone could probably offer some more specific feedback.
ok, i guess more specifically i just need a selection border (in the form of a gameobject i've already created) to apear around the intended object when the ray hits. Then a seperate input (spacebar) to destroy the objects in the selection
The 'selection border' question has come up before in the forums; maybe try searching for 'highlight object' or 'outline object' and see if you can find any of those threads. For deleting the objects, you'll probably need to keep track of which objects are selected, either by storing them in a container or somehow flagging them as being selected. Then, when the space bar (or whatever control) is pressed, you would invoke GameObject.Destroy() on all selected objects.
Thanks for all the assistance jesse, it's been very helpfull, i've got another question. Here's my script for selecting the objects in question Code (csharp): function DrawGreenRay() { var ray = camera.ScreenPointToRay (Vector3(371,210,0)); Debug.DrawRay (ray.origin, ray.direction * 400, Color.green); var hit : RaycastHit; if (Physics.Raycast (transform.position, transform.forward, hit, 400)){ if(hit.collider.gameObject.tag=="GreenEnemy" ){ var go = GameObject.Find("EnemySelectionReticle"); go.GetComponent(SelectionReticleAnimator).selected = true; yield WaitForSeconds (.1); go.GetComponent(SelectionReticleAnimator).selected = false; print ("Green Selected" + hit.collider); } else print ("wrong color"); } } Everything works the way i want, however i'm stumped as to how to make the GameObject.Find("EnemySelectionReticle") search only within the hierarchy of the object "GreenEnemy" instead of the entire scene. i've followed the documentation in http://ws.cis.sojo-u.ac.jp/~izumi/U...entation/ScriptReference/GameObject.Find.html which seems to say that i need to specify Code (csharp): GameObject.Find("/GreenEnemy/ReticleObject/EnemySelectionReticle"); but that returns a NullReferenceException i've also tried sendmessage but that didnt seem to work either This ones's got me confused, any help would once again be appreciated
hehehe, well of course i try the entire weekend before posting, then 15 minutes after posting figure it out. IF its of any help to anyone, here's the cod snipet that i adjusted Code (csharp): function DrawGreenRay() { var ray = camera.ScreenPointToRay (Vector3(371,210,0)); Debug.DrawRay (ray.origin, ray.direction * 400, Color.green); var hit : RaycastHit; if (Physics.Raycast (transform.position, transform.forward, hit, 400)){ if(hit.collider.gameObject.tag=="GreenEnemy" ){ transform.Find("/Green Enemy/ReticleObject/EnemySelectionReticle").GetComponent (SelectionReticleAnimator) .selected = true; yield WaitForSeconds (.1); transform.Find("/Green Enemy/ReticleObject/EnemySelectionReticle").GetComponent (SelectionReticleAnimator) .selected = false; print ("Green Selected" + hit.collider); } else print ("wrong color"); } } getcomponent had to be changed to a Code (csharp): transform.Find("/parent/child/childofchild/") .GetComponent (Child's script name) .function to call
ok, got a new problem a summary of what i'm trying to do: select objects based on their color (in this case i've taged them) then once selected press "execute" to destroy the active selection. Works fine on multiple enemies of different colors, but as soon as i have 2 of the same it targets only the first of that color in the scene hierarchy no matter what object is being aimed at Here's my scripts Code (csharp): function DrawYellowRay() { var ray = camera.ScreenPointToRay (Vector3(371,210,0)); Debug.DrawRay (ray.origin, ray.direction * 400, Color.yellow); var hit : RaycastHit; if (Physics.Raycast (transform.position, transform.forward, hit, 400)){ if(hit.collider.gameObject.tag=="YellowEnemy" ){ print ("Yellow Selected" + hit.collider); transform.Find("/Yellow Enemy/ReticleObject/EnemySelectionReticle") .GetComponent (SelectionReticleAnimator) .selected = true; yield WaitForSeconds (.1); transform.Find("/Yellow Enemy/ReticleObject/EnemySelectionReticle") .GetComponent (SelectionReticleAnimator) .selected = false; print ("Yellow Selected" + hit.collider); } else print ("wrong color"); } } Code (csharp): var SelectTargetSound : AudioSource; var selected = false; var selectionActive = false; var AnimationSpeed = 1; var destroyer = false; function Update () { if (selected == true) { playSelectionReticleAnimation(); } //execute is spacebar if (Input.GetButtonDown ("Execute")) { DestroySelected(); } } function playSelectionReticleAnimation() { if (selectionActive == true) { print ("Already Selected") ; } else if (selectionActive == false) { SelectTargetSound.Play(); animation.Play ("ReticleSelect"); animation ["ReticleSelect"].speed = AnimationSpeed; selectionActive = true; } } function DestroySelected() { if (selectionActive == true){ Destroy ( transform.root.gameObject ); print ("Destroyed!!!"); } }
.Find only finds the first instance of an object that matches the name. Since you have the collider component already, follow that to the part you're looking for e.g. var thing = hit.collider.GetComponent(Enemy); thing.SetSelected(); and in your Enemy.SetSelected() function, you'd activate the animated object. Also Find is "really really slow" and calling it outside of initialization time is generally not something you want to happen if you can avoid it.
thanks for the help but i'm really confused on how to implement what you're talking about. i understand i need to get rid of the transform.find lines, but the rest is over my head, sorry... not my specialty here
Code (csharp): var ray = camera.ScreenPointToRay (Vector3(371,210,0)); Debug.DrawRay (ray.origin, ray.direction * 400, Color.yellow); var hit : RaycastHit; if (Physics.Raycast (transform.position, transform.forward, hit, 400)){ if(hit.collider.gameObject.tag=="YellowEnemy" ){ print ("Yellow Selected" + hit.collider); Replace the following Find functions Code (csharp): transform.Find("/Yellow Enemy/ReticleObject/EnemySelectionReticle") .GetComponent (SelectionReticleAnimator) .selected = true; yield WaitForSeconds (.1); transform.Find("/Yellow Enemy/ReticleObject/EnemySelectionReticle") .GetComponent (SelectionReticleAnimator) .selected = false; With a much more happy Code (csharp): hit.collider.GetComponent(YellowEnemy).SetSelected(); Your YellowEnemy script (or Enemy script, or whatever script it is that you've attached to your YellowEnemy-tagged objects) would then have a SetSelected function that did what the find functions tried to do. Code (csharp): private var animatorComponent : SelectionReticleAnimator; function Start() { animatorComponent = GetComponentInChildren(SelectionReticleAnimator); } function SetSelected() { animatorComponent.selected = true; yield WaitForSeconds(0.1); animatorComponent.selected = false; }
ah, much more clear, thanks a lot for the help, i'l try putting it all together in the morning and see how it goes. Cheers!
Just chiming in again to say major thanks to both of you, i think that was the last of my issues in this matter. Cant wait to show off what i've got working here in the coming weeks!