Jump to content
This forum will be closing down. Please move to the respective dedicated project forums.

Is there a way to make a sprite or button in a Slice-9 or Patch-9 way?


Recommended Posts

you'd have to make your own function to build it, using copyRect or some form of bitmap copying routine anyway


If you want the centre part to scale a gradient you're probably better off either starting off with a large image and scaling down or drawing it with graphics linear gradient and caching it.. the problem there in that example though is your left and right edges.. if you're dynamically drawing a gradient you'd probably want to overlay the highlight as a separate PNG. probably simplest to just start with the biggest image you need, take chunks out of it and scale it down.


there's something to start with here, although I haven't tried it and it doesn't seem to give control over the edge width from what I can see.


Link to comment
Share on other sites

Hi, it is easy to render 9-image and there are several solutions. Problem is when you need to scale it or rotate. Most of the solutions suffer from small gaps that will start to appear in the image as it renders the image piece by piece.


If you need solution that does not suffer from this, your best way is to prerender it. You can then scale it (some kind of pop dialog), anchor or rotate it without problem. Of course, non-uniform scale may visually deform corners, but it depends on your implementation - if you have several button that have more or less the same size, then deformation is negligible.


Some time ago I created js class that does this - result is new kind of gameobject (like sprite, bitmaptext, ...): http://www.html5gamedevs.com/topic/14271-9-images-in-phaser/


But 2 days ago I created imho better version in Typescript (full source below). It works like factory and returns texture with prerendered image. Use it like this:

            var nine = Helper.NineImage.create(this.game, DialogLayer.DIALOG_WIDTH, DialogLayer.DIALOG_HEIGHT, "Atlas", "DialogBG", 25, 25, 25, 25, false);            this._bg = new Sprite(aGame, 0, 0, nine.texture)            this._bg.anchor.setTo(0.5, 0.5);               :               :

 Parameters are game, width and height of final image, texture key, texture frame, 9-image borders. Last parameter says whether width and height is in pixels or in number of repeats of central area - handy if you have some pattern and want to display it for example 10x3 times.


 If you want to place text into it then I made another class I am happy with, which wraps bitmap text to given rectangle and even splits it into pages: http://sbcgamesdev.blogspot.cz/2015/02/phaser-tutorial-how-to-wrap-bitmap-text.html


 And here is full source for 9-image class:

