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.

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 circles 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!

Tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

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