Skip to content

Instantly share code, notes, and snippets.

@PrimaryFeather
Created April 19, 2012 17:02
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save PrimaryFeather/2422317 to your computer and use it in GitHub Desktop.
Save PrimaryFeather/2422317 to your computer and use it in GitHub Desktop.
Simple Sprite subclass with a rectangular mask in stage coordinates
package starling.extensions
{
import flash.display3D.Context3D;
import flash.geom.Point;
import flash.geom.Rectangle;
import starling.core.RenderSupport;
import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Sprite;
import starling.errors.MissingContextError;
public class ClippedSprite extends Sprite
{
private var mClipRect:Rectangle;
public override function render(support:RenderSupport, alpha:Number):void
{
if (mClipRect == null) super.render(support, alpha);
else
{
var context:Context3D = Starling.context;
if (context == null) throw new MissingContextError();
support.finishQuadBatch();
support.scissorRectangle = mClipRect;
super.render(support, alpha);
support.finishQuadBatch();
support.scissorRectangle = null;
}
}
public override function hitTest(localPoint:Point, forTouch:Boolean=false):DisplayObject
{
// without a clip rect, the sprite should behave just like before
if (mClipRect == null) return super.hitTest(localPoint, forTouch);
// on a touch test, invisible or untouchable objects cause the test to fail
if (forTouch && (!visible || !touchable)) return null;
if (mClipRect.containsPoint(localToGlobal(localPoint)))
return super.hitTest(localPoint, forTouch);
else
return null;
}
public function get clipRect():Rectangle { return mClipRect; }
public function set clipRect(value:Rectangle):void
{
if (value)
{
if (mClipRect == null) mClipRect = value.clone();
else mClipRect.setTo(value.x, value.y, value.width, value.height);
}
else mClipRect = null;
}
}
}
@felipevex
Copy link

Hi Daniel! You did an amazing job with Starling. THANK YOU VERY MUCH!

So, I'm not a good english speaker but i will try, ok?

I Think i got a problem some problems with the ClippedSprite:

  1. This class has not import for DisplayObject and Point classes.
  2. If you move the ClippedSprite to any position different from origin (0, 0), the clip rectangle will not behave as expected. Can you check please?

Example:
var clip:ClippedSprite = new ClippedSprite();
clip.clipRect = new Rectangle(0, 0, 20, 20);
clip.x = 10;
var image:Image = new Image(SOME TEXTURE)
clip.addChild(image);
starling.stage.addChild(clip);

///////

To make things right i add some code at render() function before setScissorRectangle line:

//////

public override function render(support:RenderSupport, alpha:Number):void
{
if (mClipRect == null) super.render(support, alpha);
else
{
var context:Context3D = Starling.context;
if (context == null) throw new MissingContextError();

            support.finishQuadBatch();

            var realClip:Rectangle = mClipRect.clone();
            var point:Point = this.localToGlobal(new Point(this.x, this.y));
            realClip.x += point.x;
            realClip.y += point.y;

            context.setScissorRectangle(realClip);

            super.render(support, alpha);

            support.finishQuadBatch();
            context.setScissorRectangle(null);
        }
    }

Thank you again!

@PrimaryFeather
Copy link
Author

Hi felipevex!
Thanks a lot for your error report, and for the nice words about Starling!

You're perfectly right, the class was missing two imports. I've added them right away!

As for the wrong position of the clip rectangle: I agree, this is a little misleading. I wrote it in the description of the extension, but it's easy to miss: the clip rectangle is always given in stage coordinates. That's why they don't react as you expected them to.

