using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; [Serializable] public class Rocket : MonoBehaviour { public float lag; public Transform explosion; public Vehicle launchVehicle; public Vehicle targetVehicle; public int speedX; public string laserID; private Vector3 strtPos; private int stage = -1; public LayerMask mask = -1; public LayerMask maskOpt = -1; public IEnumerator Start() { //Init name = "lsr#" + laserID; float velocity = Game.Settings.laserSpeed * speedX + Mathf.Max( 0, launchVehicle.transform.InverseTransformDirection( launchVehicle.velocity).z * (targetVehicle ? 1 : Vector3.Dot( transform.forward, launchVehicle.transform.forward))); //AutoTargeting if (targetVehicle) { Vector3 bgn = transform.position; Vector3 pos; Vector3 vel; Vector3 accel; if (targetVehicle.networkView.isMine) //Local vehicle, high precision { Vector3 refvel = targetVehicle.gameObject.rigidbody.velocity; float reftme = Time.time; yield return new WaitForSeconds(Time.fixedDeltaTime * 0.5f); //Allow target to move so we can analyze it's acceleration pos = targetVehicle.transform.position; vel = targetVehicle.gameObject.rigidbody.velocity; accel = (vel - refvel) / (Time.time - reftme); ////Accelleration over 1 second } else //Remote vehicle, just make it look good { Vector3 refpos = targetVehicle.transform.position; float reftme = Time.time; yield return new WaitForSeconds(Time.fixedDeltaTime * 0.5f); //Allow target to move so we can analyze it's velocity Vector3 refvel = (targetVehicle.transform.position - refpos) / (Time.time - reftme); //velocity over 1 second refpos = targetVehicle.transform.position; reftme = Time.time; yield return new WaitForSeconds(Time.fixedDeltaTime * 0.5f); //Allow target to move so we can analyze it's acceleration pos = targetVehicle.transform.position; vel = (targetVehicle.transform.position - refpos) / (Time.time - reftme); //velocity over 1 second accel = (vel - refvel) / (Time.time - reftme); //Accelleration over 1 second } float dur = 0f; while (true) { pos += vel * Time.fixedDeltaTime; vel += accel * Time.fixedDeltaTime; dur += Time.fixedDeltaTime; if ( dur > 10 || Vector3.Distance(bgn, pos) < dur * velocity) { break; } transform.LookAt(pos); } } //Lag Compensation //Unnecessary when autotargeting, as hits are calculated on target client else if (lag > 0f) { rigidbody.position += rigidbody.transform.TransformDirection( 0f, 0f, velocity * lag); //Position extrapolation for non authoratative firing instances } //Begin Run rigidbody.velocity = rigidbody.transform.TransformDirection( 0f, 0f, velocity); strtPos = rigidbody.position; stage = 0; //Cleanup yield return new WaitForSeconds(Mathf.Lerp( 13f, 5f, Game.Settings.laserSpeed * speedX * 0.003f)); Destroy(gameObject); } public void FixedUpdate() { if (stage != 0 || !launchVehicle || !Game.Settings) { return; } if (Game.Settings.laserGrav != 0f) { Vector3 rigvel = rigidbody.velocity; rigvel.y -= Game.Settings.laserGrav * (float)speedX * Time.deltaTime * 20f; rigidbody.velocity = rigvel; } Vector3 vector = transform.position - strtPos; RaycastHit[] hits = Physics.RaycastAll( strtPos, vector, vector.magnitude, (Game.Settings.lasersOptHit) ? maskOpt : mask); for (int i = 0; i < hits.Length; i++) { RaycastHit collision = hits[i]; //Launch vehicle is immune to hits if (collision.collider.transform.root.gameObject == launchVehicle.gameObject) { continue; } //Non-authoratative game instances DO NOT detect vehicle laser hits. Hits are detected on authoratative instance, and then broadcast to other clients with lH RPC if ( ((targetVehicle && !targetVehicle.networkView.isMine) || (!targetVehicle && !launchVehicle.networkView.isMine)) && collision.rigidbody) { continue; } //We are the instance if this laser on the firer's computer, & we tagged another vehicle if ( ((targetVehicle && targetVehicle.networkView.isMine) || (!targetVehicle && launchVehicle.networkView.isMine)) && collision.rigidbody) { Vehicle veh = (Vehicle)collision.transform.root.gameObject.GetComponent(typeof(Vehicle)); if (veh && veh.isResponding) { //Determine where we hit them veh.gameObject.networkView.RPC( "lH", RPCMode.Others, laserID, collision.transform.InverseTransformDirection(collision.point)); //We are quarry, and made a tag if ( launchVehicle.isIt == 1 && (Time.time - veh.lastTag) > 3f) { launchVehicle.gameObject.networkView.RPC( "iS", RPCMode.All, veh.gameObject.name); veh.lastTag = Time.time; } //They were quarry, and we tagged them else if ( veh.isIt == 1 && (Time.time - launchVehicle.lastTag) > 3 && (Time.time - veh.lastTag) > 3) { launchVehicle.gameObject.networkView.RPC( "sQ", RPCMode.All, 2); } //They weren't quarry, and we weren't supposed to shoot them else if ( veh.isIt == 0 && launchVehicle.isIt == 0) { launchVehicle.gameObject.networkView.RPC( "dS", RPCMode.All, veh.gameObject.name); } } } if ((bool)collision.rigidbody || Game.Settings.laserRico == 0f) { laserHit( collision.transform.root.gameObject, collision.point, collision.normal); } else { rigidbody.position = collision.point; rigidbody.velocity = Game.Settings.laserRico * Vector3.Lerp( Vector3.Scale( rigidbody.velocity, collision.normal), Vector3.Reflect( rigidbody.velocity, collision.normal), Game.Settings.laserRico); } } strtPos = rigidbody.position; } public void laserHit(GameObject go, Vector3 pos, Vector3 norm) { stage = 1; rigidbody.position = pos; rigidbody.velocity = Vector3.zero; go.BroadcastMessage( "OnLaserHit", launchVehicle.networkView.isMine, SendMessageOptions.DontRequireReceiver); Collider[] colliders = Physics.OverlapSphere(pos, 10f); foreach (Collider hit in colliders) { if (hit.attachedRigidbody) { hit.attachedRigidbody.AddExplosionForce( 350f + speedX * 300f, pos, 1f, 2f); } } Instantiate( explosion, pos, Quaternion.FromToRotation(Vector3.up, norm)); //transform.rotation } }