Rodrigo

Vertical Image Sprite

Recommended Posts

Hi,

 

I'm a total noob in this area so I'm not even sure if Pixi is right for what I need.

 

I'm a front end developer and turns out that I have to create a interactive website. The client is wants to rely on sprite sheet images (vertical mostly) to create some fancy cartoon-like animations. For rendering issues my original idea is to do this with PIxi (I've read how great it works on top of WebGL, when supported) and I saw some examples in devices and was very impressed with the performance.

 

To the point, is Pixi the best tool for this or I'm going a little over board by using it?. I mean would be a significant difference in performance if I use Pixi or just change the background position of a bunch of DOM elements?. Should I use another canvas framework for this purpose?. If Pixi is the right choice, how can I animate this type of stuff (big linear sprite images)?. One of the sprites is over 11000 pixels of height and I get a width or height out of range warning in the console so I can't even get the image in the stage.

 

In other scenario the sprite is composed of 4 images of 400 pixels of height each one (1600 pixels total). The stage has 800 pixels of height and I want to show just one image, I'm using this code:

var mainStage = new PIXI.Stage(0xeeeeee),    mainRenderer = PIXI.autoDetectRenderer(960,800);document.body.appendChild(mainRenderer.view);var // the image Sprite imported as a texture    testTexture = new PIXI.Texture.fromImage('img/bird.jpg'),    // the actual element in the stage    testSprite = new PIXI.TilingSprite(testTexture,640,800);mainStage.addChild(testSprite);// render the canvas stagerequestAnimFrame( animate ); function animate(){  requestAnimFrame( animate );  // render the stage     mainRenderer.render(mainStage);}

And I'm getting this result, which shows more than I want. What I need is just the top part of the image:

pixi2.jpg

 

And if I change the code to this:

var // the image Sprite imported as a texture    testTexture = new PIXI.Texture.fromImage('img/bird.jpg'),    // the actual element in the stage    testSprite = new PIXI.TilingSprite(testTexture,640,400);

The result is this:

pixi1.jpg

 

The image is scaled down as the height is changed. How can I correct this?.

 

Many thanks in advance,

Rodrigo.

Share this post


Link to post
Share on other sites

The PIXI.BaseTexture is the image source, and a PIXI.Texture references the BaseTexture and specifies the Frames..

 

// "Image" Implements "HTMLImageElement" Interface: // Reference: http://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElementvar source = new Image(); source.src = "img/bird.jpg";// "HTMLImageElement" is the 'source' of BaseTextureTestBaseTexture = new PIXI.BaseTexture(source, PIXI.scaleModes.LINEAR);//The Rectangle is the FrameTestTexture = new PIXI.Texture(TestBaseTexture, new PIXI.Rectangle(0,0,400,400));//PIXI.Texture.FromFrame loads from cache.. in this method, we are using// the texture instance we created.TestSprite = new PIXI.Sprite(TestTexture);		stage.addChild(TestSprite);

EDIT: I actually couldn't make sense of the 'loaded' event being emitted/dispatched in the Documentation (http://www.goodboydigital.com/pixijs/docs/files/src_pixi_textures_BaseTexture.js.html#l11) .. so I removed reference to it in the code sample I posted.. 

Edited by mrBRC

Share this post


Link to post
Share on other sites

 I made the edit above to remove the sentiment about the loaded EventListener.. this next code sample works...

var source = new Image();source.src = "img/bird.jpg";TestBaseTexture = new PIXI.BaseTexture(source, PIXI.scaleModes.LINEAR);TestBaseTexture.addEventListener("loaded", function(e) {    TestTexture = new PIXI.Texture(TestBaseTexture, new PIXI.Rectangle(0,0,400,400));    TestSprite = new PIXI.Sprite(TestTexture);    stage.addChild(TestSprite);});	

.. however, you're essentially attaching this event listener to TestBaseTexture while it is actively loading the source.. so I don't know how stable.

I attempted to create a new PIXI.BaseTexture(null, PIXI.scaleModes.LINEAR); attaching the event listener, and than assigned the source to TestBaseTexture.source... it does not raise the loaded event..

which is what I meant by I couldn't make sense of the 'loaded' event in the documentation.. it only seems to work at the point you initialize the object with a source.. 

Share this post


Link to post
Share on other sites

Hi,

 

Thanks a lot for the answer, it was very helpful and did the trick.

 

I do have another question. The idea, as mentioned in the original post, is to create an animation using sprites. How can I move the base texture without calling all that code over and over. I'm not sure about code performance, probably is not an issue, but it seems a little cumbersome create every time the same set of elements and finally keep adding the sprite to the stage like this:

function updateSprite(value){  TestTexture = new PIXI.Texture(TestBaseTexture, new PIXI.Rectangle(0,value,400,400));  TestSprite = new PIXI.Sprite(TestTexture);  stage.addChild(TestSprite);}

So I was wondering if there's a direct method that works on an object key:value pair to change the texture position, like position.x on a sprite, for example. I tried with setFrame() but it returns an error:

//this removes the sprite from the rendererTestTexture.setFrame(0,400,640,400);// also tried this and seems to change the scale of the elementTestTexture.setFrame(TestBaseTexture, new PIXI.Rectangle(0,400,640,400));

Thanks a lot again.

 

Cheers,

Rodrigo.

Share this post


Link to post
Share on other sites

well.. they will be seperate Texture objects..

you should probably consider using a Loader...

 

 

I use an AssetLoader, which in turn calls a JsonLoader when the asset is a json file.

 

This the sprite sheet, composed of several images of different frame sizes.

http://www.iakarra.net/demo/polymer/WiAClient/ingame.png

This is the json file that specifies the frames (by name) and has a meta property on the bottom that gives a relative uri to the spritesheet.

http://www.iakarra.net/demo/polymer/WiAClient/ingame.json


Lets assume you have a bunny file that has 2 frames 400 width and height each, where the 2nd animation is below the first.

{ "frames": {"bunny-0" : {	"frame": {"x":0,"y":0,"w":400,"h":400},	"rotated": false,	"trimmed": false,	"spriteSourceSize": {"x":0,"y":0,"w":18,"h":18},	"sourceSize": {"w":18,"h":18}},"bunny-1" : {	"frame": {"x":0,"y":400,"w":400,"h":400},	"rotated": false,	"trimmed": false,	"spriteSourceSize": {"x":0,"y":0,"w":400,"h":400},	"sourceSize": {"w":400,"h":400}}},  "meta": {	"image": "bunny.png",	"format": "RGBA8888",	"size": {"w":400,"h":800},	"scale": "1"  }}

I removed some of the irrelevant meta data properties.

you would use the JsonLoader to load the json file. Which inturn loads the bunny.png file
At that point you could use the following:

PIXI.Texture.fromFrame("bunny-0")
PIXI.Texture.fromFrame("bunny-1")

because the JsonLoader would cache those frames into the TextureCache.

