some raycasting (old)

some raycasting (old)

Raycasting engine & explainer with calculang

Or the mathematics of DOOM?

default view is looking directly at the block to the right of the player (see โ€˜levelโ€™ view below). Scrub FOV to the right to look at the long wall! Then increase player y to simulate walking along it.

Field of View (FOV) is radians. 1 Rad is ~52 degrees. 2 is ~104, so the default is a little wide FOV.

Code
viewof player_x_in = Inputs.range([3,61], {step:1, value:32, label:'player x'})
viewof player_y_in = Inputs.range([3,61], {step:1, value:32, label:'player y'})

viewof ray_angle_in_step_size = Inputs.select([0.01,0.02,0.04], {value:0.02, label: 'ray_angle_in steps'})

import {interval} from '@mootari/range-slider'

viewof fov = interval([-3.14*2, 3.14*2], {
  step: 0.01,
  value: [-1,1],
  label: 'field of view',
})


embed(
  calcuvizspec({
    models: [main],
    input_cursors: [{player_x_in,player_y_in}],
    mark: {type:'bar', point:false},
    encodings: {
      //row: {name: 'formula', type:'nominal', domain: ['inverse_ray_length','negative_inverse_ray_length']},
      x: {grid: false, name: 'ray_angle_in', /*sort:'descending',*/type: 'quantitative', domain: _.range(fov[0],fov[1],ray_angle_in_step_size), nice:false, ticks:2},
      color: {name: 'ray_hit_color', type:'nominal', legend:false},
      y: {grid: false, name: 'inverse_ray_length', type: 'quantitative'},
      opacity: {name: 'inverse_ray_length', type: 'quantitative', legend:false},
    },
    width: 500, height:200,
    spec_post_process: spec => {spec.encoding.y.scale = {domain:[0,0.3],};
      spec.encoding.x.axis = {tickCount:2, grid:false}
    return spec}
    
}),
    {config: {background:'#eee'}})

Level:

Code
embed(
  calcuvizspec({
    models: [main],
    input_cursors: [{player_x_in,player_y_in,ray_angle_in:(fov[0]+fov[1])/2}],
    mark: 'rect',
    encodings: {
      x: {name: 'level_x_in', type:'nominal', domain: _.range(0,63.1,1)},
      y: {name: 'level_y_in', type: 'nominal', domain: _.range(0,63.1,1)},
      color: {name: 'value', type: 'nominal', legend:false},
      row: {name: 'formula', type:'nominal', domain: ['level_plus_player_plus_ray']},
    },
    width: 400, height:400
}))
Code
embed(
  calcuvizspec({
    models: [main],
    input_cursors: [{player_x_in,player_y_in}],
    mark: {type:'bar'},
    encodings: {
      color: {name: 'formula', type:'nominal', domain: ['inverse_ray_length','negative_inverse_ray_length']},
      x: {name: 'ray_angle_in', /*sort:'descending',*/type: 'quantitative', domain: _.range(fov[0],fov[1],ray_angle_in_step_size), nice:false},
      //color: {name: 'formula', type:'nominal', domain: ['ray_x','ray_y','ray_value'], legend: false},
      y: {name: 'value', type: 'quantitative', format:',.1f', independent:true},
    },
    width: 400, height:100,
    spec_post_process: spec => {spec.encoding.y.scale = {domain:[-0.3,0.3]}; 
    spec.encoding.color.scale = {"range": ["blue","lightblue"]};
    return spec}
}))

Rays:

Some views I used in development and will remove or replace soon

Code
embed(
  calcuvizspec({
    models: [main],
    input_cursors: [{player_x_in,player_y_in}],
    mark: 'text',
    encodings: {
      y: {name: 'formula', type:'nominal', domain: ['ray_length']},
      x: {name: 'ray_angle_in', type: 'quantitative', domain: _.range(-1,1,0.1)},
      //color: {name: 'formula', type:'nominal', domain: ['ray_x','ray_y','ray_value'], legend: false},
      text: {name: 'value', type: 'quantitative', format:',.1f'},
    },
    width: 800, height:100
}))
Code
embed(
  calcuvizspec({
    models: [main],
    input_cursors: [{player_x_in,player_y_in}],
    mark: 'text',
    encodings: {
      x: {name: 'formula', type:'nominal', domain: ['ray_x','ray_y','ray_value','ray_length']},
      y: {name: 'ray_steps_in', type: 'nominal', domain: _.range(0,50,1)},
      color: {name: 'formula', type:'nominal', domain: ['ray_x','ray_y','ray_value'], legend: false},
      column: {name: 'ray_angle_in', type:'nominal', domain: [0,0.01,0.1,0.5,-0.4]},
      text: {name: 'value', type: 'quantitative', format:',.2f'},
    },
    width: 100, height:500
}))

Appendix

Tip

You can find the calculang model source code by opening Developer Tools (Ctrl+Shift+I) and navigating to the .cul.js file (Ctrl+P and search .cul.js).

Code
import { calcuvizspec } from "@declann/little-calcu-helpers"
embed = require('vega-embed');

viewof entrypoint = Inputs.select(['models/raycasting/raycasting.cul.js'], {label:'entrypoint'})

entrypoint_no_cul_js = entrypoint.slice(0,-7)

main = require(`../../${entrypoint_no_cul_js}.js`);

introspection_fetch = await fetch(`../../${entrypoint_no_cul_js}.introspection.json`)

introspection = introspection_fetch.json({typed:true})

inputs = Object.values(introspection.cul_functions).filter(d => d.reason == 'input definition').map(d => d.name).sort()

formulae = Object.values(introspection.cul_functions).filter(d => d.reason == 'definition').map(d => d.name)

// formulae excluding pure inputs
formulae_not_inputs = Object.values(introspection.cul_functions).filter(d => d.reason == 'definition' && inputs.indexOf(d.name+'_in') == -1).map(d => d.name)
Tip

For calculang devtools adjust entrypoint in devtools.

|