CanvasQuery
CanvasQuery copied to clipboard
Sprites in Playground
What would be your expectation regarding rendering sprites in Playground. Preferably write example USAGE in real code.
TL;DR
The problem is that there are many solutions to render sprites/animations.
A sprite rendering would have to support these (or is this is not what you expect?):
- texture atlas
- fixed grid
- scale, rotation, align
- DURATION
I've put emphasis on DURATION because it implies having time delta somewhere - and that's where the thing gets nasty as this clearly leverage Playground beyond unobtrusive core architecture that deals with display and input only.
On top of that - it's really hard to achieve that with functional (rather than objective) approach without sacrificing readability - and I don't really want to go with objects because it's pushing playground towards tightly coupled engine (like Phaser).
That's the minimal form for a functional sprite rendering. It requires you to have a sprite
defined somewhere earlier.
renderSprite(app.sprites.tank, x, y, delta);
app.sprites.tank = {
image: "tank",
frames: 16,
width: 32,
height: 32,
alignX: 0.5,
alignY: 0.5,
duration: 0.4
};
- What about loops?
- What about events? (state finished) - useful for coupling with game logic
I really think that having your own sprite object is more convenient than functional approach - and for rendering you just use layer.drawRegion
So now I am thinking more about providing just two methods to extract frame from textureAtlas and fixed-size spritesheet - something like more advanced version of layer.drawRegion
While sprite rendering in Playground would be nice, maybe it's more suited to a plugin or a bit of example code provided for users' reference but not included in playground.js itself.
I agree with pretty much everything you said about the objective versus functional approach. Keeping track of the time elapsed in order to calculate which frame to render implies an objective approach, which doesn't seem to fit well with the rest of playground.js.
A function to grab a frame from a fixed-size spritesheet would be handy for a lot of purposes.
grabSprite( app.images.spriteSheet, frameWidth, frameHeight, frameNumber );
What would the function for grabbing a frame from a textureAtlas look like? (I'm not understanding how it would differ from drawRegion.)
For a textureAtlas I believe we would first have to add some kind of a loader - as for atlas there usually come JSON file with frames positions, original frame size before truncation and so on.
However there is not an industry standard... except the ugly one that comes from flash - but let's leave that for a moment.
this.loadTextureAtlas("something");
/* ... */
var sprite = this.layer.grabFromTextureAtlas(atlas, frame);
This would give you solely sprite data (frame size etc) and you would have to use it manually with scale
, rotate
, and drawRegion
considering desired align.
Otherwise we would have this tremendous function:
this.layer.drawFromTextureAtlas(image, atlas, frame, x, y, alignX, alignY, rotate, scale);
And still - you'd have to manage frame number (delta) manually - that's why I think that implementing sprites does not go well with functional approach.
I kind of agree with @nknauth about not having sprite support in playground. Apart from the problems already mentioned, what I love about Playground/Canvasquery is its functional approach, simplicity and low level aproach, which gives me the freedom to play and adapt the library to the needs of the app/game.
I do think Atlas support would be convenient, though.. the first approach (the pair loadTextureAtlas() grabFromTextureAtlas()
--maybe loadAtlas(), getAtlasFrame()
? ), looks nice.
Mmm.. what about an additional class, separated from Playground, to handle sprites? a Sprite class decoupled from playground.
Sprite{
//public properties
x, y, rotation, scalex, scaley, alignX, alignY, animations,
//public methods
function play('anim_id', loop, speed|fps);
function step(delta);
function draw(framebuffer | func);
}
It would handle atlas parsing and frame handling. framebuffer
would be a canvasquery (or canvas) object where to draw to. It would be nice if it could support a custom function for the actual drawing, once the 2d transform and other pre-draw stuff is prepared. Inside, draw could be:
function draw(func)
{
//2d transform, stuff..
func( /* all parameters needed for a custom draw, like the texture, final position, etc. */);
//undo transform and stuff..
}
or if this is too dirty, just add properties to the Sprite to customize the render of it, like alpha, drawMode, hls, hlsoffset...
step()
would handle the animation, based on current animation (set by play()
), and the specified delta time.
animations
would be an array of {id:'walk', anim: [2, 3, 4, 4, 4, 10, 5], fps:1}
and, not much more. But above all, for me the most important feature of a sprite class would be the 2d transforms handling.
Don't know if all this is silly or has any sense.. sorry :P
I wonder if it could be interesting to have the Sprite class totally decoupled from Playground and CanvasQuery.. hmm.. It would be quite a thing..
Thanks for feedback guys.
I agree that cq and playground should stay decoupled from the object model.
I have to use these "standard" texture atlases in the next project so expect some loader in the next iteration of playground.
Then I will see if there is a possibility to put some drawing helpers for them in cq.
So far so good.
http://gfycat.com/FarawayPlushDuckbillplatypus
this.loadAtlases("planet");
Rendering manually is pretty easy. Wondering if there is even a need for any helper method.
var atlas = app.atlases.planet;
var frame = atlas.frames[this.currentFrame];
app.layer.drawRegion(atlas.image, frame.region, this.x + frame.offset[0], this.y + frame.offset[1]);
Of course you have to manage currentFrame
based on atlas.frames.length
and delta
time.
Looks perfect! :))
http://canvasquery.com/playground-atlases
also check Release Notes
We could have something like common repository for "universal" elements like sprites. I am using pretty much same sprite object as @feiss described
Also get ready for rebranding - this will not affect your code in any way - but I am getting rid of Query in CanvasQuery - it scares of all the professionals.
? don't understand what do you mean with that repository.. something like a heterogenous this.resources
hash object?
Noes, something completely separated from playground code itself - kind of a website or repo, where you can throw a "sprite class" and redirect people there.
Oh, nice. Something like code snippets for playground/canvaswhatever. Could help a lot to newbies, and a perfect place for plugins..
Today I have came up with this:
this.layer.save();
this.layer.align(0.5, 0.5);
this.layer.translate(100, 100);
this.layer.drawAtlasFrame(atlas, current, 0, 0);
this.layer.restore();
Without align it would look like this:
var atlas = app.atlases.planet;
var frame = atlas.frames[this.currentFrame];
this.layer.save();
this.layer.translate(100, 100);
this.layer.drawAtlasFrame(atlas, current, - frame.width * 0.5, - frame.height * 0.5);
this.layer.restore();
Guess we can also introduce Spritesheet
- same thing as atlas except for tilesets with fixed size frames.
align
doesn't change anything about Canvas vs CQ compatibility - so I consider it optional
drawAtlasFrame
requires playground
but who uses cq separately anyway.
who uses cq separately anyway
/me raises hand (just for a personal hobby project, nothing serious)
I will consider moving images and atlas loaders to cq.
oh please, don't bother to think about it because of my last stupid comment. It just a stupid little project in which I don't need playground, that's it..
Images and atlas loaders fit very well in playground, it is the natural place for them (although --don't hit me, just rambling-- it also has sense that a Layer could know how to load itself..)