The easiest 'DisplayObject' to use for animation is the PIXI.MovieClip.(http://www.goodboydigital.com/pixijs/docs/classes/MovieClip.html#property_textures)

It has a texture array collection and methods for the animation states.

you can get a better example of the MoveClip from PIXI.js git Examples.. if you haven't done so already, download them from github (https://github.com/GoodBoyDigital/pixi.js

If you download the examples individually, you'll probably need download the bin folder as well.. than modify the index.html files to point to where to bin folder containing pixi.js and/or pixi.dev.js. This probably goes without saying.. but eh..


now.. as far as your updateSprite(value) function goes

var TestBaseTexture,    TestSprite;// pretend we initialized those variables using the function earlier. That is, when we loaded the image into the source and constructed the BaseTexture that was assigned to TestBaseTexture// And TestSprite is now a child of stage.function updateSprite(x,y,width,height){  var x = x || 0,      y = y || 0,      width = width || 640,      height = height || 400;  var myNewTexture = new PIXI.Texture(TestBaseTexture, new PIXI.Rectangle(x,y,width,height));  TestSprite.texture = new PIXI.Sprite(myNewTexture);}updateSprite(null,400,null,null);// the last 2 nulls are unnecessary in this call, because they would be null if not specified.

We don't need to manipulate stage if we already have a reference to the object. We also don't need to keep loading the source.

There will be multible texture objects in animations.. don't forget that these objects are yours to overload to...
 

TestSprite.AnimationFrames = [];TestSprite.AnimationFrames.push(TestSprite.texture);

Alternatively...

function updateSprite(sprite,x,y,width,height){  if (sprite) {  var x = x || 0,      y = y || 0,      width = width || 640,      height = height || 400;  var myNewTexture = new PIXI.Texture(TestBaseTexture, new PIXI.Rectangle(x,y,width,height));  if (sprite.AnimationFrames){    sprite.texture = new PIXI.Sprite(myNewTexture);    sprite.AnimationFrames.push(sprite.texture);    sprite.AnimationFrameIndex = sprite.AnimationFrames.length - 1;  } else {    sprite.AnimationFrames = [{sprite.texture}];    sprite.texture = new PIXI.Sprite(myNewTexture);    sprite.AnimationFrames.push(sprite.texture);    sprite.AnimationFrameIndex = sprite.AnimationFrames.length - 1; //will be 1    sprite.LoopAnimation = true;  } }}updateSprite(TestSprite,null,400,null,null);TestSprite.UpdateAnimation = function(){   this.AnimationFrameIndex = (this.AnimationFrameIndex + 1 < this.AnimationFrames.length) ? this.AnimationFrameIndex + 1 : (this.LoopAnimation) ? 0 : this.AnimationFrames.length;   this.texture = this.AnimationFrames(AnimationFrameIndex);   }Animate() {   render.render(stage);   TestSprite.UpdateAnimation();   requestAnimFrame(Animate);}requestAnimFrame(Animate);

EDIT: Note that this animation frame mechanism doesn't have a delay between texture changes.. so it would change textures pretty rapidly.. Also, I really wouldn't alter the PIXI.Sprite object.. I would more likely create my own object where one of the properties was the PIXI.Sprite object.. 

 

var MyMakeShiftObject = { "sprite" : TestSprite, "AnimationFrames" : [{TestSprite.texture}], "LoopAnimation" : true, "AnimationFrameIndex" : 0, "baseTexture" : TestBaseTexture, "AddAnimationFrame" : function(x,y,width,height) {}};

or...

function MakeShiftObject(sprite, baseTexture) {  this.sprite = sprite;  this.AnimationFrames = [{sprite.texture}];  this.LoopAnimation = true;  this.AnimationFrameIndex = 0;  this.baseTexture = baseTexture;  this.AddAnimationFrame = function(x,y,width,height) {};}var MyMakeShiftObject = new MakeShiftObject(TestSprite,TestBaseTexture);

or something like that..

Edited by mrBRC

Share this post


Link to post
Share on other sites

Hey Brett,

 

First, thank you very much for your help, patience and kindness in this matter, I know is hard to take newbie questions some times.

 

Your solutions worked out perfectly and now I'm in the crossroad of which should I pick, either the texture changing in the sprite object or using the movieClip object. Any suggestions on which one is better?.

 

I modified your code a little bit to this at the end (this is for the texture changing on the sprite object):

var source = new Image();source.src = "img/sprite-images.png";var imageAmount = 4,    animationFrames = [],    currentFrame = 0;for(var i = 0; i < imageAmount; i++){  var textureBase = new PIXI.BaseTexture( source, PIXI.scaleModes.LINEAR ),      textureTest = new PIXI.Texture( textureBase, new PIXI.Rectangle(0,(55*i),80,50) );  // in this particular case 50 is the image height and 5 is the gap between each image  animationFrames.push(textureTest);}var testSprite = new PIXI.Sprite(animationFrames[0]);mainStage.addChild(testSprite);

And using the assetLoader:

var loader = new PIXI.AssetLoader(["sprite.test.json"]);var spriteTest,    animationFrames = [],    imageAmount = 4,    currentFrame = 0;//set up the callback when the asset is loaded, in this case the json fileloader.onComplete = loadCompleted;loader.load();function loadCompleted(){  for(var i = 0; i < 4; i++)  {    var newTexture = PIXI.Texture.fromFrame(i);    animationFrames.push( newTexture );  }  spriteTest = new PIXI.Sprite(animationFrames[currentFrame]);  mainStage.addChild(spriteTest);}

Then using any event handler I can update the sprite's texture:

spriteTest.texture = animationFrames[currentFrame];

So basically I can attach the code to Pixi's requestAnimFrame or any other event I want. It could be very useful using advanced UI controls, like sliders or buttons. The great thing is that the movieClip object allows the same control over the animation playback.

 

Again thanks a lot.

 

Cheers,

Rodrigo.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.