Building a Javascript game Day 2

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);


        // 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.

Published by ibon

Chocolate engineer, software eater. Data visualisation at Workday. Past: Platochat, SdkBox, Chukong, Ludei.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: