Jump to content

How to keep sprites/rendering and physics separate? (GIF included) ;)


Max
 Share

Recommended Posts

Hi!

 

I'm still pretty new to Phaser and I have some questions on how to keep my code clean.

 

I'm currently working on a little prototype that involves my character sprites to be rotated back and forth slightly for movement animation. This can be seen here (click the image for animation):

 

post-6671-0-24504200-1404780369_thumb.gi

 

To accomplish this, I have the sprite's anchor set to the center bottom (0.5, 1) and then I just manipulate the sprite's rotation in the update function. It works well but an undesired side-effect is: now the character's position is also at center bottom of the sprite. So if I want to position other elements relative to the sprite – i.e. reposition the collision body – I now have to take into account that the character's position is not the intuitive and standard top left. Instead, it's bottom center.

 

It may seem like I'm over-engineering this, but imagine if I want to change the sprite animation at some point – I'd have to change everything that has to do with the position of the sprite because most likely its anchor will change, too.

 

I guess my questions are:

 

1. Is there an easy way to visually rotate a sprite without repositioning its anchor? How?

2. Will I be able to rotate just the image without rotating the physics body? How?

3. Let's say I have another sprite that displays a drop-shadow for my character. This shadow must move and rotate along with the character sprite. Is there an easy way to do this if questions 1 and 2 are answered yes? How?

 

I'm not asking you to write the code for me. If you could just point me to places in the docs/examples or specific sprite methods/attributes that will help me with my problem, that would be greatly appreciated. Thank you very much for your help!   :)

Link to comment
Share on other sites

1. I don't get why it bother you (based on your example now), if you really want the position of the hero on the top left, add a function to him :

