I need a bit of help with using Raycast Layers in my multiplayer project. The setup is authoritative, so when you fire your gun it sends a message to the server, the server casts a ray to find out what you hit, sends the damage message to that object (still on server side) which calculates damage and then updates the health value across all clients. In the game you control a pirate ship with musketeers standing on the deck. Each of them does the firing when you press the mouse, but I need their raycasts to ignore the ship itself. At first I thought I could just make each ship be in a layer called "unit_mine" on the local machine and be in the "unit_other" layer on everyone else's, but this won't work if I calculate gunshots on the server (which is the best way). How could I make it so the raycast will ignore only the ship on which the musketeer is standing? (preferably without making as many layers as their are players in the game and moving them all to their own layer, unless that's the best way to do it.)
Use RaycastAll, sort the returned hits by distance (maybe they already are?), and use the first one that isn't the ship the shooter belongs to.
you could do a recursive raycast, checking what object you hit, if the object you hit is tagged "Player" e.g. you can recast the ray from that point in the same direction, and it'll return the opposite hit, ignoring your player object. e.g. I created this class to make passive ray casting easier. Code (CSharp): //PassiveRaycast.cs //C# using UnityEngine; public sealed class PassiveRaycast { public readonly Ray ray; //the ray that was cast public readonly float distance; //how far public readonly string ignoreTag; //the tag to ignore public readonly Vector3 hitPoint; //the Vector3 point where the raycast ends public readonly RaycastHit hit; //the RaycastHit object returned from the raycast public readonly PassiveRaycast nextCast; //if we didn't hit anything, this will be the next cast public readonly int steps; //the number of steps it took to get to this raycast public readonly int maxSteps; //the maximum number of steps allowed private bool _hit; //used to convert this class to bool conditional, set by the Raycast function public PassiveRaycast endCast {//gets the last cast in this rayCast get {//WARNING: this is recursive, if maxSteps is set too high, this will cause a stack overflow exception if (nextCast != null) { return nextCast.endCast; } return this; } } public PassiveRaycast(Ray ray, string ignoreTag, int maxSteps = 5, float distance = float.PositiveInfinity, int steps = 0) {//creates a passive raycast, ignoring the tag defined by ignoreTag this.ray = ray; //store the ray this.distance = distance; //store the distance this.ignoreTag = ignoreTag; //store the tag to be ignored this.steps = steps; //store the steps this.maxSteps = maxSteps; //store the maxSteps _hit = Physics.Raycast(ray, out hit, distance); //perform the raycast if (_hit) {//we hit something if (hit.transform.tag == ignoreTag) {//the tag is to be ignored if (steps < maxSteps) {//we're safe from overflow hitPoint = hit.point; //set the hitPoint to where the raycast ended //perform recursive raycast nextCast = new PassiveRaycast(ray, ignoreTag, maxSteps, distance, steps + 1); } else {//we can't do anymore raycasts hitPoint = ray.origin + (ray.direction * distance); //set the hitPoint to where the raycast ended } } } else {//we hit nothing hitPoint = ray.origin + (ray.direction * distance); //set the hitPoint to where the raycast ended } } public static implicit operator bool(PassiveRaycast pr) {//allows you to do if(PassiveRaycast) { We hit something! } return pr._hit; } public void DrawDebug(Color startColor, Color endColor) {//renders the entire raycast from start to finish Color color = Color.Lerp(startColor, endColor, steps / (float)maxSteps); Debug.DrawLine(ray.origin, ray.origin + (ray.direction * distance), color); //WARNING: this is recursive, if maxSteps is set too high, this will cause a stack overflow exception if (nextCast != null) { nextCast.DrawDebug(startColor, endColor); } } } Example use is: Code (CSharp): //PassiveRayTest.cs //C# using UnityEngine; using System.Collections; public class PassiveRayTest : MonoBehaviour { public bool test = false; private PassiveRaycast raycast; void OnValidate() {//this works in the editor, simply check the test checkbox if (test) { //new PassiveRaycast(Ray ray, string ignoreTag, int maxSteps = 5, float distance = float.PositiveInfinity, int steps = 0); raycast = new PassiveRaycast(new Ray(transform.position, transform.forward), "Player"); PassiveRaycast endcast = raycast.endCast; if (endcast) {//we hit something Debug.Log("hit: "+endcast.hit.transform.name); if (raycast) {//we hit something, but ignored it Debug.Log("ignored: "+raycast.hit.transform.name); raycast = raycast.nextCast; while (raycast != null) { if (raycast && raycast != endcast) {//we hit something, but ignored it Debug.Log("ignored: "+raycast.hit.transform.name); } raycast = raycast.nextCast; } } } else {//we hit nothing if (raycast) {//we hit something, but ignored it Debug.Log("ignored: "+raycast.hit.transform.name); raycast = raycast.nextCast; while (raycast != null) { if (raycast) {//we hit something, but ignored it Debug.Log("ignored: "+raycast.hit.transform.name); } raycast = raycast.nextCast; } } else { Debug.Log("no hit!"); } } test = false; } } void Update() {//draw the whole raycast raycast.DrawDebug(Color.green, Color.red); } } I hope this helps!
@TwixEmma, Wow, what a robust solution! I'll have to add this to my scripting library. Thanks a bunch!