netcell

Nine Patch Plugin for Phaser

Recommended Posts

So a few months ago I have to deal with the kind of nine patch image. I see that many game engines and app frameworks support this kind of image, but Phaser doesn't. I did google around and found this gist on the thread ninepatch-images-possible-with-phaser. However, the code has some very serious problems:

  1. The class consider the image should be divided in to equals part horizontally and vertically, and we all know that most time, that is not the case;
  2. It creates new texture every time you create new instance of the same nine patch image, that is a big waste of memory and performance;
  3. The code is outdated since there have been so many changes in Phaser in the last few versions, would definitely crash on 2.4;
  4. The nine patch image must be standalone, you cannot load it from a spritesheet or a texture atlas.

I created my own solution, and it works very well in my works. So today I polish the code to share to all of you :)

 

This is the Nine Patch Plugin for Phaser.

 

You can try out the demo on this codepen.

 

For usage, read the readme on the github repository. For more technical details check out this post.

 

The source is available for download from latest release or the github repository or via bower:
bower install --save nine-patch-phaser-plugin

Btw, since Phaser.NinePatchImage actually extends Phaser.Image, so you can do anything that you can do on a Phaser.Image instance with a Phaser.NinePatchImage instance. However, in some cases, like with anchor, you have to run the method UpdateImageSizes afterward for the NinePatchImage to be displayed correctly. Cheers!

 

Share this post


Link to post
Share on other sites

Hi, nice. 9-image is really missing in Phaser and it is really widely used.

 

 Some time ago I created this solution: http://sbcgamesdev.blogspot.cz/2015/05/phaser-tutorial-adding-9-patch-image.html It is made as additional component that is compiled into custom Phaser build. Nowadays I would probably made it in different way (probably as subclass of RenderTexture). It has one nice feature: last parameter says whether width and height parameters are in pixels or in repeats of central part of 9-image. So, it can be used if working with tiled patterns and last column and row in central final area is not cut as it always displays whole central part of 9-image.

 

 Did you try to scale your 9-image? I had problems with my original solution as there were black lines between parts of the image if rendering it piece by piece. In final solution I am pre-rendering it so it can be then scaled without this problem.

 

 Anyway ... I was also missing wrapping of bitmap text that would fit it into rendered 9-image. Here (http://sbcgamesdev.blogspot.cz/2015/02/phaser-tutorial-how-to-wrap-bitmap-text.html) is solution that wraps it and even splits it into pages. So, in conjunction with any 9-image solution it is breeze to create text boxes with bitmap fonts and texts of any length!

Share this post


Link to post
Share on other sites

I have a lot of zoom-bouncy buttons in my game using nine patch and nothing went wrong so I think scaling is fine. I added scale option to the control panel in the codepen, you can try it out :) Since scaling doesn't affect patch's relative position, it gets update in realtime just like measures.

Yes, the repeat option would be nice. I didn't work with that type so I didn't think of that.

I'm not sure if I understand your blog post correctly (I'm reading and editing code on my phone), but your solution is rendering an entire new texture for each component, right? May be I should look into that since it would helps decrease the ammount of sprites for static UI elements. However I would still need to keep the multi-sprite approach since many of my UI elements require dynamic size :D

Share this post


Link to post
Share on other sites

This is what it looks like.  It's fine in chrome.

 

attachicon.gifgaps.jpg

 

Okay, thank you, I'll look into it as soon as I have my VM up and running. Also figure I should check with Firefox on mac too. Gotta go to sleep now though :) In the mean time, if anyone is having the same problem (on the same OS/Browser or not), please tell me :) thank you all :D

Share this post


Link to post
Share on other sites

Just tried it on Ubuntu, firefox has the same problem with gaps, chrome doesn't, but chrome does show a different type of problem (possibly also on windows, didn't notice), look at the corners, looks like sides are being smoothed more than the corners.

 

post-10579-0-49090300-1440758748.jpg

 

You maybe also want to add some protection for the width/height getting too small and negative as other rendering errors occur.

 

I've tried Toms 9-patch a while ago when I was knocking up a GUI that I never finished.  It worked great, pre-rendering to a texture sidesteps all the problems you encounter with misaligned parts, the repeating mode was a nice extra.

Share this post


Link to post
Share on other sites

Just tried it on Ubuntu, firefox has the same problem with gaps, chrome doesn't, but chrome does show a different type of problem (possibly also on windows, didn't notice), look at the corners, looks like sides are being smoothed more than the corners.

 

attachicon.gifgaps2.jpg

 

You maybe also want to add some protection for the width/height getting too small and negative as other rendering errors occur.

 

I've tried Toms 9-patch a while ago when I was knocking up a GUI that I never finished.  It worked great, pre-rendering to a texture sidesteps all the problems you encounter with misaligned parts, the repeating mode was a nice extra.

 

Update: In my test, if the targetWidth/Height is odd, the gaps appear. wow~!

 

I'm not sure what is the problem, though I may have a fix for the gaps by patching some pixels for firefox only. :)

 