[...]getPosition: function(){    //for anchor at (0.5, 1)    return {        x: this.x - (this.width/2),        y: this.y - this.height    }}[...] 

2. Why do you only want to rotate the sprite and not the body ? Collisions will not be good

3. Just bind your hero position and rotation to his shadow so th shadow will move with your player. In the shadow's update :

this.x = hero.x;this.y = hero.y;this.angle = hero.angle;

(something like that). Or if you use P2 you can use a constraint (http://examples.phaser.io/).

 

I'm don't know if there is a better solution (finally pretty new too ^^)

Link to comment
Share on other sites

Thanks for your reply, titmael! :)

 

1. I don't get why it bother you (based on your example now), if you really want the position of the hero on the top left, add a function to him

As I said, changing the anchor point just for animation changes many other implementations in my code. I'm hoping to – in the future – have the body parts of my characters be interchangeable. So I would either need to render them beforehand on a canvas and generate a sprite from BitmapData or the individual body parts would be sprites and need to be positioned relative to my base sprite. If I have a weird anchor point like (0.5, 1) that makes this process a lot more complicated. And if that anchor point changes, I'll have to reimplement all my relative positioning as well as potentially movement code and positioning of the character itself.

I think if there was a translate method then calculating the rotation myself would be pretty straight-forward. I'm struggling to find one on the objects or in the documentation, though.

2. Why do you only want to rotate the sprite and not the body ? Collisions will not be good

I think it might feel weird, it's something I have to try out. I'm currently using Arcade physics, so as far as I know the body doesn't rotate with the sprite anyway.

3. Just bind your hero position and rotation to his shadow so th shadow will move with your player. In the shadow's update

Yeah, that should work with any anchor as long both sprites are the same size. I'm not sure why I thought this part might be a problem. Thanks!

Link to comment
Share on other sites

If you use a null sprite as the topmost container, you can add more sprites (or images if you don't need collision on body parts) to that sprite using sprite.addChild() - each one can then have its own separate anchor and be rotated however you like. Doing it this way, you could have the body positioned with the anchor at the bottom and rotate it to give you your walking animation, and also add a shadow as another child which doesn't rotate. You can position these as needed within the topmost container sprite so that moving the whole lot together gives you a nice relative position.

// container sprite with the physics bodyvar character = game.add.sprite(0, 0, null);game.physics.enable(character, Phaser.Physics.ARCADE);// create the shadowvar shadow = game.add.image(0, 0, 'shadow');shadow.anchor.setTo(0.5, 0.5);// create the bodyvar body = game.add.image(0, 0, 'body');body.anchor.setTo(0.5, 1);// move the shadow down relative to the height of the bodyshadow.y = body.height;// add the shadow first, then the body on topcharacter.addChild(shadow);character.addChild(body);
Link to comment
Share on other sites

If you use a null sprite as the topmost container, you can add more sprites (or images if you don't need collision on body parts) to that sprite using sprite.addChild() - each one can then have its own separate anchor and be rotated however you like. Doing it this way, you could have the body positioned with the anchor at the bottom and rotate it to give you your walking animation, and also add a shadow as another child which doesn't rotate. You can position these as needed within the topmost container sprite so that moving the whole lot together gives you a nice relative position.

I think I'm liking this approach. I'll have to try it out later. I guess if I wanted to change the angle of multiple children together, I could nest them inside another null-sprite and not enable physics on it. I will have to experiment to find out what the implications are. I'll report back when I've tried it out! :)

Link to comment
Share on other sites

I've used this to construct quite detailed characters with different anchor points, offsets and so on. And yeah, you can just keep nesting objects within objects and rotating, moving and scaling them as needed. The only slightly tricky part is in working out what should be nested in what for what you want to do.

Link to comment
Share on other sites

I've used this to construct quite detailed characters with different anchor points, offsets and so on. And yeah, you can just keep nesting objects within objects and rotating, moving and scaling them as needed. The only slightly tricky part is in working out what should be nested in what for what you want to do.

Hey, I just wanted to let you know that I've tried out using child sprites and it works pretty well for composing objects off of different pieces.

Currently I'm still using HTML5 canvas to generate imageData for a character sprite that is composed of a head, a body and a legs sprite. I then pass that generated image over to a different object that generates image data for a slight drop-shadow.

I need to do this, because I don't want to manually create drop-shadows for entities that are not rectangular. This is currently preventing me from attaching individual body parts as child sprites. I'm not sure if there is a more elegant solution because my current method using BitmapData-objects will probably get too resource-intensive once I need to generate character sprites on-the-fly.

Layering the generated shadow and the generated character sprite works really well using your child-sprite-method. For the wiggle-animation where I need to rotate the sprite, I'm thinking of just calculating the rotation manually using rotation matrices. Is there possibly an easy way to apply such matrices to entities?

 

And to get more flexibility I recommand you to use P2 ;) Custom collision shapes, better physics etc

Yeah, I've read about P2, it looks super-powerful. I'll probably use that or Ninja Physics in favor of Arcade physics as soon as I get collision bodies where rotation matters. Thanks for the tipp! :)

Link to comment
Share on other sites

If you want the entire sprite to eventually have a single drop shadow, you could create a BitmapData object and draw the entire composed sprite to it (the top level), which will create a flat duplicated version, then set all of the pixels to black with the appropriate BitmapData methods? It'll not be super fast, and I'm sure there are probably ways of doing this with filters, but whatever way you do it will eventually involve some process of flattening the final composed sprite and turning it into a silhouette to use as a drop shadow.

 

Again I'm doing something similar in mine (though rather than flattening the whole sprite, I'm drawing each piece of the character onto the 'shadow' BitmapData object as I assemble it) but my  shadows are oriented to look like proper shadows rather than flat shadows. I can't show this right now, but I'll be able to post a screenshot or even upload the demo later on if needed.

Link to comment
Share on other sites

If you want the entire sprite to eventually have a single drop shadow, you could create a BitmapData object and draw the entire composed sprite to it (the top level), which will create a flat duplicated version, then set all of the pixels to black with the appropriate BitmapData methods? It'll not be super fast, and I'm sure there are probably ways of doing this with filters, but whatever way you do it will eventually involve some process of flattening the final composed sprite and turning it into a silhouette to use as a drop shadow.

