Let's say you have a bunch of tweens running like this:


Now you want to scroll them horizontally while they fall. By updating camera x, they start moving, but in the end, the camera x value will overflow. And besides, one might want to wrap some background graphics before then.

Therefore we need to periodically snap the camera back to the original position. But then the tweens will snap back too.

So the individual sprites need a transform value on top of the current tween position to correct for the camera repositioning.

I haven't found any setting in Phaser for this. Any ideas?


It's possible to work around it with keeping a global variable to keep track of the camera yanking, and adding it manually to the onUpdateCallback of the tween, and consolidating the difference with the next tween change. But the hack seems to be glitching sometimes, and I suspect it's slower than if an internal transform variable could be used. Anyway, here's the result:



1 Answer 1


(Based on input from http://www.html5gamedevs.com/topic/20539-infinite-scroll-wrapping-with-tweened-sprites/)

A suggested workaround:

I coupled it with some event signals, and came up with the following test for performance (see below for code):


You can pass a whole number on get param c to change the count, default count is 100. On my laptop browser it starts acting up on after 2000 somewhere (Linux Mint 17,1, 770 MHz cpu, 3,5G ram, firefox 44.0.2) on a 800x600px canvas.

Basically I add a signal to the world object that adds the yank difference with addAll to all DisplayObjects' x values. Then it iterates the game tween manager to update each tweened custom sprite's camera_offset_x variable, used for those sprites to calculate the x together with the intermediary tweened tx property (IF the isTweened is true for the sprite). The camera_offset_x is reset with tween onComplete.

Funnily, the game.tweens.getAll() function is undefined when no tweens exist. Expected behaviour would be that it return 0 and not just blatantly fail, no?

var sprite = new Array();
var spawncount;

window.onload = function() {
    game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, '', {create: create, update: update});
    spawncount = parseInt(getQuery("c"));
    if (!spawncount || spawncount == 0 || spawncount === undefined || spawncount === null)
        spawncount = 100;
    else if (spawncount > 5000)
        spawncount = 5000;

CameraTweenGfx = function(game, x, y) {
    Phaser.Graphics.call(this, game, x, y);

    this.camera_offset_x = 0;
    this.tx = x;
    this.ty = y;

    this.update = function() {
        if (this.game.tweens.isTweening(this)) {
            this.x = this.tx - this.camera_offset_x;
            this.y = this.ty;

CameraTweenGfx.prototype = Object.create(Phaser.Graphics.prototype);
CameraTweenGfx.prototype.constructor = CameraTweenGfx;

function create() {

    game.camera.yank = function() {
        var params;

        params = {
            x: this.x,
            y: this.y
        this.setPosition(0, 0);
        console.log("inside custom camera yank method");

    game.camera.onYank = new Phaser.Signal();
    game.camera.onYank.add(yankHandler, game.camera);

    game.onCameraYank = new Phaser.Signal();
    game.onCameraYank.add(yankHandler2, game);

    game.world.setBounds(0, 0, window.innerWidth + 100, window.innerHeight);

    for (var i = 0; i < spawncount; i++) {
        var startx;
        var starty;
        var endx;
        var endy;
        var duration;
        var color;
        var size;

        startx = game.rnd.integerInRange(10, game.width - 10);
        starty = game.rnd.integerInRange(10, game.height - 10);
        endx = game.rnd.integerInRange(10,game.width - 10);
        endy = game.rnd.integerInRange(10, game.height - 10);
        color = game.rnd.integerInRange(0, 16581375);
        duration = game.rnd.integerInRange(100, 4000);
        size = game.rnd.integerInRange(10, 20);

        sprite[i] = new CameraTweenGfx(game, startx, starty);

        sprite[i].drawRect(0, 0, size, size);

        sprite[i].camera_offset_x = 0;

            tx: endx,
            ty: endy
        }, duration, null, true, 0, 0).onComplete.addOnce(function() {
            this.camera_offset_x = 0;
        }, sprite[i]);

    poly = new Phaser.Polygon();
        new Phaser.Point(0, game.height),
        new Phaser.Point(game.width, game.height / 2),
        new Phaser.Point(game.width, game.height),
    var graphics = game.add.graphics(0, 0);


function update() {
    game.camera.x ++;
    if (game.camera.x > 50)

function yankHandler(params) {
    console.log("inside camera onYank handler" + this.totalInView);
    // doesn't do anything now, but maybe needed for other stuff maybe needed for other stuff

function yankHandler2(params) {
    console.log("inside game onCameraYank handler");
    this.world.addAll("x", -50);
    if (typeof this.tweens.getAll == "function") {
        this.tweens.getAll().forEach(function(o) {
            o.target.camera_offset_x += params.x;

// naughtly stolen from stackoverflow.com/questions/831030/how-to-get-get-request-parameters-in-javascript
function getQuery(name){
   if(name=(new RegExp('[?&]'+encodeURIComponent(name)+'=([^&]*)')).exec(location.search))
      return decodeURIComponent(name[1]);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .