Search Unity

[Solved] RayCast doesn't hit Object

Discussion in 'Physics' started by Karrzun, Oct 26, 2017.

  1. Karrzun

    Karrzun

    Joined:
    Oct 26, 2017
    Posts:
    129
    Hey everyone,

    I'm currently having a little problem with my project and RayCasts in particular. In general, I use the RayCast to select a variety of things, which can be summarised as HexTiles and InteractableObjects. The HexTiles make up my map and the InteractableObjects are all the things which then can be placed on the map. When either one of those objects is hit, it's highlighted by changing its color to visualize to the user, what he currrently has selected. HexTiles will be colored red, InteractableObjects white.
    Now, for most of the things, it all works perfectly fine. HexTiles are always hit and they always change their color. But out of all my InteractableObjects I've got so far, there are two, that won't work. When I click one of those, instead of hitting and highlighting the InteractableObject, it hits and highlights the HexTile behind it. Here are some examples:

    1) a normal gras map, without any selections
    Gras_normal.PNG

    2) a gras map with a HexTile selected
    Gras_hex.PNG

    3) a gras map with a pine tree (InteractableObject) selected
    Gras_tree.PNG

    4) a sand map with a HexTile selected
    Sand_hex.PNG

    5) a sand map after trying to select the palm tree (InteractableObject)
    Sand_tree.PNG

    As you see, it won't select/highlight the palm tree even though I use the same code and stuff as I do to select the pine tree, which obviously works.
    The code is pretty straight-forward and shouldn't provide any problems:


    Code (CSharp):
    1.  public class MouseManager : MonoBehaviour {
    2.  
    3.     CameraManager cameraMan;
    4.     GameManager gameMan;
    5.  
    6.     // Use this for initialization
    7.     void Start () {
    8.         cameraMan = this.gameObject.GetComponent<CameraManager> ();
    9.         gameMan = this.gameObject.GetComponent<GameManager> ();
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void Update () {
    14.  
    15.        [...]
    16.  
    17.         // MOUSE POINTER HOVER
    18.  
    19.         // Returns the type of GameObject we are mousing over
    20.         Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );
    21.         RaycastHit hitInfo;
    22.  
    23.         if( Physics.Raycast(ray, out hitInfo) ) {
    24.             GameObject hitObject = hitInfo.collider.transform.parent.gameObject;
    25.  
    26.             // What kind of object are we over?
    27.             if(hitObject.GetComponent<Hex>() != null) {
    28.                 // We are over a hex
    29.                 MouseOver_Hex(hitObject);
    30.             } else if (hitObject.GetComponent<InteractableObject>() != null) {
    31.                 // We are over an InteractableObject
    32.                 MouseOver_Interactable (hitObject);
    33.             }
    34.         }
    35.     }
    36.  
    37. // What happens when we click on a tile?
    38.     private void MouseOver_Hex(GameObject hitObject) {
    39.         // LEFT-CLICK
    40.         // to deselect InteractableObjects and toggle tile-highlighting
    41.         if(Input.GetMouseButtonDown(0)) {
    42.             if (gameMan.HideCreationMenu ()) {
    43.                 return;
    44.             }
    45.  
    46.             // If we have an InteractableObject selected, we simply deselect it
    47.             if ( MapData.IsInteractableObjectSelected() ) {
    48.                 MapData.DeselectInteractableObject ();
    49.                 return;
    50.             }
    51.  
    52.             // If we don't have anything selected, we toggle highlighting of the tile
    53.             hitObject.GetComponent<Hex>().ToggleHighlighting();
    54.         }
    55.  
    56.         // RIGHT-CLICK
    57.         // for InteractableObject interaction
    58.         else if(Input.GetMouseButtonDown(1)) {
    59.             // Only do something, when the tile is not already occupied
    60.             if (hitObject.GetComponent<Hex> ().occupied) {
    61.                 return;
    62.             }
    63.  
    64.             // If we don't have anything selected, we open the menu to create an InteractableObject
    65.             if (!MapData.IsInteractableObjectSelected()) {
    66.                 MapData.SetInteractionSpot (hitObject);
    67.                 gameMan.ShowCreationMenu ();
    68.  
    69.             // Otherwise we check what it is, that we have selected
    70.             } else {
    71.                 GameObject selObj = MapData.GetSelectedInteractableObject ();
    72.        
    73.                 // If it's a unit, we move it
    74.                 if (selObj.GetComponent<Unit> () != null) {
    75.                     MapData.SetInteractionSpot (hitObject);
    76.                     Unit selectedUnit = selObj.GetComponent<Unit> ();
    77.                     selectedUnit.currentTile.GetComponent<Hex> ().occupied = false;
    78.                     selectedUnit.currentTile = hitObject;
    79.                     selectedUnit.destination = hitObject.transform.position + hitObject.GetComponent<Hex>().GetHeightOffset();
    80.                     hitObject.GetComponent<Hex> ().occupied = true;
    81.            
    82.                 // Anything else (loot, obstacle, ...) is simply deselected
    83.                 } else {
    84.                     MapData.DeselectInteractableObject ();
    85.                 }
    86.             }
    87.         }
    88.     }
    89.  
    90.     // What happens when we click on an InteractableObject?
    91.     private void MouseOver_Interactable(GameObject hitObject){
    92.         // LEFT-CLICK
    93.         // to select and deselect the InteractableObject
    94.         if(Input.GetMouseButtonDown(0)) {
    95.             if (gameMan.HideCreationMenu ()) {
    96.                 return;
    97.             }
    98.  
    99.             // If the clicked InteractableObject is the one we already selected, only deselect it
    100.             bool sameInteractableObject = hitObject.GetComponent<InteractableObject> ().IsSelected ();
    101.             MapData.DeselectInteractableObject ();
    102.  
    103.             if (sameInteractableObject) {
    104.                 return;
    105.             }
    106.  
    107.             // Otherwise, after deselecting the former selected InteractableObject, we select the new one
    108.             MapData.SelectInteractableObject (hitObject);
    109.         }
    110.  
    111.         // RIGHT-CLICK
    112.         // to change color
    113.         else if(Input.GetMouseButtonDown(1)){
    114.             // If a selected InteractableObject is right-clicked, it is deselected
    115.             if (hitObject.GetComponent<InteractableObject> ().IsSelected ()) {
    116.                 MapData.DeselectInteractableObject ();
    117.             }
    118.             // If an unselected InteractableObject is right-clicked, its color is changed
    119.             else {
    120.                 hitObject.GetComponent<InteractableObject> ().SwitchColor ();
    121.             }
    122.         }
    123.     }
    Code (CSharp):
    1. public static class MapData {
    2.  
    3.     private static GameObject selectedInteractableObject;
    4.     private static GameObject creationSpot;
    5.  
    6.     [...]
    7.  
    8.     // Selects an InteractableObject and highlights it
    9.     public static void SelectInteractableObject(GameObject gameObj){
    10.         gameObj.GetComponent<InteractableObject> ().Select ();
    11.         selectedInteractableObject = gameObj;
    12.     }
    13.  
    14.     // Deselects the currently selected InteractableObject and changes its color back to standard
    15.     public static void DeselectInteractableObject(){
    16.         if (selectedInteractableObject != null) {
    17.             selectedInteractableObject.GetComponent<InteractableObject> ().Deselect ();
    18.             selectedInteractableObject = null;
    19.         }
    20.     }
    21.  
    22.     // Returns true, if an InteractableObject is currently selected. False otherwise
    23.     public static bool IsInteractableObjectSelected(){
    24.         return selectedInteractableObject != null;
    25.     }
    26.  
    27.     // Returns the currently selected InteractableObject
    28.     public static GameObject GetSelectedInteractableObject(){
    29.         return selectedInteractableObject;
    30.     }
    31.  
    32.     // Sets the location where to create an InteractableObject
    33.     public static void SetInteractionSpot(GameObject newSpot){
    34.         creationSpot = newSpot;
    35.     }
    36.  
    37.     // Returns the location where to create an InteractableObject via a GameObject element
    38.     public static GameObject GetInteractionSpot(){
    39.         return creationSpot;
    40.     }
    41.  
    42. }
    Code (CSharp):
    1. public class Hex : MonoBehaviour {
    2.     public bool occupied = false;
    3.  
    4.     Material standardMaterial;
    5.     bool highlighted = false;
    6.  
    7.     [...]
    8.  
    9.     // Highlights and un-highlights the tile
    10.     public void ToggleHighlighting(){
    11.         MeshRenderer mr = this.GetComponentInChildren<MeshRenderer>();
    12.  
    13.         // If the hex tile is already highlighted, we change it back to normal
    14.         if (highlighted) {
    15.             mr.material = standardMaterial;
    16.             highlighted = false;
    17.  
    18.         // Otherwise we highlight it
    19.         } else {
    20.             mr.material.color = MyColor.hexHighlightColor;
    21.             highlighted = true;
    22.         }
    23.     }
    24. }
    All the InteractableObjects implement this code, with their own twist obviously
    Code (CSharp):
    1. public abstract class InteractableObject : MonoBehaviour {
    2.  
    3.     public GameObject currentTile;
    4.     public Color standardColor;
    5.  
    6.     protected bool selected = false;
    7.  
    8.     public abstract void SwitchColor ();
    9.  
    10.     public void SetColor(Color c){
    11.         this.GetComponentInChildren<MeshRenderer> ().material.color = c;
    12.     }
    13.  
    14.     public void ResetColor(){
    15.         this.GetComponentInChildren<MeshRenderer> ().material.color = standardColor;
    16.     }
    17.  
    18.     public void Select(){
    19.         selected = true;
    20.         SetColor (MyColor.interactableHighlightColor);
    21.     }
    22.  
    23.     public void Deselect(){
    24.         selected = false;
    25.         SetColor (standardColor);
    26.     }
    27.  
    28.     public bool IsSelected(){
    29.         return selected;
    30.     }
    31.  
    32.     public void Destroy(){
    33.         Destroy (this.gameObject);
    34.     }
    35. }

    So, I hope I provided enough code and examples. Does anybode know why the palm tree won't be hit by the RayCast? Thank you in advance!
     
  2. Plystire

    Plystire

    Joined:
    Oct 30, 2016
    Posts:
    142
    Can you select the palm tree by selecting the top of it instead of the trunk?

    It could be that the ray is off by a little bit. Use Debug.DrawLine/DrawRay to draw the entire ray from ray.origin to hitInfo.point, and compare that with your tree collider to see if it's actually hitting the tree's geometry. A screenshot showing both the line and the tree's collider would also be helpful
     
  3. Karrzun

    Karrzun

    Joined:
    Oct 26, 2017
    Posts:
    129
    No, I couldn't select the top of the palm tree either, but by now I was able to solve this by myself.
    It seems, that after importing the different tree models, I immediatly ticked the checkbox "Generate Colliders" for the all the other trees in my project except for the two that didn't work (the palm tree and a dead tree) - I must have missed those. Then I created all the different tree-Prefabs. The ones, where I had checked the checkbox, got a Mesh Collider. The other two did not get one, when creating the prefab, and still didn't get it automatically after checking the "Generate Colliders" checkboxes afterwards, even after refreshing the prefabs and stuff. By now, I manually added the Mesh Colliders to the broken Prefabs, which solved the problem.

    TL; DR I'm an idiot.

    Jus did some stuff in the wrong order and it kept me busy for 3 days now... and after posting the problem online, I find the solution within a couple of hours. -_-

    Well, thank you anyway for your reply and have a nice day!


    P.S: Is there a way to mark this thread as solved?
     
    Last edited: Oct 27, 2017
  4. Plystire

    Plystire

    Joined:
    Oct 30, 2016
    Posts:
    142
    I believe you can edit your first post to change the title of the thread.