The reason I made it that way is the following: you can't rotate the clip rectangle; this is a technical limitation of the "scissor rectangle" I'm using here. I thought that when I put the clip rectangle on the stage, this becomes more obvious (you can't rotate the stage, anyway), and it allows you to move the clipped sprite through a stationary clipping area.

I agree that this is not the most intuitive way, though. In the future, Starling will contain real masks that can be rotated and scaled with their objects. And I will consider changing the implementation of the clipped sprite to work different. In the meantime, you've found a solution for your project, anyway! =)

Thanks again!
Best regards,
Daniel

@Absulit
Copy link

Absulit commented Jul 13, 2012

Hi, Im having an issue with the class.

Currently Im working with 320x480 dimensions, and I've managed so it works on multiple devices just as Sony Ericsson and Galaxy Tab 10.1; I test on my computer 320x480, and then deploy to the Galaxy Tab; the clipRect works fine there on my computer and with the Galaxy Tab, but at the time I tested on the Sony Ericsson (480x854) the mask has a displacement; closer the current mask is to the top left is fine, but from that point, the mask moves a bit proportionally

This is the init code on the Main class

var screenWidth:int;
var screenHeight:int;

screenWidth = stage.fullScreenWidth;
screenHeight = stage.fullScreenHeight;

var viewPort:Rectangle = new Rectangle(0, 0, screenWidth, screenHeight);
_starling = new Starling(Game, stage, viewPort);

_starling.stage.stageWidth = 320;
_starling.stage.stageHeight = 480;
_starling.start();

I have a Sprite Class(Masked) wich inside has both, the ClippedSprite instance (_mask) and the Sprite (_item) to be masked;
then I need 9 instances of Masked, all those inside a class Container, and finally Container is added to the Sprite window inside the main Game class; those 9 items are sorted in a grid, each value of the grid is given manually, and both the _item and _maks use those values;
it sounds a little messed up, but the code works locally and with the Galaxy Tab 10.1.

I don't know if the ratio of 320x480 has been broken, but if it is, the other objects in the game also should be misplaced and it is not the case.

I suspect is something with the scale factor, but my factor is 1, so it should not be broken.

I hope you can take a look, thanks in advance.

@PrimaryFeather
Copy link
Author

PrimaryFeather commented Jul 16, 2012 via email

@Absulit
Copy link

Absulit commented Jul 17, 2012

Hi Daniel, thanks for your answer.

The clipRect works great now! but i have a new issue, the "touch area" remains misplaced, so again, far from top left the mask is moved, and near is better placed.

Thanks again for your amazing work with the framework.

@PrimaryFeather
Copy link
Author

Ah, damn, I overlooked that! Now that part works, too. I've reduced some code duplication along the way.
Thanks for the compliments! I'm glad that you chose Starling for your project! =)

Best regards,
Daniel

@Absulit
Copy link

Absulit commented Jul 18, 2012

Hi Daniel, thank you so much, the code works perfectly now!
Thanks again for your work

Sebastian

@PrimaryFeather
Copy link
Author

You're welcome! I'm glad to hear it works now! =)

@David-Luis
Copy link

Hello, I'm trying to use this clipped sprite. I added various Movieclip to it, but, whatever values I put to the clipper rectangle, I always see all the animation (even when width and height of the clipper are 1)

@zenrobin
Copy link

Hi - Thanks for this extension. Useful!
Looks like current implementation doesn't support scale -- if you scale the ClippedSprite, the clipping rect doesn't react as you'd expect (it stays the same size). Children sprites of the ClippedSprite, however, scale as you'd expect.

I'm wondering if translating the desired scale to x and y values and then updating the clipRect is ideal, or if perhaps there's a better way like using a matrix or just resetting the cliprect after the scale is complete - even though visually this wouldn't look correct during the scale.

I'll run some tests and will report back when / if I find a path. Thanks.

@skolesnyk
Copy link

Daniel,

I see the ClippedSprite hasn't been updated for 7 months. Is it still compatible with latest Starling?

@zmarkan
Copy link

zmarkan commented Sep 25, 2013

As of Starling 1.4 there is no need for ClippedSprite anymore, as Sprite class features a clipRect parameter that does the same thing. See http://gamua.com/blog/2013/09/starling-14/ for more info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment