How to control rocket pathing with Quaternion.Slerp
So I currently have code that shoots a rocket from the player location to a target position. The intention is to have a nice straight arc where the rocket goes up and then arcs and comes down. When the player is shooting the rocket in the +z direction, the path for the rocket is fine. When I shot in the -Z direction or from side the side, the rocket starts to take really weird paths (i.e. sweeps to the sides really far ) and doesnt have the trajectory I am looking for. I am using Quaternion.Slerp and don't really understand how it works. I've tried looking in to using a bezier curve implementation but it just doesnt have the missile shooting feel that I am looking for .
Question is...is there a way to contain a Quaternion.Slerp to a plane ( I'd like the rocket to travel in an arc along a plane that is straight up and down and passes through the player and target points.
I use pretty standard missile homing code in the missileTracking() function. Any suggestions or recommendations for how to get the intended behavior would be much appreciated. TYTY
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using VRTK;
// try moving along bezier curve that creates a middle control point using the plane equation.
public class MissileMove : MonoBehaviour {
private int j;
[HideInInspector] public Vector3 target;
private Rigidbody missileRB;
private float deploymentTime;
private float deployHeight =.005f;
private float deploySpeed =3f;
private float turnTime;
private float velocity=2;
private float torque;
List<Transform> missileChildren = new List<Transform>();
List<Vector3> childrenAngles = new List<Vector3>();
private Vector3 targetAngle = new Vector3(-90f, 0f, 0f);
private bool missileFiring = false;
void OnEnable()
{
j = Random.Range(0, 4);
missileRB = GetComponent<Rigidbody>();
}
// Use this for initialization
void Start ()
{
deploymentTime = Time.time;
torque = torqueGetter();
int children = transform.childCount;
for (int i = 0; i < children; ++i)
{
missileChildren.Add(transform.GetChild(i));
childrenAngles.Add(transform.eulerAngles);
}
}
void OnDisable()
{
this.gameObject.GetComponent<missileExplosion>().enabled = true;
}
// Update is called once per frame
void Update ()
{
if (!missileFiring)
{
foreach(Transform child in missileChildren)
{
child.transform.rotation = Quaternion.Slerp(child.transform.rotation, Quaternion.Euler(new Vector3(-90f,0f,0f)), ((Time.time - deploymentTime)/5.0f)-.25f);
}
}
if (!missileFiring)
{
StartCoroutine(MissileDeploy());
}
if (missileFiring)
{
MissileTracking();
foreach(Transform child in missileChildren)
{
child.transform.localRotation = Quaternion.Euler(new Vector3(0f, 0f, 0f));
}
}
}
IEnumerator MissileDeploy()
{
if (Time.time - deploymentTime < 1.2)
{
transform.Translate(Vector3.forward * deployHeight * Mathf.Sin(deploySpeed * (Time.time - deploymentTime)));
}
if(Time.time-deploymentTime>1.2)
{
missileRB.velocity = Vector3.down* .08f;
yield return new WaitForSeconds(1.5f);
missileFiring = true;
missileRB.GetComponent<Collider>().enabled = true;
}
}
void MissileTracking()
{
turnTime += (Time.deltaTime * (1/torque));
if (target == null || missileRB == null)
{
return;
}
velocity += Time.deltaTime;
missileRB.velocity =.5f* velocity*velocity * missileRB.transform.forward;
Vector3 lookPos = target - transform.position;
Quaternion rotation = Quaternion.LookRotation(lookPos);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, turnTime);
}
float torqueGetter()
{
float dist = Vector3.Distance(target, transform.position);
if (dist > 1f)
{
return dist * 5f;
}
else
{
return dist * dist * 5f;
}
}
void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Floor"))
{
Vector3 position = this.gameObject.transform.position;
position.y = .65f;
this.gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
this.gameObject.transform.position = position;
this.gameObject.GetComponent<missileExplosion>().enabled = true;
}
}
}
Answer by conman79 · Oct 08, 2016 at 10:38 PM
The problem is because you're rotating to the world space rotation new Vector3(-90f,0f,0f), when you only want to rotate on the local x axis.
On line 65, to isolate the rotation to the x axis, change your code like this::
child.transform.rotation = Quaternion.Slerp(child.transform.rotation, Quaternion.Euler(-90f, transform.localEulerAngles.y, transform.localEulerAngles.z), ((Time.time - deploymentTime)/5.0f)-.25f);
That is actually not the part of the code that is giving me trouble. The part of the code you are referring to controls the wings on the missile co$$anonymous$$g down after the rocket deploys (it was a work around because I couldn't figure out the animator). It is working as I intended.
The code that is giving me trouble is in lines 103-114. Thank you!
I can't see anything wrong with the rotation code in lines 112-114, I even tested it in a quick Unity project and it worked fine. There's probably something somewhere else in the code causing issues but I can't figure it out right now. The problem screams local vs. world rotations/positions though.
If you could upload a sample project somewhere I could take a look.
With that being said, your suggestion solved another problem that I was having ( namely the one that you were addressing) in a much more elegant way than the way that I was solving it. $$anonymous$$akes it look cleaner and better. Thank you!
Your answer
Follow this Question
Related Questions
How to Slerp / Lerp Rotation on a Single Axis? 0 Answers
Slerp rotation issue when calling a lot 0 Answers
Rotate on Transform.localeulerAngels smoothly 0 Answers
Lerp going crazy when negative 1 Answer