module Helper {    export class NineImage {        private static _textureKey = 0;        private static _nineImage: Phaser.BitmapData;        private static _image: Phaser.Image;        private static _frame: Phaser.Frame;        private static _width: number;        private static _height: number;        private static _horizontalRepeats: number;        private static _verticalRepeats: number;        private static _centralWidth: number;        private static _centralHeight: number;        private static _lastWidth: number;        private static _lastHeight: number;        private static _leftWidth: number;        private static _rightWidth: number;        private static _topHeight: number;        private static _bottomHeight: number;        // -------------------------------------------------------------------------        public static create(aGame: Phaser.Game,            aWidth: number, aHeight: number,            aKey: string, aFrame: number | string,            aTop: number = 0, aLeft: number = 0, aBottom: number = 0, aRight: number = 0,            aRepeats: boolean = false): Phaser.BitmapData {            // image            NineImage._image = aGame.cache.getImage(aKey);            // get frame            if (typeof aFrame === "string") {                NineImage._frame = aGame.cache.getFrameByName(aKey, aFrame);            } else {                NineImage._frame = aGame.cache.getFrameByIndex(aKey, aFrame);            }            // calculate dims            NineImage.calculateNineImage(aWidth, aHeight, aTop, aLeft, aBottom, aRight, aRepeats);                        // create nine image bitmap data            NineImage._nineImage = new Phaser.BitmapData(aGame, "NineImage" + (NineImage._textureKey++), NineImage._width, NineImage._height);            // render into bitmap data            NineImage.renderNineImage();                             // return result            return NineImage._nineImage;               }        // -------------------------------------------------------------------------        private static calculateNineImage(aWidth: number, aHeight: number,            aTop: number, aLeft: number, aBottom: number, aRight: number,            aRepeats: boolean): void {            var frame = NineImage._frame;            NineImage._centralWidth = frame.width - aLeft - aRight;            NineImage._centralHeight = frame.height - aTop - aBottom;            if (aRepeats) {                NineImage._horizontalRepeats = aWidth;                NineImage._verticalRepeats = aHeight;                NineImage._width = aLeft + aRight + NineImage._centralWidth * aWidth;                NineImage._height = aTop + aBottom + NineImage._centralHeight * aHeight;                NineImage._lastWidth = 0;                NineImage._lastHeight = 0;            } else {                var w = aWidth - aLeft - aRight;                NineImage._horizontalRepeats = Math.floor(w / NineImage._centralWidth);                NineImage._lastWidth = w % NineImage._centralWidth;                var h = aHeight - aTop - aBottom;                NineImage._verticalRepeats = Math.floor(h / NineImage._centralHeight);                NineImage._lastHeight = h % NineImage._centralHeight;                NineImage._width = aWidth;                NineImage._height = aHeight;            }            NineImage._leftWidth = aLeft;            NineImage._rightWidth = aRight;            NineImage._topHeight = aTop;            NineImage._bottomHeight = aBottom;        }        // -------------------------------------------------------------------------        private static renderNineImage(): void {            var sourceY = NineImage._frame.y;            var destY = 0;            // top row            if (NineImage._topHeight > 0) {                NineImage.renderNineImageRow(NineImage._image, sourceY, destY, NineImage._topHeight);                sourceY += NineImage._topHeight;                destY += NineImage._topHeight;            }            // centrals            for (var i = 0; i < NineImage._verticalRepeats; i++) {                NineImage.renderNineImageRow(NineImage._image, sourceY, destY, NineImage._centralHeight);                destY += NineImage._centralHeight;            }            // last height            if (NineImage._lastHeight > 0) {                NineImage.renderNineImageRow(NineImage._image, sourceY, destY, NineImage._lastHeight);                destY += NineImage._lastHeight;            }            sourceY += NineImage._centralHeight;            // bottom            if (NineImage._bottomHeight > 0) {                NineImage.renderNineImageRow(NineImage._image, sourceY, destY, NineImage._bottomHeight);            }        }        // -------------------------------------------------------------------------        private static renderNineImageRow(aImage: Phaser.Image, aSourceY: number, aDestY: number, aHeight: number) {            var sourceX = NineImage._frame.x;            var destX = 0;                // left            if (NineImage._leftWidth > 0) {                NineImage._nineImage.copy(aImage, sourceX, aSourceY, NineImage._leftWidth, aHeight, destX, aDestY);                destX += NineImage._leftWidth;                sourceX += NineImage._leftWidth;            }            // centrals            for (var i = 0; i < NineImage._horizontalRepeats; i++) {                NineImage._nineImage.copy(aImage, sourceX, aSourceY, NineImage._centralWidth, aHeight, destX, aDestY);                destX += NineImage._centralWidth;            }            // last width            if (NineImage._lastWidth > 0) {                NineImage._nineImage.copy(aImage, sourceX, aSourceY, NineImage._lastWidth, aHeight, destX, aDestY);                destX += NineImage._lastWidth;            }            sourceX += NineImage._centralWidth;            // right            if (NineImage._rightWidth > 0) {                NineImage._nineImage.copy(aImage, sourceX, aSourceY, NineImage._rightWidth, aHeight, destX, aDestY);            }        }    }}
Link to comment
Share on other sites



It's better you to change the lines 64-65:

NineImage._centralWidth = frame.width - aLeft - aRight;NineImage._centralHeight = frame.height - aTop - aBottom;

By this:

NineImage._centralWidth = frame.width - aLeft - aRight;if (NineImage._centralWidth <= 0)    NineImage._centralWidth = 1;NineImage._centralHeight = frame.height - aTop - aBottom;if (NineImage._centralHeight <= 0)    NineImage._centralHeight = 1;

because it's safer if the user misconfigured NineImage (as I did the first time).

Link to comment
Share on other sites


  • Recently Browsing   0 members

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