Sundays are for rest, so this day of work has been an easy one. Some code refactors, like changing the default blending mode, but most importantly I added an important feature I wanted to have in the game.

It is expected, that when a group of bubbles pop, depending on their number, some “soul lines” would be added. These are the white lines in the gif.

These lines will fed up a power-up. Pop bubbles are the energy necessary to power one special effect that would randomly pop a predefined amount of bubbles. These lines are governed by an specific shader. They can have different color, size and intensity, and travel by a random cubic bezier curve. The curve describes the whole traverse path, and the segment is calculated by making use of a fancy easing scheme.

... this.easingStart = EasingEaseIn({exponent: 1.5}); this.easingEnd = EasingEaseOut({exponent: 1.5}); ... // nt stands for normalized time. // If the soul animation takes 2000 ms, nt=.5 means we // are at half the animation time. // Since I use a bezier curve, this does not correlate // to be the half point in the curve. // t0 and t1 will be two solved values over the bezier curve let t0 = this.easingStart(nt); const t1 = this.easingEnd(nt); ... // calculate a cubic segment ranging from t0..t1 on // the bezier curve for(let i = 0; i<Segments; i++) { bezier.getValueAt(t0, p0); bezier.getValueAt(t0+.001, p1); // normal vector as point p0 in the curve let nx = p1.y - p0.y; let ny = p1.x - p0.x; // normalized vector const l = Math.sqrt(nx*nx + ny*ny); nx/=l; ny/=l; ... // generate shader points: // p0 + nx * lineWidth // p0 - nx * lineWidth let yy0 = p0.y + p0y; let yy1 = p0.y - p0y; // avoid twisted lines if (yy0>yy1) { [yy0, yy1] = [yy1, yy0]; } this.lineData[ptr++] = p0.x + p0x; this.lineData[ptr++] = yy0; this.lineData[ptr++] = tint; this.lineData[ptr++] = 1; this.lineData[ptr++] = p0.x - p0x; this.lineData[ptr++] = yy1; this.lineData[ptr++] = tint; this.lineData[ptr++] = -1; ... }

The shader fragment is as simple as

vec4 f = vec4(uIntensity*smoothstep( .9, .0, abs(vY))); // vY -1 or 1 gl_FragColor = f*uColor*tint;

This line shader does not use tessellation. It does not benefit from any charming line join/cap process either, but i just want it to be a simple flowing line. It is current state, it does not batch lines. I should duplicate some shader data for that, which I will definitely do if I have the time or should I need to start optimising code.

In day 3 I will start coding in-game model + logic. Instead of an animation, I’d start to resemble more a whole game.

If you think you could contribute some graphics, just lemme know ğŸ˜€

Comments are also welcome.