Please clarify your first question. Are you saying that the player cannot be spotted after the first time the AI spots them? To try and answer your questions I need a bit more explanation about your code. I think I get what you are trying to do, but you seem to be doing it in a strange way. I’ve commented what doesn’t seem clear. Also I’ve commented in stuff that may help.
void TragetAvailable()
{
if (target)
{
if (sightRaycasts ())
{
AI_State_HasTarget();
}
}
}
public bool sightRaycasts()
{
bool retVal = false;
RaycastHit hitTowardsLowerBody;
RaycastHit hitTowardsUpperBody;
float raycastDistance = sightDistance + (sightDistance * 0.5f);
Vector3 targetPosition = lastKnowPosition;
if (target)
{
targetPosition = target.transform.position;
}
Vector3 raycastStart = transform.position + new Vector3 (0, 1.6f, 0); //Why not just have a transform placed where you want to do your line of sight checks towards?
Vector3 direction = targetPosition - raycastStart;
LayerMask excludeLayers = ~((1 << 9) | (1 << 10)); //Exclude Ragdoll and Enimies Layer Mask
//I recommend using this: https://docs.unity3d.com/ScriptReference/LayerMask.html. Using LayerMasks prevents errors caused by incorrectly entering layer numbers
Debug.DrawRay (raycastStart, direction + new Vector3 (0, 1, 0)); // is the offset "new Vector3 (0, 1, 0)" a offset for where in the enemy/player body you want to do your LOS check towards? If so, rather use a transform to do your raycast towards and get transform.position
if (Physics.Raycast (raycastStart, direction + new Vector3 (0, 1, 0), out hitTowardsLowerBody, raycastDistance, excludeLayers))
{
if (hitTowardsLowerBody.transform.GetComponent<CharacterStats> ())
{
if (target)
{
if (hitTowardsLowerBody.transform.GetComponent<CharacterStats>() == target)
{
retVal = true;
}
}
}
Debug.Log ("Lower raycast");
}
if (retVal == false) //so you raycast towards the lower body as your first attempt? Why? Wouldn't the upper body be more likely to be visible?
{
direction += new Vector3 (0, 1.6f, 0); //just to check, is the enemy/player's upper body supposed to be at (0,2.6f,0)?
if (Physics.Raycast (raycastStart, direction, out hitTowardsUpperBody, raycastDistance, excludeLayers))
{
if (target)
{
if (hitTowardsUpperBody.transform == target.transform)
{
if (!target.crouch) //by using a transform instead of a offset, you can have the AI simply to look at where the upper body is, covering both the crouching and not crouching cases
{
retVal = true;
Debug.Log ("upper");
}
}
}
}
}
if (retVal)
{
lastKnowPosition = target.transform.position;
}
return retVal;
}
//could just set forward vector of transform of enemy/player.
public void LookAtTarget(Vector3 positionToLook)
{
Vector3 directionToLookTo = positionToLook - transform.position;
directionToLookTo.y = 0;
float angle = Vector3.Angle (transform.forward, directionToLookTo);
if (angle > 0.1f)
{
targetRot = Quaternion.LookRotation (directionToLookTo);
transform.localRotation = Quaternion.Slerp (transform.localRotation, targetRot, Time.deltaTime * 3);
}
}
}
About the angle thing, I’m not sure but maybe the angle returned by Vector3.Angle is not always positive. Try Mathf.Abs(Vector3.Angle(…))
I can’t run the scene. Please send the whole project, or at least a version where you cut out everything but the stuff needed to test the AI. Alternatively, compile and send the executable. My internet cap is running out, but the game shouldn’t be too big if you export the bare minimum to show the problem.
Sorry about that. I do have an idea though. I suggest using Unity - Scripting API: Debug.DrawRay to see where your raycasts are going. When you play the game you can either view the lines in scene view or set the editor to draw them in the game view too. Start by drawing lines in different colours for your different raycasts. These will show you where the AI is looking. Then when you know that the AI is looking at the right place you can draw more lines for when the AI raycast does hit the player. It is important that you make sure the raycasts are visible long enough. By default they show for one frame. If your AI updates every 0.01 seconds, the ray must be drawn for 0.01f (you set this in the function paramaters, see the docs).
If you are not careful and all your AI are drawing those debug lines at the same time, your game will slow down a lot. So what I suggest is in your AI you have a bool drawDebugRay and whenever your AI script draws the debug line you check that drawDebugRay == true and only draw the line if true. That way you can debug just one AI guy at a time.
Hi, I use DebugDrawRay from the beginning, but it doesn’t help That I redid a bit of the old script, please try to make himself a project. The player is necessary to add CharacterStats player controller. For shelters is necessary to add to do the cube and him to hang CoverBehaviour.)
Unfotunately I’m too busy to recreate the project right now. Your code looks like it’s got the right idea but where do you actually tell the AI to check if it can see anyone? You do a check to see if you can see the current target, but you don’t seem to set the target. The AI should be checking a few times a second to see if it can see the player, then it sets the target and alerts it’s buddies if it spots the player. The AI should keep checking using the same method, at the same interval, whether it has a target yet or not. You seem to only do line of sight checks if the AI has a target.