Skip navigation
mferus
Currently Being Moderated

Is it possible to add texture (image fill) to a line drawn with graphics.lineTo()?

May 15, 2009 11:57 AM

I am trying to draw a  line from x1, y1 to x2,y2 and i want it to be a line that repeats a pattern from an image. All I can see is that you can only draw lines and change their color or thickness but I would like it to repeat an image. Is that possible or do i have to use a really long and thin rectangle with a bitmap fill?
The problem is I am making a game where the user will be able to actually draw the line so i have to make it be created dynamically.
The game fantastic contraption (www.fantasticcontraption.com) has in the game a feature where you draw lines of any length and position that are filed with a picture.

Any help is appreciated. Thanks!!

  • Currently Being Moderated
    Community Member
    May 15, 2009 12:45 PM

    a line can't "contain" an image.  you can create images by changing the colors used in your lines.  for example:

     

    www.kglad.com , click on snippets, click on mandelbrot.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 3:35 PM

    there's a lineGradientStyle that you can use but that's not what's being used at fantasticcontraption.  they look like they're using a movieclip that contains a mask and the movieclip is rotated and the mask is scaled with mouse movement.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 8:01 PM

    Actually you can do this natively in the drawing API, but only from flash player 10.

     

    There are two ways to do it.

     

    The old API style in fp10, with the new bitmap stroke:

     

    http://help.adobe.com/en_US/AS3LCR/Flash_10.0/flash/display/Graphics.h tml#lineBitmapStyle()

     

     

    or


    using the IGraphicsData object approach:

    create a GraphicsStroke

    and assign its fill to be a new GraphicsBitmapFill

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 9:01 PM

    A dashed line is more complicated and requires the data for the drawing path which is iterated along its length to draw shorter segments, switching the stroke on and off for each one. Easy for straight lines, a bit more complicated for curves etc.

     

    Here's an example (in Flex, using Degrafa - just for illustrative purposes, I know you are doing this in flash, not flex, so its not directly applicable) with a dashed line.The stroke style here is a gradient style, we haven't implemented the fp10 bitmap stroke in degrafa yet:

    http://degrafa.org/source/HappyHolidays/HappyHolidays.html

     

    The underlying Degrafa code for the dashed line is basically doing what I described above.

    http://code.google.com/p/degrafa/source/browse/branches/Origin/Degrafa /com/degrafa/decorators/standard/SVGDashLine.as

     

    This code handles curves and arbitrary dash on and off patterns, as well as being specific to work with the Degrafa rendering flow...so it's probably a lot more complex than you'd be looking for, but the general idea is to measure each segment making up your drawing line, (pythagoras if its only linetos) and then break up into pieces the length of your dash on and dash off requirements. You may need to combine the end of one segment with the start of the next one, for example. You switch the lineStyle off with graphics.lineStyle() (i.e. no arguments)  and then switch it back on with regular arguments. You can also use moveTo to make gaps in the line but only if you don't need to use a fill, otherwise you must draw the null stroked segments with lineTos for the fill to work correctly.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 9:18 PM

    that's pretty cool.

     

    but it's not what they're using at fantasticcontraptions.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 9:32 PM

    @kglad you're right, thanks for pointing it out - that is different, I had just interpreted the questions in the text here. I did check out the link earlier but I tend to be impatient with links if I can't see the thing I'm supposed to see straight away. I took another look now and I see (I think) what is meant....the animated blue line with the white 'stroke' and the wooden branch 'stroke'.

     

    I would still be inclined to do something like this with the drawing api.

     

    The same type of approach as the dashline could be used for any type of line decoration along a drawing path if you treat the path as data. It just needs to be drawn slightly differently and redrawn on a frame loop if its animated. If they're doing it that way too, I don't know from looking at it whether the animated blue line is a filled shape or whether the white outline is a filter and the blue part is just a the (frame animated) drawn line.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 9:44 PM

    i think i could create that blue line (water rod) using a movieclip (of an animated horizontal long blue line) that contains a child mask movieclip that masks the blue animated line.  by rotating the main movieclip and than sizing the mask i could create that effect.

     

    the wood rod could be easily done using the lineBitmapStyle() method.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 15, 2009 9:59 PM

    yes both those ways could work. I often find myself veering towards code and thinking less about the timeline when I should be.

     

     

    I think on both counts you could also actually do what the OP suggested in the first post:

     

    Draw a shape that represents a rotated rectangle that runs along the line segment with no stroke and a bitmapFill with a repeat = true and the fill's matrix rotated to orient in the correct direction

     

    use the same bitmapData for all the fills, with matching edges for continuity when repeated

    one for the branch

    one for the blue stroke

     

    for the animated blue line, just animate the single instance of the blue stroke bitmapdata by scrolling its pixels.

     

    I think that would also work and be pretty lightweight.

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 16, 2009 12:43 AM

    I just threw together a quick proof of concept for the last technique I described...using some similar to the branch image from that earlier link. The swf is attached. Just click around the stage.

     

    I didn't get too sophisticated here.... so no mouse dragging of the circles  etc although that would be easy to add in.

     

     

    Once its drawn via the drawing API its basically just the native renderer that get's sluggish with the animation updates if you add too much. All the bitmapdata transformations are being done at the native level for the updates, but it can get quite cumbersome/cpu intensive if you put too much on stage. I suspect it might be faster under these conditions if the drawn content was vector data, because you can loop through thousands of drawing commands very quickly.

     

     

    BranchBitmap is a library bitmap set to export on frame 1 with BranchBitmap as the class name.

     

    The code for this is :

     

     

    var segments:Sprite=new Sprite()
    addChild(segments)
    var connectors:Sprite = new Sprite();
    addChild(connectors);
    
    var points:Array=[];
    
    stage.addEventListener(MouseEvent.CLICK, clickhandler)
    stage.addEventListener(Event.ENTER_FRAME,frameupdater);
    
    
    function clickhandler(e:MouseEvent):void{
        points.push(new Point(e.stageX,e.stageY));
        connectors.graphics.beginFill(0xff0000,.8);
        connectors.graphics.drawCircle(e.stageX,e.stageY,15);
        drawNewSegment()
    }
    var lastPoint:Point;
    var scrollwidth:uint=2;
    
    
    var branchBitmapData:BitmapData = new BranchBitmap(247,52);
    var scrollpixels:BitmapData = new BitmapData(scrollwidth,branchBitmapData.height)
    
    function frameupdater(e:Event):void{
        branchBitmapData.lock();
        var rect:Rectangle = branchBitmapData.rect;
        rect.x=branchBitmapData.width-scrollwidth;
        rect.width=scrollwidth;
        scrollpixels.copyPixels(branchBitmapData,rect,new Point(0,0))
        branchBitmapData.scroll(1,0)
        branchBitmapData.copyPixels(scrollpixels,scrollpixels.rect,new Point(0,0))
        branchBitmapData.unlock();
    }
    function drawNewSegment():void{
        
        if (points.length>1){
            if (!lastPoint) lastPoint= points[0];
            var latestPoint:Point = points[points.length-1];
            var diff:Point = latestPoint.subtract(lastPoint);
            var angle:Number = Math.atan2(diff.y,diff.x);
            var baseRectangle:Rectangle = new Rectangle (lastPoint.x, lastPoint.y-branchBitmapData.height/2,Point.distance(lastPoint,latestPoint),branchBitmapData.height);
            var drawingPoints:Array=[];
            var drawingMatrix:Matrix = new Matrix();
            var bitmapMatrix:Matrix=new Matrix();
            bitmapMatrix.translate(0,-branchBitmapData.height/2)
            drawingMatrix.translate(-lastPoint.x,-lastPoint.y);
            drawingMatrix.rotate(angle);
            bitmapMatrix.rotate(angle);
            drawingMatrix.translate(lastPoint.x,lastPoint.y);
            bitmapMatrix.translate(lastPoint.x,lastPoint.y);
            //DEBUG: segments.graphics.lineStyle(0,0,1);
            segments.graphics.beginBitmapFill(branchBitmapData,bitmapMatrix,true,true)
            var p:Point = drawingMatrix.transformPoint(baseRectangle.topLeft);
            var sp:Point =p;
            segments.graphics.moveTo(p.x,p.y);
            p=drawingMatrix.transformPoint(new Point(baseRectangle.bottomRight.x,baseRectangle.y));
            segments.graphics.lineTo(p.x,p.y);
            p=drawingMatrix.transformPoint(baseRectangle.bottomRight);
            segments.graphics.lineTo(p.x,p.y);
            p=drawingMatrix.transformPoint(new Point(baseRectangle.x,baseRectangle.bottomRight.y));
            segments.graphics.lineTo(p.x,p.y);
            segments.graphics.lineTo(sp.x,sp.y);
            lastPoint= latestPoint
            
        }
        
    }
    
    Attachments:
    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 16, 2009 4:54 AM

    It looks like the uploads take ages in a 'QUEUED' state, here is the swf and fla as download links, if you want to take a look:

     

    Demo (click around)

    http://www.interactionscript.com/adhoc/drawingAPI.swf

     

    Download fla (CS3):

    http://www.interactionscript.com/adhoc/drawingAPI.fla

    |
    Mark as:
  • Currently Being Moderated
    Community Member
    May 17, 2009 4:56 PM

    You're welcome.

     

    That last part is the easy part   - you just need to redraw the segment between the last point and the current point on mouse move. For performance reasons it's probably best to split the segments out into individual Shape instances inside the segments Sprite , so you're only updating the drawing commands in the last added Shape object.

     

    I don't have cs4 yet either. But if you need to code for fp10 and you're using windows you can do code-only projects (no timeline) with FlashDevelop.

    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points