I’ve done this many, many times before. But this time, when I use the below code to select a character, it works the first time… and only that one time. It will NOT work twice. I just don’t know why and I’ve torn my project apart multiple times trying to figure it out.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Select();
}
}
public void Select()
{
RaycastHit hit;
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Transform previous = isSelected;
if (UnitManager.allUnits.Contains(hit.collider.transform.gameObject) && isSelected != hit.collider.transform)
{
isSelected = hit.collider.transform;
Debug.Log(hit.collider.transform.gameObject.name + " is selected");
}
else if (isSelected != null)
{
Debug.Log(previous.gameObject.name + " was deselected");
}
}
}
What exactly does not work the second time? Place some Debug.Log() lines through the method to see how far it gets executes and which if-statement does not get entered. Select() should always be called, i highly doubt that the Raycast if does not work on the second run, so it’s probably one of your custom if’s below that which doesnt get entered - even tho unless one of your methods causes the statement to fail afterwards i wouldnt know why it should fail either.
I have a few debug.log’s in there and the first time I click they all run as they should. The second time it may or may not run and the third time it just won’t. Then sometimes I start the project and it works every single time. I’m going nuts
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
/// <summary>
/// Unit Manager handles unit selection, adding/removing units from the unit list, destroying unit gameobjects...
/// </summary>
public class UnitManager : MonoBehaviour
{
private static GameObject Units;
private static GameObject P1Units;
private static GameObject P2Units;
public static List<GameObject> allUnits = new List<GameObject>();
public static List<GameObject> p1Units = new List<GameObject>();
public static List<GameObject> p2Units = new List<GameObject>();
public static List<GameObject> hero = new List<GameObject>();
private Camera cam;
private PlayerCamera playCam;
public static Transform isSelected;
/// <summary>
/// Instantiates the prefabs for the character models of P1 and P2 hero choices
/// </summary>
private void Awake()
{
cam = Camera.main;
playCam = cam.GetComponent<PlayerCamera>();
Units = GameObject.Find("Units");
P1Units = GameObject.Find("P1Units");
P2Units = GameObject.Find("P2Units");
//Player1 = GameObject.Find("Player1Cam").GetComponent<PlayerCamera>();
//Player2 = GameObject.Find("Player2Cam").GetComponent<PlayerCamera>();
UnitInit();
}
/// <summary>
/// Adds player 1 and 2 to the list of all untis
/// </summary>
void Start()
{
}
/// <summary>
/// select a unit on click
/// </summary>
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Select();
}
}
private void Select()
{
RaycastHit hit;
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Transform previous = isSelected;
Debug.Log(hit.collider.transform.gameObject.name);
if (UnitManager.allUnits.Contains(hit.collider.transform.gameObject) && isSelected != hit.collider.transform)
{
PlayerCamera.newSelection = true;
isSelected = hit.collider.transform;
Debug.Log(hit.collider.transform.gameObject.name + " is selected.");
}
else if (isSelected == hit.collider.transform)
{
Debug.Log(previous.gameObject.name + " is already selected.");
}
else
{
Debug.Log(previous.gameObject.name + " was deselected.");
}
}
}
public static void UnitInit()
{
foreach (Transform child in Units.transform)
{
foreach (Transform child2 in child.transform)
{
if (child2.gameObject.CompareTag("Unit"))
{
AddUnit(child2.GetComponent<Unit>());
}
foreach (Transform child3 in child2.transform)
{
child3.gameObject.layer = 10;
}
}
}
isSelected = allUnits[0].transform;
}
///<summary>
///add a new unit to the list of all units and to the respective player's unit list
/// </summary>
public static void AddUnit(Unit unit)
{
if (unit.gameObject.CompareTag("Unit"))
{
allUnits.Add(unit.gameObject);
}
if (unit.transform.IsChildOf(P1Units.transform))
{
p1Units.Add(unit.gameObject);
}
else if (unit.transform.IsChildOf(P2Units.transform))
{
p2Units.Add(unit.gameObject);
}
}
}
@Aerhart941
so now that you always have prints on raycast hit, what do you see?
Does the raycast always hit? Or do sometimes you see that that raycast does work?
The raycast always outputs that it hits something 100% of the time. The odd thing is the times it doesn’t work, the raycast is hitting the ground or wall past the character. And when it does work, it hits the character and works properly nurmerous times.
I would start with assigning a layer to the character, and using a layer mask in the raycast.
See if that solves things.
This sounds like some sorting issues of the objects in 3D.
I have some new info… I noticed something. I am using NavMesh for character movement and every so often, my characters will all crouch and then stand back up. Once that happens they will not interact with Raycasts anymore.
Any idea why that is happening? The crouching happens completely randomly. Sometimes it will be immediately, sometimes not at all. And sure enough, every time they crouch the raycasts stop working on them.
Ahhh, yes. NavMesh and Physics.Raycast don’t work well together. I don’t recall the exact details but google it and you should find a bunch of discussions.
Maybe someone can shed some light on the exact problem and solution, I’m not familiar with it.
You mentioned that your character crouches every now and then and stops? Have you considered depending on where your raycast is coming from it might be that the movement from the crouch animation is causing your raycast to stop? It could be detecting a different object just from that little bit of movement and that is what is throwing off the code.
At least that’s just my theory, you have to bear in mind if your raycast is coming out of a character somehow that it will follow all movement from that character so if you have it attached to your head and the head is pointing down slightly as it crouches then it will be pointing at the terrain rather than your intended object and so on.
This is one of the reasons why I think I’ve seen people use multiple raycasts to help the AI detect things rather than just one.
It was absolutely the crouching that was ruining it. After the character crouched and stood back up, I guess that made the collider fall through the stage. I went ahead and pulled an all-nighter and redid the entire Third Person controller and everything is perfect.
Ah, glad you fixed it, it’s just something to bear in mind with raycasts, another point is that if you simply attach any raycast script to a model the raycast will shoot out from wherever the origin point is often from the centre of the model itself, because of this I often like to create empties for those sorts of scripts so I know where exactly the raycast is going to shoot from. You can even get fancy if you’ve got a lot of movement going on and have the empty stay at a certain height or whatever to prevent issues like that happening without affecting the model animation itself.
Yea that’s a good practice. I have all of the script for the models on an empty gameObject and the models inside of it. Whatever was going on with the Unity Standard third person controller really must have thrown the models out of whack. I will be avoiding that thing going forward.