Draw canvas clip() weirdness

54 views
Skip to first unread message

dola...@hotmail.com

unread,
Aug 1, 2013, 11:41:57 PM8/1/13
to mel...@googlegroups.com
Hi, I've been using Melon for sometime now for my final year dissertation, and I've got to say I love it! 
However, I am coming across some problems
I am trying to make a radar/minimap on the top of my screen, something like this:


Good news is, I have done most of the code, and it works.. 90%. The problem is masking the context using the context.clip() function. It's masking some objects and not the cone. Look at the picture for an explanation

In my version, the yellow lines get cut nicely, however, the green cone protrudes outside the map!

Here is my code for the draw section of the HUD_Item:

    draw: function (context) {
        context.fillStyle = "rgba(0, 0, 0, 0.5)";
        context.fillRect(this.pos.x, this.pos.y, this.rect.width, this.rect.height);
        context.rect(this.pos.x, this.pos.y, this.rect.width, this.rect.height);
        context.clip();

        var xOffset = this.centrePoint.x - (this.focusedEntity.pos.x / me.game.currentLevel.tilewidth);
        var yOffset = this.centrePoint.y - (this.focusedEntity.pos.y / me.game.currentLevel.tileheight);

        context.fillStyle = "#FFF000";
        context.fillRect(this.focusedEntity.pos.x / me.game.currentLevel.tilewidth + xOffset, this.focusedEntity.pos.y / me.game.currentLevel.tileheight + yOffset, 1, 1);

        for (var j = 0; j < this.entities.length; j++) {
            var x = this.entities[j].pos.x / me.game.currentLevel.tilewidth + xOffset;
            var y = this.entities[j].pos.y / me.game.currentLevel.tileheight + yOffset;
            context.fillStyle = "#FFF000";
            context.fillRect(x, y, 1, 1);
            if (this.entities[j].faceDirection) {
                var grd = context.createRadialGradient(x, y, 0, x, y, 80);
                grd.addColorStop(0, "rgba(152,212,23,0.6)");
                grd.addColorStop(1, "rgba(152,212,23,0)");
                context.beginPath();
                context.arc(x, y, 70, this.entities[j].faceDirection - 1, this.entities[j].faceDirection + 1, false);
                context.lineTo(x, y);
                context.closePath();
                context.fillStyle = grd;
                context.fill();
            }
        }
        context.clearRect(this.pos.x, this.pos.y, this.rect.width, this.rect.height);
        var collisionlayer = me.game.currentLevel.getLayerByName("collision").layerData;
        for (var i = 0; i < collisionlayer.length; i++) {
            for (var j = 0; j < collisionlayer[i].length; j++) {
                if (collisionlayer[i][j] != null) {
                    context.fillStyle = "#FFF000";
                    context.fillRect(i + xOffset, j + yOffset, 1, 1);
                }
            }
        }
        this.parent(context);
    },
});

 The cone part is highlighted in yellow


Thanks a bunch!


melonJS

unread,
Aug 2, 2013, 12:00:04 AM8/2/13
to mel...@googlegroups.com, dola...@hotmail.com
I don't have that much experience with clip() to be honest, but the few times i tried, I never used closePath(), but I was however saving the context and restoring it after i finished playing with it. maybe that's what you are missing ?

melonJS

unread,
Aug 2, 2013, 12:01:02 AM8/2/13
to mel...@googlegroups.com, dola...@hotmail.com
the screenshots look great by the way, i' looking forward seeing your game once finished !


On Friday, August 2, 2013 11:41:57 AM UTC+8, dola...@hotmail.com wrote:

dola...@hotmail.com

unread,
Aug 2, 2013, 12:44:37 AM8/2/13
to mel...@googlegroups.com, dola...@hotmail.com
Thank you! I have tried saving and restoring the context, and it doesnt change a thing. One thing I have found out is that if I use a box instead of the cone, then it will behave as intended? So is it the cone's fault? And if so, I am not sure what I am doing wrong with the cone

Jay Oster

unread,
Aug 2, 2013, 1:46:53 AM8/2/13
to mel...@googlegroups.com, dola...@hotmail.com
Hi!

I just wrote a minimal test case, and it works as expected: http://jsfiddle.net/5Z82J/1/

The only thing I did differently is added `context.beginPath()` before the `context.rect()` used for the clipping region. Without that, the rectangle gets "merge" with any previous path, and that final path is what the clipping region will be. (Try it on the jsFiddle! Commenting the beginPath will turn the "non-clipped" cone black, because it becomes part of the clipping region with reverse winding!)

Also, don't forget to save the context before clipping, and restore after you are done drawing inside the clipping region!

dola...@hotmail.com

unread,
Aug 2, 2013, 11:27:56 AM8/2/13
to mel...@googlegroups.com, dola...@hotmail.com
Solved! I followed Jay's fiddle and it now works perfectly!

Thanks everyone!
Reply all
Reply to author
Forward
0 new messages