I am not having your blurry problem on any of my devices (including: Chrome and Firefox on Windows, Chrome and Safari on Mac and Safari on iPhone) :( Guess I have to spin up another VM for Ubuntu TT_TT

 

Pre-rendering doesn't work so well when you need dynamic UI components, like progress bar, popup,... I am having to work with a lot of dynamic components in my work :(

 

I'll add repeating mode right after fixing the gaps problem, it should be quite easy :).

 

Also, I'll look into caching static part of the nine patch image, like with a progress bar, all the patches on left and right sides are static.

 

I'll add some restriction on the measures, and flip the image when the measures are less then 0;

Share this post


Link to post
Share on other sites

Sounds like it's going to be a part pixel / rounding problem, maybe not 100% fixable given how many devices there are out there.  If you can get it working on only the devices you care about, then be happy with that :-)

 

You hinted in your blog about getting around to releasing othe GUI components when time permits, I'd certainly be interested in looking at that as I've still to either finish my own or adopt an open sourced solution.  I've looked at some others, but GUI's are funny, complicated and diverse - off the shelf solutuions only ever quite provide half the functionality you're after.

Share this post


Link to post
Share on other sites

 Gap problem is really rounding / rendering problem. Part of it can come from rounding and part from way in which OpenGL works (if rendering with WebGL) - with bilinear filtering pixel color is equal to color of pixel in texture only if taken from the very middle of the pixel (https://en.wikipedia.org/wiki/Bilinear_interpolation).

 

 Even the tilemaps in Phaser are prerendered (only the visible part) to:

1) increase performance,

2) avoid these problems

 

 You can scale the prerendered image too, but it is not as nice as if growing in size (not scaling) in your solution. I think, that to achieve this you can:

 1) prerender image,

 2) fake growing with 4 sprites and croping rectangles - make 4 sprites using prerendered texture and crop them to show only needed part,

 3) maybe you will run into the same problems with gaps again if combined with scaling, but you can avoid it by duplicate rendering + overlapping of last column and row for top left part and other parts (if not rendering transparent boxes... it should work)

 

post-12887-0-40345900-1440775315.png

 

 

Hmmm.... you can do ovrlapping in your current solution - if you do not have any complex pattern on your boxes.

Share this post


Link to post
Share on other sites

If your source image is semi transparent then simple overlapping will show up.  It's going to be the big panels that probably won't dynamically resize that will benefit from prerendering.  Are you are using 9-patch for smaller controls, like progress bars?

Share this post


Link to post
Share on other sites

If the image is semi transparent, surely overlaping wouldn't work. I wrote a progressbar class using 3 seperated sprites, but I was going to change to nine patch for cleaner code since caching is possible with cacheAsBitmap. Guess I am just too obsessed with cleaning the code haha. (I'll release a progress bar plugin too)

Actually in my work, my current job is tuning the performance for the games and creating reusable modules/plugins. May be a starry wrapper for a displayobject or a popup or a list view...

However, it has always been like this: the class is a file, copied from project to project, changed on the fly if needed. It is very hard to maintain in such way so I decided to move each of them to a seperated project and repository, preferably installable from bower. And it makes sense to share them with the community. Hell you are already helping me finding out problems :D

@Tom Atom: is it alright to you if I change your code into a prerender mode for the plugin? :)

Share this post


Link to post
Share on other sites

 No, problem :)

 

Thank you, will update soon :)

 

Please make them available from npm too.

 

I'm not really sure what style I should change my codes to fit with npm users (probably browserify/webpack users). Simply publish it on npm just doesn't make sense.

I am using babel and browserify to build my codes, any help?

Share this post


Link to post
Share on other sites

In your implementation, you have committed the following errors:

  • You do not use atlases (very convenient).
  • You create a set of images. is the wrong way. We need to create a bitmap.
  • You repeat the image elements. This will lead to low speed operation at high resolutions. We need to use the fill.

I have long written this functionality for my game (just not in the form of a patch).

Share this post


Link to post
Share on other sites

1. My implementation does accept atlas very well. Even my example page is using atlas :) One of the reason I made this was because the original gist doesn't.

2. I'm not sure I understand, what do you mean by we need to create bitmap, can you provide some example?

3. I know I know, we should prerender the element. I was doing this in order to dynamically change my element size. Also, when the element is static, we can use cacheAsBitmap, would perform well. I think the problem here is only the gaps.

Btw, I was not repeating the image Infact, I was doing what the atlas does: split the image into 9 pieces. (Not sure if I understand you correctly)

Can you share your implementation? :)

Share this post


Link to post
Share on other sites

2. Plugin has to prepare the map for the specified parameters. Then you create an image based on the bitmap. This will simplify positioning and copying.
3. You repeat the central region, to fill the space. It is the most resource-intensive moment. You need to get the color of the central region and perform the fill bitmap.

 

I'm not going to show my code, because it is not designed as a separate module.

Share this post


Link to post
Share on other sites

I am totallt lost. The central region is not repeated, it's scaled, and as answered in a thread recently, it is not an expensive operation at all. The repeat part was an option of Tom's implementation, and even then, he was prerendering so that's only an one time operation :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.