Oltier
Oltier

Reputation: 15

Canvas 2D maze torch effect

I am working on a school project that includes these conditions:

I started making this game with the use of canvas. I have succeeded to make a torch effect around the character as shown here:

http://people.inf.elte.hu/tunyooo/web2/HTML5-Maze.html

However, I cannot make it NOT to light through walls.

I am fairly sure I should do something like this: Start a loop in all directions from the current position of the character up until it reaches the view distance OR if the context.getImageData() returns [0,0,0,255]. This way, I could get the character's distance from northern, eastern, western and southern walls. Then, I could light the maze around the character with a (viewdistance-DistanceFrom*Wall) rectangle.

Unfortunately though, after 15 hours of thinking about this I am running out of ideas how to make this work. Any tips are appreciated.

Upvotes: 1

Views: 2154

Answers (3)

user1693593
user1693593

Reputation:

A simpler way of doing this is (ps: I get a "forbidden" error on the link provided so i cannot see what you did):

  • Have a matte version of the maze, a transparent and white image where white represent allowed drawing areas. This matte image should match the maze image in size and placement.
  • Create an off-screen canvas the size of the torch image
  • When you need to draw the torch first draw the matte image into the off-screen canvas. Draw it offset so the correct part of the matte is drawn. For example: if the torch will be drawn at position 100, 100 on the maze then draw the matte into the off-screen canvas at -100,-100 - or simply create the canvas the same size as the maze and draw in the matte at 0,0 and the torch at the relative position. More memory is used but simpler to maintain.
  • Change composite mode to source-in and then draw the torch. Change composite mode back to copy for the next draw.

Now your torch is clipped to fit within the wall. Now simply draw the off-screen canvas to your main canvas instead of the torch.

Note: it's important that the torch is made such as it cannot reach the other side of the wall (diameter size) or it will instead shine "under" the maze walls - this can be solved other ways though by using matte for different zones which is chosen depending on player position (not shown here).

To move in the demo below just move the mouse over the canvas area.

Live demo

Snapshot Matte

function mousemoved(e) {

    var rect = canvas.getBoundingClientRect(),   // adjust mouse pos.:
        x = e.clientX - rect.left - iTorch.width * 0.5, // center of torch
        y = e.clientY - rect.top - iTorch.height * 0.5;
        
    octx.drawImage(iMatte, 0, 0);                // draw matte to off-screen
    octx.globalCompositeOperation = 'source-in'; // change comp mode
    octx.drawImage(iTorch, x, y);                // clip torch
    octx.globalCompositeOperation = 'copy';      // change comp mode for next
    
    ctx.drawImage(iMaze, 0, 0);                  // redraw maze
    ctx.drawImage(ocanvas, 0, 0);                // draw clipped torch on top
}

In the demo the torch is of more or less random size, a bit too big in fact - something I made quick and dirty. But try to move within the maze path to see it being clipped. The off-screen canvas is added on the size of the main canvas to show what goes on.

An added bonus is that you could use the same matte for hit-testing.

Upvotes: 1

markE
markE

Reputation: 105035

Make your maze hallways into clipping paths.

Your torch effects will be contained within the clipping paths.

[ Addition to answer based on questioner's comments ]

To create a clipping path from your existing maze image:

Open up your maze image in a Paint program. The mouse cursors X/Y position are usually displayed as you move over the maze image.

Record the top-left and bottom-right of each maze hallway in an array.

var hallways=[];

hallways.push({left:100, y:50, right: 150, bottom: 65});  // for each hallway

Listen for mouse events and determine which hallway the mouse is in.

// hallwayIndex is the index of the hallway the mouse is inside

var hallwayIndex=-1;

// x=mouse's x coordinate, y=mouse's y coordinate

for(var i=0;i<hallways;i++){

    var hall=hallways[i];

    if(x>=hall.left && 
       x<=hall.right && 
       y>=hall.top && 
       y<=hall.bottom)
       { hallwayIndex=i; }
}

Redraw the maze on the canvas

Create a clipping path for the current hallway:

var width=hall.right-hall.left;
var height=hall.bottom-hall.top;

ctx.beginPath();
ctx.Rect(hall.left,hall.top,width,height);
ctx.clip();

Draw the player+torch into the hallway (the torch will not glow thru the walls).

Upvotes: 1

Daniel Darabos
Daniel Darabos

Reputation: 27455

There is a brilliant article on this topic: http://www.redblobgames.com/articles/visibility/

Doing it accurately like that, however, is a lot of work. If you want to go with a quick and dirty solution, I would suggest the following. Build the world from large blocks (think retro pixels). This makes collision detection simpler too. Now you can consider all points within the torch radius. Walk in a straight line from the character to the point. If you reach the point without hitting a wall, make it bright.

(You could do the same with 1-pixel blocks too, but you might hit performance issues.)

Upvotes: 0

Related Questions