How do I shoot a bullet that follows a sine wave?


I am trying to get a “gun” object that fires a “bullet” object in a sine wave pattern.
The gun can be pointing in any direction, so to get the bullet to travel forward I use this:

transform.Translate(Vector3.forward * magnitude * Time.deltaTime);

I want the bullet to always be facing the direction that is moving (always forward), so it’s forward direction will rotate as it is moving forward to follow the path of the sine wave. To do this, I think I should rotate the transform. I’ve tried several ways with no success.

For my last try I did the following:

Vector3 direction = transform.Forward;
direction.x += Cos(transform.position.x);
direction.y += Sin(transform.position.x);
transform.rotation = Quaternion.RotateTowards(transform.rotation,

Then I move it forward using the code I supplied up top, but the bullets just sort of bubble around facing silly directions.
I’ve made so many changes that I don’t think the above even makes sense anymore.
Can someone help me with the math for this?


The problem with that method is that if you tilt left for a second, then right for a second, sure you’ll be aimed in the same direction as when you started, but you’ll be to the right of your original path by who knows what. To make all the sideslips cancel, you could have the first tilt right be only 1/2 second. But, once you start tilting by Sins, you need integrals to solve it (if I tilt right faster and faster, then 1/2 second is no longer 1/2 the tilt.)

Having said that, this looks nice and the aim is barely off:

float startTime;
Start() { startTime=Time.time; ... } // <--yes, key off time passed

Update() {
  // tilts up/down (rotate around local x):
  // move local forwards here

The *6 is the period: 2PI (6.28) gives exactly one bob/second. The *1 is how steep the bobs are. The 1.3 is a fudge factor. Without it, the bullets tilts up, then down, and ends up facing the way it was fired, but too high, over and over. 1.3 has it about stay even.

To make aiming work, maybe an empty flying the way you shoot, and a child that keys off the correctly aimed, stable parent, but bobbing:

Transform childBullet;
float startTime;

Start() { 
  childBullet = transform.Find("childBulletModel");
  startTime = Time.time;

FixedUpdate() {
  // wiggle child up/down:
  float Y = Mathf.Sin((Time.time-fireTime)*10)*3;
  childBullet.localPosition = new Vector3(0, Y, 0);

  // horrible hack to aim where we will be in 0.1 seconds:
  Vector3 newPos = transform.position+transform.forward*0.1f+
  // move us ...

As before, `*10` is the period of the wiggle (2PI is 1/sec) and `*3` is the amount, in meters.