part of sprites; /// A Sprite is a [Node] that renders a bitmap image to the screen. class Sprite extends NodeWithSize { /// The texture that the sprite will render to screen. /// /// If the texture is null, the sprite will be rendered as a red square /// marking the bounds of the sprite. /// /// mySprite.texture = myTexture; Texture texture; /// If true, constrains the proportions of the image by scaling it down, if its proportions doesn't match the [size]. /// /// mySprite.constrainProportions = true; bool constrainProportions = false; double _opacity = 1.0; /// The color to draw on top of the sprite, null if no color overlay is used. /// /// // Color the sprite red /// mySprite.colorOverlay = new Color(0x77ff0000); Color colorOverlay; /// The transfer mode used when drawing the sprite to screen. /// /// // Add the colors of the sprite with the colors of the background /// mySprite.transferMode = TransferMode.plusMode; TransferMode transferMode; /// Creates a new sprite from the provided [texture]. /// /// var mySprite = new Sprite(myTexture) Sprite([this.texture]) { if (texture != null) { size = texture.size; pivot = texture.pivot; } else { pivot = new Point(0.5, 0.5); } } /// Creates a new sprite from the provided [image]. /// /// var mySprite = new Sprite.fromImage(myImage); Sprite.fromImage(Image image) { assert(image != null); texture = new Texture(image); size = texture.size; pivot = new Point(0.5, 0.5); } /// The opacity of the sprite in the range 0.0 to 1.0. /// /// mySprite.opacity = 0.5; double get opacity => _opacity; void set opacity(double opacity) { assert(opacity != null); assert(opacity >= 0.0 && opacity <= 1.0); _opacity = opacity; } void paint(RenderCanvas canvas) { canvas.save(); // Account for pivot point applyTransformForPivot(canvas); if (texture != null) { double w = texture.size.width; double h = texture.size.height; if (w <= 0 || h <= 0) return; double scaleX = size.width / w; double scaleY = size.height / h; if (constrainProportions) { // Constrain proportions, using the smallest scale and by centering the image if (scaleX < scaleY) { canvas.translate(0.0, (size.height - scaleX * h) / 2.0); scaleY = scaleX; } else { canvas.translate((size.width - scaleY * w) / 2.0, 0.0); scaleX = scaleY; } } canvas.scale(scaleX, scaleY); // Setup paint object for opacity and transfer mode Paint paint = new Paint(); paint.color = new Color.fromARGB((255.0*_opacity).toInt(), 255, 255, 255); if (colorOverlay != null) { paint.setColorFilter(new ColorFilter.mode(colorOverlay, TransferMode.srcATop)); } if (transferMode != null) { paint.setTransferMode(transferMode); } // Do actual drawing of the sprite if (texture.rotated) { // Calculate the rotated frame and spriteSourceSize Size originalFrameSize = texture.frame.size; Rect rotatedFrame = new Rect.fromPointAndSize(texture.frame.upperLeft, new Size(originalFrameSize.height, originalFrameSize.width)); Point rotatedSpriteSourcePoint = new Point( -texture.spriteSourceSize.top - (texture.spriteSourceSize.bottom - texture.spriteSourceSize.top), texture.spriteSourceSize.left); Rect rotatedSpriteSourceSize = new Rect.fromPointAndSize(rotatedSpriteSourcePoint, new Size(originalFrameSize.height, originalFrameSize.width)); // Draw the rotated sprite canvas.rotate(-Math.PI/2.0); canvas.drawImageRect(texture.image, rotatedFrame, rotatedSpriteSourceSize, paint); } else { // Draw the sprite canvas.drawImageRect(texture.image, texture.frame, texture.spriteSourceSize, paint); } } else { // Paint a red square for missing texture canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width, size.height), new Paint()..color = const Color.fromARGB(255, 255, 0, 0)); } canvas.restore(); } }