Interconnecting nodes with lines using Phaser

Hello all, I haven’t posted in a while but this is an effect that I think deserves a place in here. What this effect does is to make tweening of nodes and the lines connected to those nodes move as well. I’m using Phaserjs for this and depending on your version of the browser it will show as either WebGL or Canvas.

Without any further delay here is the final effect

 

See the Pen Phaser interconnecting nodes by Michael Dobekidis (@netgfx) on CodePen.

Advanced:

See the Pen Phaser interconnecting nodes x3 by Michael Dobekidis (@netgfx) on CodePen.373

Continue to code break down and tutorial


Default Phaser initialization


var game = new Phaser.Game(800, 400, Phaser.AUTO, '', {
preload: preload,
create: create,
update: update
});


Basic Graphic creation


var startLine = game.add.graphics(0, 0);
startLine.beginFill(0xFF3300);
startLine.lineStyle(2, 0xffd900, 1);
startLine.moveTo(-100, game.height / 2 - 1);
startLine.lineTo(game.width / 2 - 100, game.height / 2 - 1);
startLine.endFill();

/// circle ///
var circle = game.add.graphics(game.width / 2 - 100, game.height / 2);
circle.lineStyle(0);
circle.beginFill(0xFFFF0B, 1);
circle.drawCircle(0, 0, 20);
circle.endFill();

///// line ////
var middleLine = game.add.graphics(0, 0);
middleLine.beginFill(0xFF1100);
middleLine.lineStyle(2, 0xff1100, 1);
middleLine.moveTo(game.width / 2 - 90, game.height / 2 - 1);
middleLine.lineTo(game.width / 2 + 100, game.height / 2 - 1);
middleLine.endFill();

////////// circle //////
var circle2 = game.add.graphics(game.width / 2 + 100, game.height / 2);
circle2.lineStyle(0);
circle2.beginFill(0xFFFF0B, 1);
circle2.drawCircle(0, 0, 20);
circle2.endFill();

//////////// end line ///////
var endLine = game.add.graphics(0, 0);
endLine.beginFill(0x149900);
endLine.lineStyle(2, 0x149900, 1);
endLine.moveTo(game.width / 2 + 100 + 10, game.height / 2 - 1);
endLine.lineTo(game.width + 100, game.height / 2 - 1);
endLine.endFill();

So now we have created the following setup:

  • line from x=0 to circle1
  • line from circle1 to circle2
  • line from circle2 to end of stage

 

Note: that all the shapes are vertically positioned on the middle of the stage

 


Animating the circles

So now we need to animate(tween) the x & y position of the circles and use onUpdateCallback to change the start and end of the lines and draw them. Basically, we re-create the lines based on the linear interpolation of the circle’s movement based on the percentage of the tween duration.


function moveCircle(item, item2, x, y, x2, y2) {
item.initialX = item.x;
item.initialY= item.y;
item2.initialX = item2.x;
item2.initialY = item2.y;
var tween = tweenProperty(item, "xy", {
x: x,
y: y
}, 1200,0,Phaser.Easing.Back.InOut);
var tween2 = tweenProperty(item2, "xy", {
x: x2,
y: y2
}, 1200,0,Phaser.Easing.Back.InOut);

tween.chain(tween2);

tween.onUpdateCallback(function(twn, percent, twnData) {
redraw(percent, reg.line1, [item.initialX, x], [item.initialY, y], -100, game.height/2-1, 0xffd900);
//// middle line //////
redrawBoth(percent, reg.line2, [item.initialX+10, x+10], [item.initialY, y], [item2.initialX, x2], [item2.initialY, y2], 0xFF1100);
//// end line /////
redraw(percent, reg.line3, [item2.initialX+10, x2+10], [item2.initialY, y2], game.width+100, game.height/2-1, 0x149900);
});
tween.onComplete.addOnce(moveRandomly);
}

Now we create the actual functions that handle the drawing of the lines based on whether they have a part that is static (startLine, endLine) or both ends are moving (middleLine)


function redraw(percent, dataObj, rangeX, rangeY, startPointX, startPointY, color) {
dataObj.clear();
dataObj.beginFill(color);
dataObj.lineStyle(2, color, 1);
dataObj.moveTo(startPointX, startPointY);
var x = Phaser.Math.linearInterpolation(rangeX, percent);
var y = Phaser.Math.linearInterpolation(rangeY, percent);
dataObj.lineTo(x, y);
dataObj.endFill();
}

function redraw2(percent, dataObj, rangeX, rangeY, endPointX, endPointY, color) {
dataObj.clear();
dataObj.beginFill(color);
dataObj.lineStyle(2, color, 1);
var x = Phaser.Math.linearInterpolation(rangeX, percent);
var y = Phaser.Math.linearInterpolation(rangeY, percent);
dataObj.moveTo(x, y);
dataObj.lineTo(endPointX, endPointY);
dataObj.endFill();
}

function redrawBoth(percent, dataObj, rangeX, rangeY, endPointX, endPointY, color) {
dataObj.clear();
dataObj.beginFill(color);
dataObj.lineStyle(2, color, 1);
var x = Phaser.Math.linearInterpolation(rangeX, percent);
var y = Phaser.Math.linearInterpolation(rangeY, percent);
dataObj.moveTo(x, y);
var x2 = Phaser.Math.linearInterpolation(endPointX, percent);
var y2 = Phaser.Math.linearInterpolation(endPointY, percent);
dataObj.lineTo(x2, y2);
dataObj.endFill();
}

So as we see, when we have a moving end of a line (a circle) we calculate its position based on the linear interpolation of the tween percentage and the starting-ending position of the circle that is been animated.


Adding some random movement


function moveRandomly(){
var x = game.rnd.integerInRange(game.width/2-100, game.width/2 + 100);
var y = game.rnd.integerInRange(game.height/2-100, game.height/2+120);
var x2 = game.rnd.integerInRange(game.width/2-100, game.width/2 + 100);
var y2 = game.rnd.integerInRange(game.height/2-100, game.height/2+120);
moveCircle(reg.circle1,reg.circle2, x, y, x2, y2);
}

function tweenProperty(item, property, obj, duration, delay, easing, yoyo, repeat, reverse) {

delay = delay || {};
easing = easing || Phaser.Easing.Linear.None;
yoyo = yoyo || false;
repeat = repeat || 0;

var tween = game.add.tween(item).to(obj, duration, easing, true, delay, repeat, yoyo);
tween.reverse = reverse || false;
return tween;
}

Note: tweenProperty function is just a helper function that I use, using a normal Phaser tween would work just the same.

 

Note #2: moveRandomly function is called when the tweens end, and this creates a loop.

 

Enjoy!

Facebooktwittergoogle_pluspinterestlinkedin
linkedin
Tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *