- Home /
AngryBots bullet spawner - Some help to convert to use Rigidbodies?
I'd like to make use of the bullet pool spawning system used in Angry Bots which keeps a pool of bullet objects in the scene for instant use. The system uses translation to move the bullets however which isn't right for the game I'm working on. So I would like to instead make it use Rigidbodies and move the bullets using AddForce().
I've tried firing the bullet from various places, in both the Spawnng script and the Destroying but the results seem to vary. For instance, the bullets either speed up as I'm firing, or the system won't recycle them correctly.
There are 2 brief scripts which are shown below. One Spawns the bullets and the other fires them (using translation) and them destroys them after a specified time. They have been converted to C# from the original JS in AngryBots with only the relevant sections shown.
Any help would be great - Thanks.
SimpleLaser
using UnityEngine;
using System.Collections;
public class SimpleLaser : MonoBehaviour
{
public Vector3 Direction = Vector3.zero;
public float lifeTime = 2f;
private float spawnTime = 0.0f;
public bool destroyForMe = false;
public float ShotForce;
public void OnEnable()
{
Debug.LogWarning("OnEnable");
// The time this object spawned
spawnTime = Time.time;
gameObject.rigidbody.velocity = Vector3.zero;
gameObject.rigidbody.angularVelocity = Vector3.zero;
// This is the force being added.
gameObject.rigidbody.AddForce(Direction * ShotForce);
}
void Update()
{
if (Time.time > spawnTime + lifeTime) // ||dist < 0)
{
Debug.LogWarning("Spawner.Destroy(gameObject)");
Spawner.Destroy(gameObject);
}
}
}
EnemyBehaviour
public IEnumerator DoFireAnim()
{
// Causes the coroutine to repeat
while (true)
{
Enemy_Anim_obj.animation[roll.name].speed = 2;
Enemy_Anim_obj.animation.CrossFade(roll.name, 0.2f);
yield return new WaitForSeconds(RollTime);
Enemy_Anim_obj.animation.Stop(roll.name);
Enemy_Anim_obj.animation[open.name].speed = 2;
Enemy_Anim_obj.animation.CrossFade(open.name, 0.2f);
if (Enemy_Anim_obj.animation.IsPlaying(open.name))
{
// Wait
}
else
Enemy_Anim_objEnemy_Anim_obj.animation.CrossFade(idle.name, 0.2f);
yield return new WaitForSeconds(0.3f);
shootingFlag = true;
Debug.Log("Called Shoot()");
// Enough time to fire bullets
yield return new WaitForSeconds(0.6f);
Enemy_Anim_obj.animation.CrossFade(close.name, 0.2f);
}
}
//--------------------------------------------------------
void FixedUpdate()
{
if (shootingFlag)
{
Debug.LogWarning("SHOOTING");
GameObject newLaserProjectile_L = Spawner.Spawn(LaserProjectile,
Left_gun.position,
Left_gun.rotation) as GameObject;
Vector3 L_GunBulletDir = playerTarget_obj.transform.position - Left_gun.transform.position;
newLaserProjectile_L.transform.rotation = Quaternion.LookRotation(L_GunBulletDir);
newLaserProjectile_L.GetComponent<SimpleLaser>().Direction = L_GunBulletDir;
newLaserProjectile_L.GetComponent<SimpleLaser>().OnEnable();
shootingFlag = false;
}
}
It would be easier to write a specific system that handles the bullets for your specific reason, rather than using angryBots's
Answer by Ellandar · Feb 21, 2013 at 02:47 PM
I haven't actually looked at angryBots so I'll just go by what I'm thinking.
If you are going to fire bullets using force instead of controlling it's position, you'll need to approach the problem slightly differently.
Instead of fireing the bullet, and then maintaining it's trajectory/speed within an Update() like the "Fireing and Destroying" scripts seems to do in your example, you probably should create your own script to control the bullet.
Create a script, add it to your bullets. You may want to pass in some variables (direction?). The moment you enable the bullet, it will fire itself straight forward if you don't change anything.
public void OnEnable()
{
spawnTime = Time.time; //time this object spawned
Vector3 direction = gameObject.rigidbody.forward; //direction to shoot, modify at will
float forceToApply = 25; // higher number = faster travelling bullet.
gameObject.rigidbody.AddForce(direction * forceToApply ) // This is the force being added.
}
public void Update()
{
// Some code in here to track time and to relocate the bullet to your pool when timeout occurs.
}
Notes: If you move a rigidbody by relocating it's position you should also stop it first:
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
If you move your bullet too fast, it may travel through any colliders you want it to hit before the game has a chance to trigger the collision.
Let me know if you want more info, I'll see what I can come up with.
Sources: http://docs.unity3d.com/Documentation/ScriptReference/Rigidbody.AddForce.html
Hi Ellandar and thanks for the help.
I've implemented the method you've suggested and it looks like the pooling doesn't work. The projectiles are being destroyed very quickly even though I have the lifeTime set to 2 seconds. I have also disabled any collision scripts to eli$$anonymous$$ate them being destroyed by other things.
The way the code works is that I have a coroutine which is first called by a trigger that the Player enters (for proximity to the enemy) - this is called only once. The coroutine carries out an enemy's animations and then sets a boolean (called shootingFlag) to true. This causes the statements in FixedUpdate to execute. FixedUpdate Instantiates the projectile and sets its direction.
It then passes the direction the bullet should travel in to SimpleLaser and then calls its OnEnable() function. I was initially passing the direction as a parameter to OnEnable by received an error a couple of times so am now setting it but using the global variable Direction ins$$anonymous$$d.
I have set the the cache size on the object in the Inspector to 4, but have tried larger values with no change in behaviour.
Please see above for the updated code.
Thanks again
G'day Bilbo,
Caught me at work at the moment, so not a lot of time to look at this. A couple of initial things that might help you on the path:
Add Debug.Log(this.name +" has been alive: " +(spawnTime + lifeTime) to your SimpleLaser's Update() just before the destroy in the if statement. That'll probably help with debugging a bit, especially if you are na$$anonymous$$g your bullets along the limes of bullet_1, bullet_2, etc.
Just before: "shootingFlag = True;" add another Debug.Log(newLaserProjectile_L.name +" was just spawned at: "+Time.time);
That should allow you to see the real time passed between spawn and destroy, especially helped if each of your bullets/lasers are named numerically.
Once I get home in 3 1/2 hours I'll sit down and take a proper look at the code (if no one else has chimed in and sorted it by then).
Ell.
From what I can see, your code should work. The only thing I can think of is that your spawner is not in fact spawning a new laser/bullet, but reusing the one that's on the screen somehow? Thus resetting it before it gets a chance to actually travel anywhere?
Ell
Excellent, so the Console output has helped to show me what's going on now :)
Basically when I completely turn off the collider on the projectile, the pooling works O$$anonymous$$ - so I can deal with that later.
I've attached an image of the Console output. One thing that's a little concerning is that OnEnable is being called twice for every projectile instantiation. Now, although the pooling works, the force that its fired at starts off slow (for about 4 shots or so) and then speeds up and pla$$anonymous$$us at a faster speed. Not sure what would be causing this, as I've set both the velocity and angular velocity of the projectile to 0 each time before firing.
Thanks for the help
$$anonymous$$eeting got canceled, yay. Ok, the way force works is it's added (using Force) over time usually. If we change to one of the alternative methods (http://docs.unity3d.com/Documentation/ScriptReference/Force$$anonymous$$ode.html) we can probably fix that.
I'd probably use VelocityChange in s$$anonymous$$d of Force, as this is an instant application of force and it ignores the mass value (so it'll go really fast, quickly). It's applied as a function of distance/time, in this case units per second i'd say (u/s). Short version here is, higher number = faster.
Start with:
gameObject.rigidbody.AddForce(Direction * ShotForce,Force$$anonymous$$ode.VelocityChange);
and see how it goes.
Your answer
Follow this Question
Related Questions
Why does the bullet has wrong direction? 1 Answer
A question about the Angry Bots demo. 0 Answers
AddExplosionForce doing nothing? 1 Answer
Rotation problem with spawning bullet 2 Answers
[SOLVED] GameObject pooling is not returning enough objects! 0 Answers