- Home /
2D bullet changes direction based on player's world position?
I'm like a lot of people here in that I'm fairly new to Unity. I'm having an issue that I just can't seem to figure out. I've tried a bunch of examples instantiating and moving a projectile in a top down 2d shooter.
My problem is that the projectile will fire in a different direction based on my player's world position. If the player is in a negative x or y axis then the bullet will fire in the reverse direction. If the player is in a positive x or y axis then it will fire as intended. Also, the closed the player is to the center of the world, the projectile fires slower.
I would appreciate any help!
Here is the code:
[code]
public GameObject projectilePrefab;
public float projectileSpeed = 2.0f;
public float projectileLifeSpan = 10.0f;
private Transform myTransform;
private Vector3 shootDirection;
private Vector3 spawnPoint;
private bool isShooting = false;
void Update(){
//set global variables
this.myTransform = transform;
this.spawnPoint = this.myTransform.Find("ProjectileSpawnPoint").position;
//shoot
this.isShooting = (Input.GetButtonDown ("Fire1"));
}
void FixedUpdate () {
//shoot
if (this.isShooting) {
//instantiate projectile at spawn point
GameObject projectile = GameObject.Instantiate (this.projectilePrefab, this.spawnPoint, Quaternion.identity) as GameObject;
//add force to move
projectile.rigidbody.AddForce(this.myTransform.position * this.projectileSpeed, ForceMode.Impulse);
//kill object after delay
Destroy(projectile, this.projectileLifeSpan);
}
}
[/code]
Answer by ben-tmg · Feb 27, 2014 at 05:31 PM
//add force to move
projectile.rigidbody.AddForce(this.myTransform.position * this.projectileSpeed, ForceMode.Impulse);
This line creates force depending on the players position. This means the closer the player is to the origin (0,0,0) the lower the force.
If you always want the bullet to go in the same direction then you need to give it the same Vector. ie If you want it to always travel along positive X you would do:
var xDir = new Vector3(1f, 0f, 0f);
projectile.rigidbody.AddForce(xDir * this.projectileSpeed, ForceMode.Impulse);
You wouldn't want to create the Vector every frame, you would want to create it in Start or Awake and save it.
Also, you don't need to save the variables myTransform and spawnPoint every frame in Update, you only need to do it Start.
Thanks for the reply ben-tmg.
I don't think I can use a vector in that way since the player is constantly moving and rotating. I moved the get on the spawn position into the shooting section so it is only updated when a shooting request in handled.
I guess my question now is really how do I apply uniform force to the projectile (so it doesn't go slower or faster based on position) and that the projectile applies force only in the direction the player is facing at the time the projectile is instantiated.
updated code:
[code]
public GameObject projectilePrefab;
public float projectileSpeed = 2f;
public float projectileLifeSpan = 10f;
private Transform myTransform;
private Vector3 shootDirection;
private Vector3 spawnPoint;
private bool isShooting = false;
void Start(){
//set global variables
this.myTransform = transform;
}
void Update(){
//shoot
this.isShooting = (Input.GetButtonDown ("Fire1"));
}
void FixedUpdate () {
//shoot
if (this.isShooting) {
this.spawnPoint = this.myTransform.Find("ProjectileSpawnPoint").position;
//instantiate projectile at spawn point
GameObject projectile = GameObject.Instantiate (this.projectilePrefab, this.spawnPoint, Quaternion.identity) as GameObject;
//add force to move
projectile.rigidbody.AddForce(this.spawnPoint * this.projectileSpeed, Force$$anonymous$$ode.Impulse);
//kill object after delay
Destroy(projectile, this.projectileLifeSpan);
}
}
[/code]
So it's more of a top down shooter than a side scroller?
You do want to use a vector but you need the correct vector :)
How are you setting the facing of the character? Is it looking at a mouse pointer or are you using a joystick?
What you need to do is find a point the bullet will be going to (say a target crosshair that is controlled by a mouse) and then find the vector that goes from the player to that point. Then you need to normalize the vector so its length is 1. Then you can use it in the bullet code.
So roughly, you want:
//The target gameObject is something you want the bullet to go towards
var targetPoint = someGameObject.Transform.Position.
//Vector from point A to point B is B - A.
var bulletDirection = targetPoint - this.spawnPoint;
bulletDirection.Normalize();
//Fire!!!
projectile.rigidbody.AddForce(bulletDirection * this.projectileSpeed, Force$$anonymous$$ode.Impulse)
etc.
Answer by bergerinc · Feb 28, 2014 at 01:06 AM
Okay. So based on what you suggested and also on this other example I found (http://answers.unity3d.com/questions/591383/fire-at-mouse-position-2d-game.html), here is my latest code. The player shoots at the mouse position all the time exactly as it should. So thanks for your help with that.
However, I want to target mobile devices with this game and I think it will be a lot to do to move the player up/down and left/right as well as target to shoot. I was hoping to just get the position the player was facing and tell the projectile to shoot itself in that direction. Is this something that can be done or am I completely off the reservation here?
[code]
public GameObject prefab;
public float projectileSpeed = 2f;
public float projectileLifeSpan = 10f;
private Transform myTransform;
private Vector3 shootDirection;
private Vector3 spawnPoint;
private bool isShooting = false;
void Start(){
//set global variables
this.myTransform = transform;
}
void Update(){
//check to see if shooting
this.isShooting = (Input.GetButtonDown ("Fire1"));
}
void FixedUpdate () {
//shoot
if (this.isShooting) {
//get mouse position as target
this.shootDirection = Input.mousePosition;
this.shootDirection.z = this.myTransform.position.z - Camera.main.transform.position.z;
this.shootDirection = Camera.main.ScreenToWorldPoint(this.shootDirection);
//rotate
Quaternion q = Quaternion.FromToRotation(Vector3.up, shootDirection - this.myTransform.position);
//create projectile and fire it
GameObject projectile = Instantiate(prefab, this.myTransform.position, q) as GameObject;
projectile.rigidbody2D.AddForce(projectile.transform.up * 500.0f);
//kill projectile after delay
Destroy(projectile,this.projectileLifeSpan);
}
}
[/code]
This is a different question :)
Use the characters 'up' axis (or which ever way it faces in local space) and convert that vector into world coordinates using transform.TransformDirection. You can use that vector ins$$anonymous$$d of the one you calculate from the shootDirection.
Also you shouldn't do the firing in FixedUpdate, that should only be used for physics related updates.
Your answer
Follow this Question
Related Questions
Collision detection for Arrows and Melee. How to properly setup physics/collision? 3 Answers
Bullet reflect not working properly 1 Answer
Increase velocity without changing trajectory 1 Answer
How do I prevent my original projectile object from being destroyed? 1 Answer
Instantiating projectile object is affecting the movement of instantiater 1 Answer