-
Notifications
You must be signed in to change notification settings - Fork 15
RayCasting
This is the most important page of the tutorial. To start our logic, we need to know some concepts with the player angle, player FOV and Screen width.
The first thing we have to know is that each ray needs to be throwed in relation of the player angle and the field of view (FOV). The player FOV is 60º, but the player focus is in the middle of the FOV. Because this we have to start the RayCasting in -30º of the player angle. For example, if the player angle is 90º, we have to cast the rays from the 60º angle to 120º angle. Check the image below to see the player FOV representation.
Inside our rayCasting() function, we can get the actual ray angle with this code
function rayCasting() {
let rayAngle = data.player.angle - data.player.halfFov;
}After it, we will start the cast of the rays. Remember that we have to iterate all screen slices, so we will use the screen width to do this. For each iteration the rayAngle variable needs to be incremented to iterate the entire player FOV. We will use the data.rayCasting.incrementAngle to do it.
function rayCasting() {
let rayAngle = data.player.angle - data.player.halfFov;
for(let rayCount = 0; rayCount < data.screen.width; rayCount++) {
// ...
// Increment
rayAngle += data.rayCasting.incrementAngle;
}
}Important: The next steps will be created inside the ray loop, and before the ray angle increment.
The first coordinates of the ray is the the same of the player coodinates. We will create an object with these values to be more organized.
// Ray data
let ray = {
x: data.player.x,
y: data.player.y
}To discover the next coordinates of the actual ray, we have to calculate this based in the ray angle. For this step, we will use the functions Math.sin() and Math.cos(). These functions will give to usthe increment values to give for the ray to follow forward. In this step we will use the precision attribute too, to control the interval of each position of the ray. The sin and cos give us float values, but we can divide these values with the precision to turn these values
smaller.
Note: The higher value of the precision, more checkings will be executed and more positions the ray will have.
Note: We need to use the
degreeToRadians()function in this step because the trigonometry functions work with radians values type.
// Ray path incrementers
let rayCos = Math.cos(degreeToRadians(rayAngle)) / data.rayCasting.precision;
let raySin = Math.sin(degreeToRadians(rayAngle)) / data.rayCasting.precision;The next step is the wall checking. We have to increment the rayCos and raySin to x and y ray coordinates until find a wall in the map. So, in this step we need a loop.
Note: Remember that the matrix positions are represented in integer coodinates. The ray positions incremented with the
cosandsinwill be float values and we need to convert these values to integer type. The function used for it isMath.floor()
// Wall checking
let wall = 0;
while(wall == 0) {
ray.x += rayCos;
ray.y += raySin;
wall = data.map[Math.floor(ray.y)][Math.floor(ray.x)];
}When the ray collides with some wall, the loop will be stopped and we will have the ray coordinates updated with the wall position. The RayCasting distance is calculated in this step, to know the strip size that we will need to draw. If the wall is near, the distance will be lower then the drawed line will be bigger. If the wall is far, the distance will be bigger then the drawed line will be smaller.
For the distance calc we will use the Pythagoras Theorem. This formula will be used with the player coodinates and the ray coordinates of the wall.
Pythagoras Theorem: a² + b² = c²
In our logic: distance² = (player x - ray x)² + (player y - ray y)²
In code: Math.sqrt( Math.pow( data.player.x - ray.x, 2 ) + Math.pow( data.player.y - ray.y, 2 ) );
The code will be:
// Pythagoras theorem
let distance = Math.sqrt(Math.pow(data.player.x - ray.x, 2) + Math.pow(data.player.y - ray.y, 2));With the distance we have to define the wall height. The wall height will be used to draw the strip in the canvas. We cannot use the distance directally because we need the reversed value. To bigger distance, smaller strip. To reverse the value we can divide the distance value with the data.screen.halfHeight. This value will define the same size for the width, height and length.
Note: The
wallHeightvalue will be used to draw the strip in the canvas. The canvas coordinates are represented with an integer type for our case so, we need to converted the value withMath.floor. The canvas drawer methods accept float values, but in our case it will not be a good practice.
// Wall height
let wallHeight = Math.floor(data.screen.halfHeight / distance);Copyright © 2018 Vinícius Reif Biavatti
- Home
- RayTrancing
- Examples
- Basic Tutorial
- Intermediary Tutorial
- Advanced Tutorial