is a direct line of sight?

Hey

I’m having some trouble scripting my AI. It looks for the nearest cover, finds the closest enemy and fires at it if it is within range, but… it fires into walls obviously because it can’t figure out if there’s an object between it and it’s target. EG, if it has a direct line of sight to it’s target.

How would you go about scripting that? I suspect a RayCast is the solution but whatever I come up with doesn’t seem to work… The RayCasts I produce don’t appear to be responding to colliders at all unless it has a rigidbody attached, which my walls don’t. Just a collider mesh.

Any ideas?

Thanks a lot in advance.

Raycasts always detect colliders; rigidbodies aren’t relevant. It’s 100% reliable…the only time I’ve ever seen it not work is when I messed up the direction (or something else) somehow. However, the most convenient way is to use Linecast between the AI and the target, rather than Raycast.

–Eric

Sorry if I sound daft, I’m new to programming, but as I understand, this should work:

This should draw a line from my guy to his target and if something breaks that line, somethingelse should happen. Right?

I’m making the line visible with the gizmo line drawer and it works. I can see the line in the editor. Yet, the line goes through the wall mesh and still dosomething happens instead of dosomethingelse, as if the wall wasn’t there.

Any ideas as to why?

My wall has a meshcollider attached. Might that be the problem?

Alright, the problem is indeed my collider mesh. When I place random box colliders, the script does work. :S

Try ticking the “Convex” box on the mesh collider? It can give you an oddly shaped collider depending on the shape of the mesh though

Normal mesh colliders work fine with raycasts; just make sure the surface normals are correct because collisions (including raycasts) go through the back side of polygons. Which also means that one-sided walls won’t work, and you’d need to model both sides.

–Eric

Yeah, I managed to fix the problem and the code works fine. Thank you very much!

I don’t really know what the difference between LineCast and RayCast is (interestingly, the latter doesn’t work, the former does), but it works. I’m happy.

Thanks!

Linecast does raycasting between two points, raycast takes a point and a direction (i.e., a ray). Presumably linecast creates a ray from the two points and calls raycast.

–Eric

When doing this, I would take into account the “head” height of the from target to the “chest” height of the end target, If I am correct the transform.position is the base of the target. So if your AI is tucked behind something, he will never shoot because his base is behind something.

Also, if he is kneeling behind cover, his head height should be set to the height at which kneeling shoots. When doing checks:

private var kneelingGunpoint=Vector3(0,0.5,0);
private var chestHeight=Vector3(0,0.75,0);
private var standingGunpoint=Vector3(0,1,0);

if(Physics.Linecast(transform.position + kneelingGunpoint,target.transform.position+chestHeight))
{fire} else {
if(Physics.Linecast(transform.position + standingGunpoint,target.transform.position+chestHeight))
{fire} else {dosomethingelse} 
}

You may also wish to look at if your AI can actually see the target. give some randomness to whether or not he will shoot, knowing that he may or may not hit the target simply because he can’t see him. Of course, this would test to say if the player will stand in the middle of shooting. Kind of a simulation of luck.

There’s a really easy way to get the probability of being seen using the dot product. Subtract the viewer’s position from the target’s to get a heading vector and then normalise that vector. The dot product of that normalised heading with the viewer’s transform.forward vector will give a value that represents the chance of being seen quite realistically (50% chance when 30º either side of a head-on target):-

var heading = (target.transform.position - transform.position).normalized;
var chance = Vector3.Dot(heading, transform.forward);

if (Random.value < chance) {
  // Spotted.
}

OK, I’m testing this same thing. Casting a line from the red sphere to the green sphere to see if it can be “seen”. It is clearly striking the intervening blue sphere (that has a spherical mesh and collider) and yet still outputs “i can see you” in the log, when it clearly should not.

I can move the green sphere anywhere to start, btw, and the message never says “I can NOT see you”.

What am I (again) doing wrong? Why isn’t the blue sphere blocking line of sight?

My goal, btw, is to have any blue sphere block line of sight from red to green.

var redBall : GameObject;
var targetBall : GameObject; // green one

function Update () {
	Debug.DrawLine (redBall.transform.position,targetBall.transform.position, Color.red);
	if (!Physics.Linecast(redBall.transform.position,targetBall.transform.position)) { Debug.Log ("i can NOT see you"); }
	else { Debug.Log ("i can see you"); }
}

P.S. May use Eric’s Vectrosity tool for this, if I tinker much more with it.

if (!Physics.Linecast(redBall.transform.position,targetBall.transform.position)) { Debug.Log (“i can NOT see you”); }

All you are asking here is ‘Did I Not hit something?’, not "Did I hit targetBall’.

what you need is to use an additional RaycastHit struct as an arg to find out WHAT you hit, and not use the !

var hit : RaycastHit;
if (Physics.Linecast(redBall.transform.position,targetBall.transform.position, hit)) { 
 Debug.Log ("i saw something"); 
 if (hit.transform == targetBall.transform) {
  Debug.Log ("i  saw targetBall"); 
 }
} else {
 //this should ordinarily never happen
 Debug.Log ("saw nothing");
}

See the Raycast docs for more complete info than Linecast gives:

Thanks, that’s it.