AS3: setting registration point of a DisplayObject with actionscript?

26,117

Solution 1

The Flash Player API doesn't expose this. I believe this is because Flash actually bakes in the registration point into the shape data when it creates the SWF. Thus, there's no actual registration point to move (instead, you'd move the shape data... if the Flash Player let you edit shape data!).

I always solve this by simply parenting my sprite/shape to another DisplayObject. So, if I have spriteA and want to set its registration point to (15, 35), I'd do this:


var spriteB:Sprite = new Sprite();
spriteB.addChild(spriteA);
spriteA.x = 15;
spriteA.y = 35;

And then from then on refer to spriteB everywhere I was previously referring to spriteA.

Solution 2

Using transform matrix this is possible. Here is a good implementation of this found on this site.

public function setRegistrationPoint(s:Sprite, regx:Number, regy:Number, showRegistration:Boolean )
{
    //translate movieclip 
    s.transform.matrix = new Matrix(1, 0, 0, 1, -regx, -regy);

    //registration point.
    if (showRegistration)
    {
        var mark:Sprite = new Sprite();
        mark.graphics.lineStyle(1, 0x000000);
        mark.graphics.moveTo(-5, -5);
        mark.graphics.lineTo(5, 5);
        mark.graphics.moveTo(-5, 5);
        mark.graphics.lineTo(5, -5);
        s.parent.addChild(mark);
    }
}

Solution 3

to you mean the index ?

Following up the comments, you can do a quick implementation like below. This is not exactly what you want as you cannot set different alignments for each child. I just didn't want to make it too complicated, it's more like 'working-pseudo-code' to give you an idea ...

package  
{
    import flash.display.DisplayObject;
    import flash.display.Sprite;    


    public class SpriteWithRegistration extends Sprite 
    {

        private var _regV:String = "T";
        private var _regH:String = "L";

        private var _width:Number = 0;
        private var _height:Number = 0;


        public function SpriteWithRegistration(width:Number, height:Number, registrationPoint:String = "TL")
        {
            this.width  = height;
            this.height = width;
            this.registrationPoint = registrationPoint;
        }

        public function set registrationPoint(p:String):void
        {
            if(p.length != 2) return;

            var regV:String = p.toUpperCase().substr(0, 1);
            var regH:String = p.toUpperCase().substr(1, 1);

            _regV = (regV == "T" || regV == "C" || regV == "B" ) ? regV : _regV;
            _regH = (regH == "L" || regH == "C" || regH == "R" ) ? regH : _regH;

            alignChildren();
        }

        override public function addChild(child:DisplayObject):DisplayObject
        {
            alignChild(child);
            super.addChild(child);
            return child;
        }

        override public function set width(value:Number):void
        {
            _width = value;
            alignChildren();
        }

        override public function get width():Number
        {
            return _width;
        }

        override public function set height(value:Number):void
        {
            _height = value;
            alignChildren();
        }

        override public function get height():Number
        {
            return _height;
        }

        private function alignChildren():void
        {
            for(var index:int = 0;index < numChildren; index++ )
                alignChild(getChildAt(index));
        }

        private function alignChild(disp:*):void
        {
            switch(_regH)
            {
                case "L":   disp.x = 0;                             break;
                case "C":   disp.x = _width*.5 - disp.width * .5;   break;
                case "R":   disp.x = _width - disp.width;           break;
            }

            switch(_regV)
            {
                case "T":   disp.y = 0;                             break;
                case "C":   disp.y = _height*.5 - disp.height * .5; break;
                case "B":   disp.y = _height - disp.height;         break;
            }
        }
    }
}

Solution 4

I'm hoping this will help someone. The Starling framework has a fantastic method called, "alignPivot()". I took their concept and adapted it to the Flash DisplayList. You essentially tell a sprite to change it's registration to left, right, center, top and bottom. This code places your sprite into a container sprite and positions itself appropriately. It returns the container sprite with the original sprite contained inside.

Code stored in a separate called called, "Position".

    public static function alignPivot(s:DisplayObject, horizontalAlign: String = "center", verticalAlign: String = "center", showRegistration: Boolean = false, _color: uint = 0x000000): Sprite {

        //create a container sprite to house the sprite you'd like to move
        var _container: Sprite = new Sprite();
        //add your sprite to the continer sprite (the container sprite is what will be returned)
        _container.addChild(s);
        //using getBounds(), find the x,y,width,and height of your sprite within the continer.
        var bounds:Rectangle = _container.getBounds(s);
        //create variables for x and y cooridnates
        var xVal: Number;
        var yVal: Number;

        //I have a separate class called Align which contains public static constants for positiong.
        //Check the values passed above and get the correct x value;
        if (horizontalAlign == Align.LEFT) xVal = -bounds.x;
        else if (horizontalAlign == Align.CENTER) xVal = -bounds.x - bounds.width * .5;
        else if (horizontalAlign == Align.RIGHT) xVal = -bounds.x - bounds.width;
        else throw new ArgumentError("Invalid horizontal alignment: " + horizontalAlign);

        //Check the values passed above and get the correct y value;
        if (verticalAlign == Align.TOP) yVal = -bounds.y;
        else if (verticalAlign == Align.CENTER) yVal = -bounds.y - bounds.height * .5;
        else if (verticalAlign == Align.BOTTOM) yVal = -bounds.y - bounds.height;
        else throw new ArgumentError("Invalid vertical alignment: " + verticalAlign);

        //apply the new x and y cooridnates to your sprite (the one moving within the container we created above)
        s.x = xVal;
        s.y = yVal;

        //optional - this will create a small X at the 0,0 position of the container.
        //This is helpful if you want to see where your registration points are
        if (showRegistration) {
            var mark: Sprite = new Sprite();
            mark.graphics.lineStyle(1, _color);
            mark.graphics.moveTo(-5, -5);
            mark.graphics.lineTo(5, 5);
            mark.graphics.moveTo(-5, 5);
            mark.graphics.lineTo(5, -5);
            _container.addChild(mark);
        }
        //return your contianer sprite
        //This will replace the sprite that you passed in the first parameter.
        //That sprite is inside the container, so you won't notice
        return _container;


    }

Implementation:

//Create your sprite
        var _holder: Sprite = new Sprite();
    //Create a shape to put in your sprite
        var my_shape: Shape = new Shape();
        my_shape.graphics.beginFill(0x000000);
        my_shape.graphics.drawRect(0, 0, 200, 100);
        my_shape.graphics.endFill();
    //Add the shape to your sprite
        _holder.addChild(my_shape);
    //Align the holder (must be done AFTER all children have been added)
    //This will put the registration point at the top-center of the sprite. 
    //_holder is replaced by a sprite (container) that contains _holder.
    //The _holder inside the container is positioned appropriately.
    _holder = Position.alignPivot(_holder,Align.CENTER, Align.TOP);
    //Add the new sprite to your stage.
    this.addChild(_holder);

List of constants so you don't have to write them yourself:

    public static const CENTER:String = "center";
    public static const LEFT:String = "left";
    public static const RIGHT:String = "right";
    public static const TOP:String = "top";
    public static const BOTTOM:String = "bottom";
Share:
26,117
Ronn
Author by

Ronn

Updated on October 27, 2020

Comments

  • Ronn
    Ronn over 3 years

    How would you set the registration point on a Sprite or Shape via actionscript (I know this is trivial using Flash, but I need to do it purely in actionscript)

  • Theo.T
    Theo.T about 15 years
    BTW, there's no default implementation for that for sprites and shapes. Which makes sense as it will depend totally on how your object sized. The best is to use an UI framework or build your own one. The idea being to specify the size of the holder and the alignments of the children.
  • Marco Luglio
    Marco Luglio about 15 years
    This is definitely the easiest and simplest way. Not the most elegant though. Bu if the overhead of having an extra container is not an issue...
  • Vishnu
    Vishnu over 12 years
    Can you explain this more in detail, Please ?
  • oxygen
    oxygen over 8 years
    Link is dead. Perhaps explaining it better was a good thing to do.