Jump to content

Infinite scroll wrapping with tweened sprites


lash
 Share

Recommended Posts

I have a bunch of sprites that are continuously tweening in a feather fall like movement:

http://holbrook.no/tests/featherfall.html

To this I need to add infinite side scroll. To avoid that potentially the camera value (theoretically) overflows, I need to yank the camera back periodically. To avoid that the sprites aren't yanked with it, I need to update their x-transformation, too,.

I can't find any settings (like camera offset) that can adjust the transformation on the sprites individually, that can be applied on top of the tweening position.

Any ideas how to do this?

Link to comment
Share on other sites

Are you trying to keep your feather-falling sprite fixed to the camera even when it's yanking back to the beginning of the world?  If so, I would throw all those sprites into a group, and make that group fixed to camera.

myFeatherFallGroup.fixedToCamera = true;

 

Link to comment
Share on other sites

No, I want the hearts to follow the scrolling, like this:

http://www.holbrook.no/tests/featherfallscrolled.html

In the above link, it's done by manually adding the camera offset x to every update callback of the tweens, which I suspect is more expensive than any already existing transform routine. Also, it's not perfect, as it glitches occasionally, as if sometimes the calculation isn't being made.

Link to comment
Share on other sites

Okay, I think I follow you.  My approach would be: At the instant of the yank, find out exactly how many pixels back I'm going to yank.  Let's say it's 500px just for fun.  Then I would do this:

var yankAmount = 500;
for(var i = featherGroup.children.length - 1; i >= 0; i--){
    featherGroup.children.x -= yankAmount;
}

This will instantly reposition the feathers back to the left side of their group.  As long as you move them the same number of pixels as your yank, you shouldn't notice any problem.  The advantage here is that rather than doing extra calculations on every update frame, you do it only every yank.

Link to comment
Share on other sites

You beat me to it.  I was just editing my last post to retract my shortsightedness.

Here's my instinct.  When a feather is launched, I would set a targetX on the sprite.  I would then tween a property I invented like xOffset rather than x itself.  Then, in the sprite's update loop, I would set x to targetX + offsetX.

Then, in the loop I gave above, I would do featherGroup.children.targetX -= yankAmount;

This should decouple the tween from the x position enough for things to work.

Link to comment
Share on other sites

Ah,I didn't think of the possibility of using arbitrary properties for tween. That's very useful.

Based on your input I've made a workaround.

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

http://www.holbrook.no/tests/tweencamerasync.html

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

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");
		this.onYank.dispatch(params);
	};
	
	
	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 = new CameraTweenGfx(game, startx, starty);
		game.add.existing(sprite);
		
		sprite.beginFill(color);
		sprite.drawRect(0, 0, size, size);
		sprite.endFill();
	
		sprite.camera_offset_x = 0;
   
		game.add.tween(sprite).to({
			tx: endx,
			ty: endy
		}, duration, null, true, 0, 0).onComplete.addOnce(function() {
			this.camera_offset_x = 0;
		}, sprite);
	}
	
	
	poly = new Phaser.Polygon();
    poly.setTo([
		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);
    graphics.beginFill(0x00FF00);
    graphics.drawPolygon(poly.points);
    graphics.endFill();
    game.world.sendToBack(graphics);
 
}

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

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
	this.game.onCameraYank.dispatch(params);
}

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

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...