- Home /
How to make a projectile fire at a moving player.
Hey guys I am extremely new to programming and im having alot of issues with making a projectile fired from a moving boss towards the moving player. What im after is a pathfind solution where the boss fires the projectile where the player is at that point. However in my last build the projectile tracked the player untill it hit him instead of just taking its position when it was fired.
the code we are currently using was written by one of our group members but he is unavailbe to explain it all to me for a few days. I've tried searching other questions, google and the documentation but I dont really understand what hes provided me with.
public class BossProjectileScript : MonoBehaviour {
public Transform target;
public int moveSpeed;
public int rotationSpeed;
private Transform _t;
public float ProjectileSpeed;
private Transform myTransform;
void Awake()
{
myTransform = transform;
}
void Start ()
{
GameObject go = GameObject.FindGameObjectWithTag("Player");
target = go.transform;
}
// Update is called once per frame
void Update ()
{
float amtToMove = ProjectileSpeed * Time.deltaTime;
//transform.Translate(new Vector3 (target.postition) * amtToMove);
Debug.DrawLine(target.position, myTransform.position, Color.yellow);
//Look at Target
myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed * Time.deltaTime);
}
}
That code is some parts of the old code we used on the boss. Which still looks at the player and provides a debug line. However this new code on the Projectile seems to do nothing but move it forward.
As i said im pretty new to programming and this is my first question and im trying to give alot of detail so apologies for the wall of text.
Please edit your post and format your code correctly using the 10101 icon
so you've tried using lerps and/or the Vector3.$$anonymous$$oveTowards. I'm not quite sure, but you could probably make or instantiate an empty GameObject whose distance away from the player is relative to the distance from the player to the boss. that would include a lot of guessing and checking but that's all I can come up with.
Hopefully this helps, but if it doesn't, I hope a more experienced coder comes along and helps you!
well, misspelling "target.postition" might be problematic. try to create that empty GO at the time of firing, and make the boss look at it the whole time. also, ins$$anonymous$$d of using transform.translate, use Vector3.moveTowards, or lerp if you want extremely fast movement. Look both of those up for more info on how to use them. And ins$$anonymous$$d of "myTransform.rotation..." use transform.LookAt or a smooth follow script through inspector.
thanks for the suggestion Herp, I had a go at using lerp. Following the scripting reference http://docs.unity3d.com/Documentation/ScriptReference/Vector3.Lerp.html . Here is what I tried, currently it seems to do nothing as when the projectile is instantiated it just remains still.
public class BossProjectileScript : $$anonymous$$onoBehaviour {
public Transform target;
public GameObject Player;
public float shipx;
public float shipy;
public float shipz;
public Transform start;
public Transform end;
void Start ()
{
GameObject player = GameObject.FindGameObjectWithTag("Player");
end = player.transform;
GameObject UFOPrefab = GameObject.FindGameObjectWithTag("boss");
start = UFOPrefab.transform;
}
// Update is called once per frame
void Update ()
{
transform.position = Vector3.Lerp(start.position, end.position, Time.time);
}
}
Answer by aldonaletto · Aug 15, 2012 at 11:16 AM
Your original script constantly fixes the projectile direction to aim the target - that's why it tracks the player to death. You may reduce the rotationSpeed value, greatly reducing the tracking effect - the projectile will turn to the player slowly, missing the target if it moves fast.
But if you really want to simply fire the projectile in a straight line to the player direction, just aim it at Start and move forward in Update:
public class BossProjectileScript : MonoBehaviour {
public Transform target;
public float ProjectileSpeed = 20;
private Transform myTransform;
void Awake()
{
myTransform = transform;
}
void Start ()
{
GameObject go = GameObject.FindGameObjectWithTag("Player");
target = go.transform;
// rotate the projectile to aim the target:
myTransform.LookAt(target);
}
// Update is called once per frame
void Update ()
{
// distance moved since last frame:
float amtToMove = ProjectileSpeed * Time.deltaTime;
// translate projectile in its forward direction:
myTransform.Translate(Vector3.forward * amtToMove);
}
} NOTE: Anyway, none of above is actually a good solution, because Translate screws up the collision detection system: the projectile should be a rigidbody and receive an initial velocity towards the target, and the only code in its script should be the OnCollisionEnter code, to destroy the projectile and apply damage to the target.
Hey Aldo thanks for the suggestion. when I use the code you provided the projectile is instantiated and moves, but it moves extremely slowly even when i change ProjectileSpeed to 5000. At the rate at which it is moving at the moment it is hard to tell if they are travelling in the right direction, they do seem to change a little as the player moves around but it isn't much. It seems like this might move the projectile to the spot but in a curve where as i was hoping for more of a straight line to wherever the player was.
How would i go about doing a better solution? How would i go about adding a force in a specific direction to a rigid body? something like
rigidbody.AddForce(Vector3.forward * 10);
ins$$anonymous$$d of the current myTransform.Translate?
I suspect that some other script is affecting the projectile movement, since with the code above it should fly at the specified projectileSpeed. Usually the bullet is a rigidbody, and you add force or set its velocity right after it's instantiated in the shooting code - like this:
Rigidbody projPrefab; // drag the projectile prefab here float projectileSpeed = 20;
... Rigidbody projectile = Instantiate(projPrefab, ...) as Rigidbody; projectile.velocity = projectile.transform.forward * projectileSpeed; ... If the projectile prefab has Inspector/Rigidbody/Use Gravity unchecked, the projectile will fly in a straight line towards the player position.
Hey Aldonaletto thanks for telling that transform messes up collision detection, I was wondering why my helicopter moved through land! xD
Tavis, have you tried playing around with the rigidbody's mass and drag? Sometimes that can slow it down.
For some reason i didn't get Aldonaletto's notification until just now. What i did wrong was i was changing the speed in the script, but it wasn't actually changing in the inspector. Just a $$anonymous$$or oversight that stumped me for ages.
The projectiles are working fine now.I put in a Vector3.Distance checker and when the projectile gets too close it stops traveling towards the player and just continues in whatever direction the player was in last( my games a space rail shooter, so its not really following standard physics rules).
Thanks for all your help aldonaletto it really helped me understand a lot of new things.
Answer by turtsmcgurts · Aug 15, 2012 at 11:27 AM
Without your code being properly formatted (and my laziness :3), I decided to just give you the essence of my method. It's in Javascript and will not work out of the box, you will need to give it an object to work with.
var projectileSpeed : float = 20;
var angle = projectile.location - player.location;
projectile.rigidbody.AddForce(angle * projectileSpeed);
This will push your object toward the player at a specified speed. Note this doesn't take bullet drop or anything fancy like that into account.
Not a good idea: the projectile will backfire and kill the shooter! The angle vector is backwards - you should use:
var angle = player.position - projectile.position;
Answer by Dhaiku · Aug 15, 2012 at 11:17 AM
what you do is you make a target for the player transform not for his position then you say to yoyur projectile, go to the place where the player transform is wich is always where the player is
instead of
target = go.transform;
you should do
target = go.transform.position;
this stores the current position of the player, and it won't follow him anymore then in your code, you should replace the target .position, with target (because it now has a transform.position in it, and you can't do transform.position.position)
a position is a Vector3, or a x y and z a transform is something every gameobject has, and its position is a small part of it also note that if you use Transform instead of transform, your code could act weird transform with a small t is the transform of the gameobject linked to the script Transform is some kind of type, like int, float, or boolean you cant say int = 5 but you can say var test : int = 5 same with transform
That's ok, but target should be declared as Vector3:
...
public Vector3 target;
...