- Home /
How do I make this script emit different particles for different surfaces & objects?
I have this script adapted from the FPS tutorial and I can't seem to figure out how to get it to emit different particles for bullet impacts on different surfaces. I know this is a common question but the answere seems to be far less so ;)
I have (and I hope I'm doing right) two different particle emmiters attached to my Machine gun game object so I don't know how the script is supposed to know the difference between them and how to call them into play when needed. here is my script:
var range = 100.0; var fireRate = 0.05; var force = 10.0; var damage = 5.0; var bulletsPerClip = 40; var clips = 20; var reloadTime = 0.5; private var hitParticles : ParticleEmitter; var muzzleFlash : Renderer;
private var bulletsLeft : int = 0; private var nextFireTime = 0.0; private var m_LastFrameShot = -1;
function Start () { hitParticles = GetComponentInChildren(ParticleEmitter); // We don't want to emit particles all the time, only when we hit something.
if (hitParticles)
hitParticles.emit = false;
bulletsLeft = bulletsPerClip;
}
function LateUpdate() {
if (muzzleFlash)
{
// We shot this frame, enable the muzzle flash
if (m_LastFrameShot == Time.frameCount)
{
muzzleFlash.transform.localRotation = Quaternion.AxisAngle
(Vector3.forward, Random.value);
muzzleFlash.enabled = true;
if (audio)
{
if (!audio.isPlaying)
audio.Play();
audio.loop = true;
}
}
// We didn't, disable the muzzle flash
else
{
muzzleFlash.enabled = false;
enabled = false;
// Play sound
if (audio)
{
audio.loop = false;
}
}
}
}
function Fire () { if (bulletsLeft == 0) return;
// If there is more than one bullet between the last and this frame
// Reset the nextFireTime
if (Time.time - fireRate > nextFireTime)
nextFireTime = Time.time - Time.deltaTime;
// Keep firing until we used up the fire time
while( nextFireTime < Time.time && bulletsLeft != 0)
{
FireOneShot();
nextFireTime += fireRate;
}
}
function FireOneShot () { var direction = transform.TransformDirection(Vector3.forward); var hit : RaycastHit;
// Did we hit anything?
if (Physics.Raycast (transform.position, direction, hit, range))
{
// Apply a force to the rigidbody we hit
if (hit.rigidbody)
hit.rigidbody.AddForceAtPosition(force * direction, hit.point);
// Place the particle system for spawing out of place where we hit the
// surface!
// And spawn a couple of particles
if (hitParticles)
{
hitParticles.transform.position = hit.point;
hitParticles.transform.rotation =
Quaternion.FromToRotation (Vector3.up,
hit.normal);
hitParticles.Emit();
}
// Send a damage message to the hit object
hit.collider.SendMessageUpwards("ApplyDamage", damage,
SendMessageOptions.DontRequireReceiver);
}
bulletsLeft--;
// Register that we shot this frame,
//so that the LateUpdate function enabled the muzzleflash renderer for one
//frame
m_LastFrameShot = Time.frameCount;
enabled = true;
// Reload gun in reload Time
if (bulletsLeft == 0)
StartCoroutine("Reload");
}
function Reload () {
// Wait for reload time first - then add more bullets!
yield WaitForSeconds(reloadTime);
// We have a clip left reload
if (clips > 0)
{
clips--;
bulletsLeft = bulletsPerClip;
}
}
function GetBulletsLeft () { return bulletsLeft; }
////////////////////////////////////////////////
EDIT: I've updated my code following Dave's post to this:
var range = 100.0; var fireRate = 0.05; var force = 10.0; var damage = 5.0; var bulletsPerClip = 40; var clips = 20; var reloadTime = 0.5; private var hitParticles : ParticleEmitter[]; var muzzleFlash : Renderer;
private var bulletsLeft : int = 0; private var nextFireTime = 0.0; private var m_LastFrameShot = -1;
function Start () { hitParticles = GetComponentsInChildren(ParticleEmitter); // We don't want to emit particles all the time, only when we hit something.
if (hitParticles)
hitParticles[0].emit = false;
bulletsLeft = bulletsPerClip;
}
function LateUpdate() {
if (muzzleFlash)
{
// We shot this frame, enable the muzzle flash
if (m_LastFrameShot == Time.frameCount)
{
muzzleFlash.transform.localRotation = Quaternion.AxisAngle
(Vector3.forward, Random.value);
muzzleFlash.enabled = true;
if (audio)
{
if (!audio.isPlaying)
audio.Play();
audio.loop = true;
}
}
// We didn't, disable the muzzle flash
else
{
muzzleFlash.enabled = false;
enabled = false;
// Play sound
if (audio)
{
audio.loop = false;
}
}
}
}
function Fire () { if (bulletsLeft == 0) return;
// If there is more than one bullet between the last and this frame
// Reset the nextFireTime
if (Time.time - fireRate > nextFireTime)
nextFireTime = Time.time - Time.deltaTime;
// Keep firing until we used up the fire time
while( nextFireTime < Time.time && bulletsLeft != 0)
{
FireOneShot();
nextFireTime += fireRate;
}
}
function FireOneShot () { var direction = transform.TransformDirection(Vector3.forward); var hit : RaycastHit;
// Did we hit anything?
if (Physics.Raycast (transform.position, direction, hit, range))
{
// Apply a force to the rigidbody we hit
if (hit.rigidbody)
hit.rigidbody.AddForceAtPosition(force * direction, hit.point);
// Place the particle system for spawing out of place where we hit the
// surface!
// And spawn a couple of particles
if (hitParticles)
{
hitParticles.transform.position = hit.point;
hitParticles.transform.rotation =
Quaternion.FromToRotation (Vector3.up,
hit.normal);
hitParticles.Emit();
}
// Send a damage message to the hit object
hit.collider.SendMessageUpwards("ApplyDamage", damage,
SendMessageOptions.DontRequireReceiver);
}
bulletsLeft--;
// Register that we shot this frame,
//so that the LateUpdate function enabled the muzzleflash renderer for one
//frame
m_LastFrameShot = Time.frameCount;
enabled = true;
// Reload gun in reload Time
if (bulletsLeft == 0)
StartCoroutine("Reload");
}
function Reload () {
// Wait for reload time first - then add more bullets!
yield WaitForSeconds(reloadTime);
// We have a clip left reload
if (clips > 0)
{
clips--;
bulletsLeft = bulletsPerClip;
}
}
function GetBulletsLeft () { return bulletsLeft; }
////////////////////////////////////////////////
I get an error message that reads: Assets/WeaponScripts/MachineGun.js(21,46): BCE0019: 'emit' is not a member of 'UnityEngine.ParticleEmitter[]'.
So I'm clearly still missing something???
Answer by DaveA · Mar 21, 2011 at 07:00 PM
I'd try changing hitParticles to an array
private var hitParticles : ParticleEmitter[];
and use GetComponenetsInChildren(ParticleEmitter) instead to get all pe's (assuming you made those pe's children of the machine gun).
Then alter the code slightly to use the array of particle emitters. You'd pick the one to set 'emit' for based on the surface they hit, which you can determine from the collider that was hit (its gameobject, its material (or tag or whatever)
var range = 100.0; var fireRate = 0.05; var force = 10.0; var damage = 5.0; var bulletsPerClip = 40; var clips = 20; var reloadTime = 0.5; private var hitParticles : ParticleEmitter[]; var muzzleFlash : Renderer;
private var bulletsLeft : int = 0;
private var nextFireTime = 0.0;
private var m_LastFrameShot = -1;
function Start ()
{
hitParticles = GetComponentsInChildren(ParticleEmitter);
// We don't want to emit particles all the time, only when we hit something.
for (var i = 0; i < hitParticles.Length; i++)
hitParticles[i].emit = false;
bulletsLeft = bulletsPerClip;
}
function LateUpdate()
{
if (muzzleFlash)
{
// We shot this frame, enable the muzzle flash
if (m_LastFrameShot == Time.frameCount)
{
muzzleFlash.transform.localRotation = Quaternion.AxisAngle
(Vector3.forward, Random.value);
muzzleFlash.enabled = true;
if (audio)
{
if (!audio.isPlaying)
audio.Play();
audio.loop = true;
}
}
// We didn't, disable the muzzle flash
else
{
muzzleFlash.enabled = false;
enabled = false;
// Play sound
if (audio)
{
audio.loop = false;
}
}
}
}
function Fire ()
{
if (bulletsLeft == 0)
return;
// If there is more than one bullet between the last and this frame
// Reset the nextFireTime
if (Time.time - fireRate > nextFireTime)
nextFireTime = Time.time - Time.deltaTime;
// Keep firing until we used up the fire time
while( nextFireTime < Time.time && bulletsLeft != 0)
{
FireOneShot();
nextFireTime += fireRate;
}
}
function FireOneShot ()
{
var direction = transform.TransformDirection(Vector3.forward);
var hit : RaycastHit;
// Did we hit anything?
if (Physics.Raycast (transform.position, direction, hit, range))
{
// Apply a force to the rigidbody we hit
if (hit.rigidbody)
hit.rigidbody.AddForceAtPosition(force * direction, hit.point);
// Place the particle system for spawing out of place where we hit the
// surface!
// And spawn a couple of particles
if (hitParticles)
{
// New code var peIdx = 0; // lets say 0 is 'normal' but 1 is 'steel' // determine what was hit if (hit.transform.tag == "steel") peIdx = 1; // you can expand on this with more types of things. Note you must define the tag and set it on the prefabs // /New code hitParticles[peIdx].transform.position = hit.point; hitParticles[peIdx].transform.rotation = Quaternion.FromToRotation (Vector3.up, hit.normal); hitParticles[peIdx].Emit(); }
// Send a damage message to the hit object
hit.collider.SendMessageUpwards("ApplyDamage", damage,
SendMessageOptions.DontRequireReceiver);
}
bulletsLeft--;
// Register that we shot this frame,
//so that the LateUpdate function enabled the muzzleflash renderer for one
//frame
m_LastFrameShot = Time.frameCount;
enabled = true;
// Reload gun in reload Time
if (bulletsLeft == 0)
StartCoroutine("Reload");
}
function Reload () {
// Wait for reload time first - then add more bullets!
yield WaitForSeconds(reloadTime);
// We have a clip left reload
if (clips > 0)
{
clips--;
bulletsLeft = bulletsPerClip;
}
}
function GetBulletsLeft () {
return bulletsLeft;
}
Hey Dave when you say " changing hitParticles to an array" how do I do that?
I edited my post after following what Dave Said but I get an error message: Assets/WeaponScripts/$$anonymous$$achineGun.js(21,46): BCE0019: 'emit' is not a member of 'UnityEngine.ParticleEmitter[]'.
So I'm clearly not understanding and or missing something??
You need to index into the array hitParticles[0].emit, for example
I'm still not getting what yur on about, I changed that line to what you wrote above and I get this error message: Assets/WeaponScripts/$$anonymous$$achineGun.js(99,86): BCE0019: 'transform' is not a member of 'UnityEngine.ParticleEmitter[]'.
??? Im a visual persone so I need a little more to go on
Ah, I'd assumed you were more familiar with program$$anonymous$$g. I'll edit my answer with more code
Answer by efge · Mar 21, 2011 at 07:03 PM
You could create two different Particle Systems and instantiate them at the RaycastHit.point depending on the tag or the name of the hit.collider or even the PhysicMaterial when you get a RaycastHit.
Take a look at the section Instantiating rockets & explosions int the reference for Instantiating Prefabs at runtime
Well, my two diffent particle effects are prefabs that are children of my $$anonymous$$acine gun as I mentioned in my question if that helps any?