I’m looking for a way to create a wave in a shape designed in canvas. After much research I found something that is pretty close to what I want:
You can make a more realistic wave using interference.
Use various parameters so you can adjust it live to find a good combination.
You can also add oscillators to represent the z axis to make it more realistic in case you want to layer the waves to make a pseudo-3D wave.
I cannot give you wave collision, fluid dynamics - that would be a bit too broad for SO but I can give you a fluid-ish wave example (as you have the point of each segment you can use that for collision detection).
And example would be to create an oscillator object which you could set the various settings on such as amplitude, rotation speed (phase) etc.
Then have a mixer function which mixes the result of these oscillators that you use.
The oscillator object in this demo look like this:
function osc() {
/// various settings
this.variation = 0.4; /// how much variation between random and max
this.max = 100; /// max amplitude (radius)
this.speed = 0.02; /// rotation speed (for radians)
var me = this, /// keep reference to 'this' (getMax)
a = 0, /// current angle
max = getMax(); /// create a temp. current max
/// this will be called by mixer
this.getAmp = function() {
a += this.speed; /// add to rotation angle
if (a >= 2.0) { /// at break, reset (see note)
a = 0;
max = getMax();
}
/// calculate y position
return max * Math.sin(a * Math.PI) + this.horizon;
}
function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}
return this;
}
This do all the setup and calculations for us and all we need to do is to call the getAmp()
to get a new value for each frame.
Instead of doing it manually we can use a "mixer". This mixer allows us to add as many oscillators we want to the mix:
function mixer() {
var d = arguments.length, /// number of arguments
i = d, /// initialize counter
sum = 0; /// sum of y-points
if (d < 1) return horizon; /// if none, return
while(i--) sum += arguments[i].getAmp(); /// call getAmp and sum
return sum / d + horizon; /// get average and add horizon
}
Putting this in a loop with a point recorder which shifts the point in one direction will create a fluid looking wave.
The demo above uses three oscillators. (A tip in that regard is to keep the rotation speed lower than the big swell or else you will get small bumps on it.)
NOTE: The way I create a new random max is not the best way as I use a break point (but simple for demo purpose). You can instead replace this with something better.