Skip to content

Instantly share code, notes, and snippets.

@y-lohse
Last active December 10, 2015 16:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save y-lohse/4462395 to your computer and use it in GitHub Desktop.
Save y-lohse/4462395 to your computer and use it in GitHub Desktop.
Lighting simulation inside a canvas Built with Cannon: https://github.com/y-lohse/Cannon
<html>
<head>
<title>RayCaster</title>
<script src="http://code.yannick-lohse.fr/cannon/1/cannon.js"></script>
<script src="raycasting.js"></script>
</head>
<body>
<div>
Torch Power
<input type="range" min="0" max="200" value="80" oninput="torch_power=value;torchlight.size=value;" />
</div>
<div>
Torch Step
<input type="range" min="0" max="200" value="100" oninput="torch_step=value" />
</div>
<div>
Torch Angle
<input type="range" min="0" max="360" value="360" oninput="torch_angle=value" />
</div>
<div>
Torch Angle Step
<input type="range" min="2" max="100" value="20" oninput="torch_angle_step=value" />
</div>
<div>
<button onclick="DEBUG=(DEBUG)?false:true;">Debug on/off</button>
</div>
<div id="canvas" style="width: 480px; height: 360px; border: 1px solid black;"></div>
<div id="fps">0</div>
<div id="logs" style="width: 800px; height: 300px; overflow: auto;">
logs in here
</div>
</body>
</html>
Cannon.include('http://code.yannick-lohse.fr/cannon/1/math.js');
Cannon.include('http://code.yannick-lohse.fr/cannon/1/display.js');
Cannon.include('http://code.yannick-lohse.fr/cannon/1/misc.js');
var canvas, player, raysObject, background, torchlight;
var DEBUG = false;
var torch_power = 80;
var torch_step = 100;
var torch_angle = 360;
var torch_angle_step = 20;
var map = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,3,0,3,0,0,1,1,1,2,1,1,1,1,1,2,1,1,1,2,1,0,0,0,0,0,0,0,0,1],
[1,0,0,3,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1],
[1,0,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,3,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2],
[1,0,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,3,3,3,0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2],
[1,0,0,0,0,0,0,0,0,3,3,3,0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,3,3,3,0,0,3,3,3,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,3,3,3,0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,4,0,0,4,2,0,2,2,2,2,2,2,2,2,0,2,4,4,0,0,4,0,0,0,0,0,0,0,1],
[1,0,0,4,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,4,0,0,0,0,0,0,0,1],
[1,0,0,4,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,4,0,0,0,0,0,0,0,1],
[1,0,0,4,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,4,0,0,0,0,0,0,0,1],
[1,0,0,4,3,3,4,2,2,2,2,2,2,2,2,2,2,2,2,2,4,3,3,4,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
], tilesize = 15;
Cannon.onReady = function(){
Cannon.Logger.autolog('logs');
Cannon.use('*');
canvas = new Cannon.Canvas('canvas');
var mapwidth = map[0].length,
mapheight = map.length;
var bg = new Rectangle(0, 0, canvas.width, canvas.height);
canvas.addChild(bg);
background = new Rectangle(0, 0, canvas.width, canvas.height);
background.fillStyle = '#EEEEEE';
background.center = [0, 0];
canvas.addChild(background);
torchlight = new RadialGradient(torch_power);
torchlight.addColorStop(0, new Color(0, 0, 0, 0));
torchlight.addColorStop(.7, new Color(0, 0, 0, .4));
torchlight.addColorStop(1, new Color(0, 0, 0, 1));
for (var i = 0; i < mapwidth; i++){
for (var j = 0; j < mapheight; j++){
if (map[j][i]){
var rect = new Rectangle(i*tilesize, j*tilesize, tilesize, tilesize);
background.addChild(rect);
}
}
}
player = new Circle(16*tilesize, 10*tilesize, tilesize/2);
player.fillStyle = new Color(200,0,0,255);
player.strokeStyle = new Color(0,0,0,0);
canvas.addChild(player);
player.moveSpeed = 2;
raysObject = new Cannon.DisplayObject();
canvas.addChild(raysObject);
var element = document.getElementById('fps');
canvas.on('canvas:FPS', function(event){
element.innerHTML = event.fps;
});
canvas.on('canvas:render', onRender);
}
function onRender(){
var newX, newY;
if (canvas.keyIsDown('up')) newY = player.y-player.moveSpeed;
else if (canvas.keyIsDown('down')) newY = player.y+player.moveSpeed;
else newY = player.y;
//Cannon.Logger.log(canvas.heldKeys);
if (canvas.keyIsDown('left')) newX = player.x-player.moveSpeed;
else if (canvas.keyIsDown('right')) newX = player.x+player.moveSpeed;
else newX = player.x;
if (isBlocking(newX/tilesize, newY/tilesize)) return;
player.x = newX;
player.y = newY;
raysObject.childs.length = 0;
background.masks.length = 0;
var angle = 0;
//player.rotation = angle/(Math.PI/180);
var rays = [];
for (var x = 0; x < torch_angle; x += (torch_angle/torch_angle_step)){
var ray_angle = angle/(Math.PI/180)-90-(torch_angle/2)+x;
ray_angle = ray_angle*(Math.PI/180);
for (var y = 1; y <= torch_step; y++){
if (isBlocking((player.x+(torch_power/torch_step*y)*Math.cos(ray_angle))/tilesize, (player.y+(torch_power/torch_step*y)*Math.sin(ray_angle))/tilesize)) break;
}
var impactX = (torch_power/torch_step*y)*Math.cos(ray_angle),
impactY = (torch_power/torch_step*y)*Math.sin(ray_angle);
rays.push(new Vertex2D(impactX, impactY));
}
rays.push(new Vertex2D(rays[0].point.x, rays[0].point.y));
if (!DEBUG){
var shape = new Shape(rays, player.x, player.y);
background.addMask(shape);
var shape = new Shape(rays, player.x, player.y);
shape.fillStyle = torchlight;
raysObject.addChild(shape);
}
else{
var shape = new Shape(rays, player.x, player.y);
shape.fillStyle = new Color(0,0,0,0);
shape.strokeStyle = new Color(200,0,0,255);
raysObject.addChild(shape);
}
}
function isBlocking(x, y){
if (y < 0 || y >= map.length || x < 0 || x >= map[0].length) return true;
return (map[Math.floor(y)][Math.floor(x)] != 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment