Anyone want to provide a sample of a script that I can attach to a game object that does a simple line of sight raycast in all directions to see if it’s able to “see” other game objects that are tagged “blueteam”? Objects in the scene tagged “losblock” block the raycast.
Terrain must also block LOS.
I know it’s simple but I’ve spent two hours now struggling with it. Grrr.
Perhaps you could narrow down what you mean by all directions - are all the blueteam objects walking at the same ground level as the raycasting object? Since it’s a line of sight test, should the rays only be cast forward from the object? Casting rays in many different directions to see if any of them hit something interesting is likely to be a big drain on performance. It might be possible to get the result you are looking for in a more efficient way.
Testing using a raycast for line of sight along the horizontal plane. But facing doesn’t come into play … it has to be in a circle around a game object. Or a single line but that would pivot around the object’s centre like a continually sweeping weather radar beam every two seconds or so, if that’s less of a performance hit.
There will only be 20-25 game objects (max) on the board checking line of sight.
I can then format the check, if it returns true, into an “if” statement.
PS. Basically a “line of sight” system checks if a single currently active piece (one of the ten) can see any of the (approximately 10) “enemy” pieces.
I think Eric is on the right lines (no pun intended) here. However, a single linecast to each blueteam object will only detect if there is a line of sight to the object’s centre. Unless the blueteam objects are very small, it would work better if you cast another two rays, slightly to each side of the centre - this will help create the impression of the object being partly visible.
Die valiantly I guess. Here’s the code I am using … I always get the “I can see you!” message regardless of terrain blocking or other objects in the way.
// LOS checking for all pieces on board
// define all of the pieces in the game
var redA : GameObject;
var redB : GameObject;
var blueA : GameObject;
// define the message box to throw the message into
var statusChanged : GUIText;
function Update () {
// check LOS from the currently active piece to all blue pieces here
// in our case, we're checking for all pieces using a brute force method
if (Physics.Linecast (redA.transform.position, blueA.transform.position) || Physics.Linecast (redB.transform.position, blueA.transform.position)) {
// post message
statusChanged.text = "I can see you!!";
}
// hide the status message if not in line of sight
if (!Physics.Linecast (redA.transform.position, blueA.transform.position) !Physics.Linecast (redB.transform.position, blueA.transform.position)) {
// stop movement
// post message
statusChanged.text = "Nothing visible right now.";
}
}
This is attached to a SceneManager GO and all the connections are made correctly in the Inspector Pane.
For an object to be detected by a raycast, it needs to have a collider and (I think) also a rigidbody. Also, make sure the terrain isn’t in the Ignore Raycast layer - I doubt it would be but, you know…
No, only a collider. Otherwise none of the OnMouseDown/Over/Etc functions would work unless you attached rigidbodies to everything, which would be a bit silly.
As the docs say, Linecast returns true if there’s a collider between the two points; you seem to be doing it the other way around. Keep in mind that, if there are colliders attached to the objects whose positions you’re linecasting between, the linecast will also return true. Easiest thing is to put the character/enemy colliders on the IgnoreRaycast layer; this can be done temporarily if you need them to be on other layers normally. Or else do some math so that the linecast is outside the player/enemy colliders, or else use the layermask variable to ignore certain layers. And yes, the terrain is detected because it uses a collider (a heightmap collider to be precise).
To test, start with something basic so that you can see that it’s working, and then add more logic on top of that until it’s doing what you want. Something like:
var ob1 : Transform;
var ob2 : Transform;
private var hit : RaycastHit;
function Update () {
if (Physics.Linecast(ob1.position, ob2.position, hit)) {
print ("Blocked by " + hit.collider.name);
}
else {
print ("Clear skies between " + ob1.name + " and " + ob2.name);
}
}
The raycasting functions have an optional layer mask parameter that you can use to filter out particular layers on a given call. Say, for example, you want to ignore the player’s collider for a raycast originating from the player’s position. You can set a layer mask to detect all layers except the player’s and pass that to Physics.Raycast. This technique still doesn’t solve all layer problems but it gives you a bit of extra flexibility.
You know, Andeee, I was going to post my solution here, and I just hadn’t gotten 'round to it!
I did find the layer mask option but it wasn’t working for me, as I needed it for other purposes and didn’t want to ignore ALL objects on that layer.
With some pointers from Neil Carter on IRC, I came up with this:
var targetTransform : Transform;
var playerTransform : Transform;
// Check LINE OF SIGHT (Part of a larger method)
var targetGameObject = targetTransform.gameObject;
var savedLayer : int = targetGameObject.layer;
targetGameObject.layer = 2;
Debug.DrawLine (playerTransform.position, targetTransform.position, Color.red);
if (Physics.Linecast(playerTransform.position, targetTransform.position, hit)) {
messageController.Message ("Target Blocked by " + hit.collider.name);
targetGameObject.layer = savedLayer;
return (false);
} else {
Debug.Log ("Clear LOS between the Player and " + targetTransform.name);
targetGameObject.layer = savedLayer;
}
This momentarily changes the target’s layermask to the ignoreraycast layer, checks it, then sets it back. There is the small chance that this could cause problems, but as this is done nearly immediately in the same function/method, it should be relatively safe.