Yeah, this is pretty much what I'm doing. If you're interested, here's my code to generate the shadow sprite:

 

'use strict';var Phaser = require('phaser');var ShadowGenerator = function(game, options) {	this.game = game;	this.options = options;};ShadowGenerator.prototype = {	generateBitmapData: function() {		var image = this.options.image;		var shadowSpread = 8;		var canvasWidth  = image.width + 2 * shadowSpread;		var canvasHeight = image.height + 2 * shadowSpread;		var bitmapData = new Phaser.BitmapData(this.game, null, canvasWidth, canvasHeight);		var context = bitmapData.context;				// offset the sprite so it's not visible on the canvas		var imageOffsetX = canvasWidth;		var imageOffsetY = image.width;		context.shadowColor = 'rgba(0, 0, 0, 0.15)';		context.shadowBlur = shadowSpread;		context.fillStyle = '#fff';		// account for offsetting the sprite so that the shadow is visible		context.shadowOffsetX = -imageOffsetX + shadowSpread;		context.shadowOffsetY = shadowSpread;		context.drawImage(image, imageOffsetX, 0);		return bitmapData;	}};module.exports = ShadowGenerator;

Again I'm doing something similar in mine (though rather than flattening the whole sprite, I'm drawing each piece of the character onto the 'shadow' BitmapData object as I assemble it) but my  shadows are oriented to look like proper shadows rather than flat shadows. I can't show this right now, but I'll be able to post a screenshot or even upload the demo later on if needed.

I'm not sure if I completely understand how this differs from my approach. If you could post a screenshot/demo and it doesn't take up too much of your time, I'm definitely interested. Thanks for your help! :)

Link to comment
Share on other sites

Oh I see, sorry I didn't realise you were using canvas's built-in drop shadow! I'm actually creating shadows totally from scratch by drawing black silhouette versions of the pieces that make up the character onto a BitmapData object, then displaying that at the bottom of the sprite's display list with reduced alpha. The reason being that I want a Zelda-style projection but with somewhat realistic shadows.

 

Yeah no problem, I'll get a demo up later on for you :)

Link to comment
Share on other sites

Oh I see, sorry I didn't realise you were using canvas's built-in drop shadow! I'm actually creating shadows totally from scratch by drawing black silhouette versions of the pieces that make up the character onto a BitmapData object, then displaying that at the bottom of the sprite's display list with reduced alpha. The reason being that I want a Zelda-style projection but with somewhat realistic shadows.

 

Yeah no problem, I'll get a demo up later on for you :)

OK, I see. Looking forward to the demo, thanks a lot man! :)

Link to comment
Share on other sites

Here you go: http://rotates.org/phaser/xv/ 

 

It's very much a proof of concept at the moment, and has some peer.js stuff in it which may throw some errors/warnings in the console, but it lets you see what I was talking about. Use WASD/cursors to move and mouse to aim and fire.

Wow, that player sprite looks very sophisticated. The shadow looks great as well – it makes it almost look like 3D. Great work! Thank you for sharing this and all the help! :)

Link to comment
Share on other sites

It's reasonably simple actually - it has two arms, which are the same sprite flipped, a head, two feet which are again the same sprite flipped, and then some detail sprites for the glow effects. All of that is placed on top of a dynamically assembled shadow. You can see another character here: http://rotates.org/phaser/xv/#server

 

Feel free to look through the source and take whatever you need (except the assets)!

Link to comment
Share on other sites

It's reasonably simple actually - it has two arms, which are the same sprite flipped, a head, two feet which are again the same sprite flipped, and then some detail sprites for the glow effects. All of that is placed on top of a dynamically assembled shadow. You can see another character here: http://rotates.org/phaser/xv/#server

 

Feel free to look through the source and take whatever you need (except the assets)!

The other character looks just as great. Thanks man!

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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