I thought you’re never too old to start so I downloaded Unity and now I’m trying to put together some videogame ideas I had since my childhood. I’ve had some experience with PHP + JS in the past, and with Python and JS + React for front-end development in the present. I’m no expert, but I’m normally good at understanding the logic behind.
Anyway, I’m quite motivated so it’s not unusual that I plan doing things I still don’t have the skills for (like this one right here).
It’s some sort of “magical shotgun”. It’s working and all, but I’d really really like that the pellets didn’t spawn all at the same time when the player fires; I’d like to give them some small delay between each other.
I’ve googled a bit and found solutions involving “Invoke”, “IEnumerator” and Coroutines, but somehow I haven’t been able to them pull off.
Basically what I need is that the function “fire()” gets executed as many times as there are pellets, but with a little delay between each time. This is my code and a short video showing how it looks right now (never mind the silly hand, it’s just a placeholder):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SG : MonoBehaviour
{
public int pelletCount = 15;
public float spreadAngle = 5;
public int pelletFireVelocity=3000;
public GameObject weaponHolder;
public GameObject pellet;
public Transform BarrelExit;
List<Quaternion> pellets;
void Awake()
{
//?
}
void Update()
{
if(Input.GetButtonDown("Fire1"))
{
fire();
}
}
void fire()
{
int selectedPowerLevel = weaponHolder.transform.GetComponent<WeaponSwitching>().selectedPowerLevel;
int newPelletCount = pelletCount + (selectedPowerLevel * 5);
float newSpreadAngle = spreadAngle + selectedPowerLevel * .75f;
int newPelletFireVelocity = pelletFireVelocity + selectedPowerLevel * 1000;
pellets = new List<Quaternion>(newPelletCount);
for (int i = 0; i < newPelletCount; i++)
{
pellets.Add(Quaternion.Euler(Vector3.zero));
}
for (int i = 0; i < newPelletCount; i++)
{
pellets[i] = Random.rotation;
GameObject p = Instantiate(pellet, BarrelExit.position, BarrelExit.rotation);
p.transform.rotation = Quaternion.RotateTowards(p.transform.rotation, pellets[i], newSpreadAngle);
p.GetComponent<Rigidbody>().AddForce(p.transform.forward * newPelletFireVelocity);
Destroy(p, 3f);
}
}
}
Any ideas on how to approach this would be very welcome!
Yeah, already did that (attached new code)… but it’s not exactly that… I mean that every time that the player fires, I want all of the 15 (or so) pellets be fired in the same “burst”, just with a little delay from each other (I mean, hundredths of a second), just for artistic purposes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SG : MonoBehaviour
{
public float damage = 5f;
public float fireRate = 1f;
public int pelletCount = 15;
public float spreadAngle = 5;
public int pelletFireVelocity=3000;
public GameObject weaponHolder;
public GameObject pellet;
public Transform BarrelExit;
List<Quaternion> pellets;
private float nextTimeToFire = 0f;
void Awake()
{
//?
}
void Update()
{
if(Input.GetButton("Fire1") && Time.time >= nextTimeToFire)
{
float selectedPowerLevel = weaponHolder.transform.GetComponent<WeaponSwitching>().selectedPowerLevel;
nextTimeToFire = Time.time + 1f + selectedPowerLevel/5f;
Debug.Log(nextTimeToFire);
fire();
}
}
void fire()
{
int selectedPowerLevel = weaponHolder.transform.GetComponent<WeaponSwitching>().selectedPowerLevel;
int newPelletCount = pelletCount + (selectedPowerLevel * 5);
float newSpreadAngle = spreadAngle + selectedPowerLevel * .75f;
int newPelletFireVelocity = pelletFireVelocity + selectedPowerLevel * 1000;
pellets = new List<Quaternion>(newPelletCount);
for (int i = 0; i < newPelletCount; i++)
{
pellets.Add(Quaternion.Euler(Vector3.zero));
}
for (int i = 0; i < newPelletCount; i++)
{
pellets[i] = Random.rotation;
GameObject p = Instantiate(pellet, BarrelExit.position, BarrelExit.rotation);
p.transform.rotation = Quaternion.RotateTowards(p.transform.rotation, pellets[i], newSpreadAngle);
p.GetComponent<Rigidbody>().AddForce(p.transform.forward * newPelletFireVelocity);
Destroy(p, 3f);
}
}
}
If you just want to program it straight, make a public variable like int burstRemaining=0;. Your program would be something like:
if(fireDelay<=0 && playerPressedFire) burstsReamining=4;
if(burstsRemaining>0) {
burstsRemaining--;
for( ... ) // the same loop you had, to fire 2 or 3 pellets
}
When you fire, this frame and the next 3 will spit out a few pellets. If you want more of a delay, make it 8 and have only odd-numbers shoot pellets.
But Unity coroutines are made for exactly this sort of thing. They’re the only way to add “wait until next frame” right in the middle of your code. They take a bit to set-up, but the guides explain it well-enough.
Just remember that anything happening in the range of “hundredths of a second” is likely to happen faster than your framerate. Since our code in Unity can only operate more or less once every frame, you’ll have to do some trickery to get things to look right. This may mean, for example, spawning multiple projectiles in a single frame and positioning them as if they had been fired at the intended rate based on their velocities and the “real” time they would have spawned if Unity was continuous.
I’m seeing the “multiple pellets per frame” thing in the code examples above, but missing the “properly positioning them in space as if they had been fired at different times” part.