250 lines
8.8 KiB
C#

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
}
}