- Home /
Not so much a scripting problem - Just need smart peoples' help.
In designing a sort of flight combat game, I am needing to fire (Instantiate prefab, and move/target with separate script on prefab) a shot, which in the first frame, does a "Lookat Target" and moves forward after that..... I am getting the velocity.magnitude of the enemy ships rigidbody, and the distance between the player and the enemy, to calculate for how far ahead of the enemy ships' transform to set as the target, as in, "compensating for the fact that both the enemy and projectile are in motion".
What I have, is doing what I want - It's a formula that gives a smaller output ,targeting closer to the enemies' position, the closer the player is to the enemy when firing - and a larger output, targeting further ahead of the enemy position, the higher that ships' rigidbody.velocity.magnitude is.
Here is the code:
using UnityEngine;
using System.Collections;
public class shotmover : MonoBehaviour {
public float speed;
public bool hasTarget;
public Transform target;
public Player player;
public Vector3 targetahead;
// Use this for initialization
void Start () {
player = GameObject.FindWithTag ("Player").GetComponent <Player> ();
Destroyshot ();
//Find out of the player has a target
hasTarget = player.seesTarget;
//If they do,
if (hasTarget) {
//Store that object
target = player.locktarget;
/*add to targetahead, forward from the enemy, higher the further you are from the target, divided by 100 because i am just dumb, and higher based on the velocity of the enemy ship.*/
targetahead += target.position + target.forward * (((Vector3.Distance(transform.position, target.position)) / 100) * (1+player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude));
transform.LookAt (targetahead);
Debug.Log ("target velocity:" + player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude.ToString ());
}
}
void Update () {
gameObject.transform.Translate (Vector3.forward * speed);
if (hasTarget) {
Debug.DrawLine (gameObject.transform.position, targetahead);
Debug.DrawLine (target.transform.position, targetahead);
}
}
void Destroyshot(){
Destroy (gameObject, 2f);
}
}
In my little formula there, I am diving by 100 because the player will only target things about 100 units away. And I knew that the velocity output would average out around 1.So I was just kind of spitballing from debug logs!
Here is an image of how that is working:
http://i.imgur.com/khWH49D.png
The help that I need is this: What would be the most accurate way, or even a more accurate way, of calculating targetahead? I drew a little triangle at the bottom of that image, to represent the situation, and the Pythagorean theorem popped into my head. But I can't quite put anything together that cohesively grabs the right values for something like that. Any ideas, Pythagorean or otherwise?
With some help from a math-guy somewhere else, I know now I need the speed and trajectory of the enemy object, then I need the speed of my projectile and the angle of the shot, If say the distance between you and the enemy is 1000 along the x axis and 200 meters along the y axis (so the distance is √(1000^2 + 200^2), and you are stationary ( I won't be most of the time, but the speed of the projectile actually won't scale off of my speed, but a fixed speed) and the enemy is moving towards me on the x axis at 10 meters/second while staying at the same height, and the speed of your projectile is 300meters/second then you can put it in a formula: √(1000(-10s)^2+200^2) = 300s solving s in this problem gives you the flight time of your projectile from launch to impact. now that you know this flight time you multiply it with the speed of the enemy object to acquire a distance in meters, this gives you the lead on your target.
His method seems to exclude Y axis calculations but I 'm trying to image, myself, how to simplify his method. I know I can get the distance (his 1000 /200) with a Vector3.Distance. I know I can grab or calculate for the speed of my projectile per x number of frames because my projectile moves forward a fixed amount every frame.).
FURTHER$$anonymous$$ORE, I feel I can ignore whether or not the enemy is moving towards me, as with my camera work, the more directly an enemy is moving towards or away from me, the less spread chance there is for the shot to miss, as either way it would be targeting for "in front of the enemy path", disregarding my relative angle during that calculation, which is intended for simplicity.
How, now, can I apply his formula in C#, I wonder , Where to grab which values from what and where to plug them into?
Please, any help is appreciated
yeah, you need math.
can you briefly say the fixed things you have, and what you're trying to calculate ?
it sounds like you have a target that's moving along some parabolic path, and you'd like to know the angle and velocity to fire a projectile at so that its parabolic path intersects the target ? and this is all in 3D ? is it right to say the paths are parabolic, versus straight lines ?
well, no, i'm intendending to fire the projectile towards the enemy + plus the enemy's forward transform relative to its current rotation , which it is always moving forward relative to, but changing every so often with its AI.
so, my goal is just to calculate that vector to fire in, as if we were assu$$anonymous$$g the enemy is traveling in a straight line with velocity magnitude 1.0, i would like to scale appropriately how far forward to plan for based on that magnitude while also calculating for the distance between the ship and the enemy, ie compensating for travel time on both the target and projectile.
Answer by elenzil · Jan 13, 2017 at 12:40 AM
THAN$$anonymous$$ YOU SO $$anonymous$$UCH. Going to play with it now.
How might I ring this effect up in a 3d worldspace?
Or does it not matter, since we're only dealing with one plane of calculations either way?
I understand the last part would be written roughly like this,
Projectile velocity = [Target position - Projectile position + Target velocity * time of collision] / collision time
Or, shot.rb.velocity = [ target.position - shot.position + target.rb.velocity * time of collision....
The time part, I do not get. I understand the importance of the variable but Please tell me, How would "time of collision" be implemented in the actual code ?
Furthermore, I see what you seem to be solving for is ultimately what I need to set the speed of the projectile to? I need a position vector to plug in, my projectile, and every projectile I fire, will have the same speed / velocity, every time.
speed and velocity are not the same thing.
velocity is a vector, which has both length and direction. speed is just a scalar, ie a single value.
the code i provided takes these inputs:
the position of the target
the velocity (vector) of the target
the position of the projectile at the beginning (or you could think of this as the position of the cannon)
the speed of the projectile
and it outputs: * whether or not it's possible for the projectile to hit the target
if it is possible, the velocity (vector) the projectile should use in order to hit the target. the length of this vector will be equal to the projectile's speed.
the routine i wrote takes care of the time variable internally.
re 3d vs 2d, the code is 3d. if your situation is 2d, that's fine too, the 3d code will work.
also, your demo is missing a lot of things, and is not playable.
hm, that doesn't sound right. can you be specific ?
exported to HT$$anonymous$$L: https://elenzil.github.io/unityUtils
that is so friggin awesome sir. i am going to try very hard to implement this into my game, even though i still only half understand the script / math.
if i sent you a project with the stuff im trying to apply it to, could you help me?
Thank you a bunch. I can't seem to figure out how to turn the calculations considering the canvas scale etc into the ones I need (distance during start frame etc)....and the target as gameobjects targetable by my player etc....Help me out?
Answer by Thomas-Hawk · Jan 14, 2017 at 09:17 PM
here is what I am ending up using
showme2 = (Vector3.Distance (transform.position, target.position));
//targetahead += target.position + target.forward * (((Vector3.Distance(transform.position, target.position)) / 100) * (player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude));
targetahead += target.position + (target.GetComponent<Rigidbody>().velocity) + player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity/showme2*(Mathf.Sqrt((Mathf.Sqrt(showme2)/speed) * (Mathf.Pow(Mathf.Sqrt(player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude), rb.velocity.magnitude)+Mathf.Pow(showme2, Mathf.Sqrt(showme))-Mathf.Sqrt(showme)+Mathf.Sqrt(player.locktarget.GetComponent<Rigidbody>().velocity.magnitude))));
//targetahead += target.position - player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity * (Mathf.Sqrt((Mathf.Sqrt(showme2)) * (Mathf.Pow(player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude, rb.velocity.magnitude)+Mathf.Pow(showme2, Mathf.Sqrt(showme))+Mathf.Sqrt(showme)+Mathf.Sqrt(player.locktarget.GetComponent<Rigidbody>().velocity.sqrMagnitude))));
transform.LookAt (targetahead);
Debug.Log ("Target velocity:" + player.locktarget.gameObject.GetComponent<Rigidbody> ().velocity.magnitude.ToString ());
showme = (Vector3.Distance(targetahead, target.position));
Here is a playable demo of that in action. http://tomahawkhomepage.x10host.com/newdemo/
WASD R SPACE