For calculang devtools adjust entrypoint in devtools.
Code
scene.addSignalListener("ray_angle_in", (_, r) => {if (observable_world ==0) return; viewof ray_angle_in.value=Math.round(r.ray_angle_in*100)/100; ray_angle_in.dispatchEvent(newCustomEvent('input'), {bubbles:true});// I might never understand how to make this always work})
Code
level.addSignalListener("xy", (_, r) => { // this didn't improve perf a lot vs event listener: nearly every mousemove is a signal change, I supposeconsole.log('hi')if (observable_world ==0) return;console.log(r) viewof ray_angle_in.value=Math.round(Math.atan2((r.level_y_in[0] - player_y_in) , (r.level_x_in[0] - player_x_in))*100)/100; ray_angle_in.dispatchEvent(newCustomEvent('input'), {bubbles:true});})
Source Code
---title: "some raycasting (playable)"order: 1author: - name: "Declan Naughton 🧮👨💻" url: "https://calcwithdec.dev/about.html"description: "some raycasting"format: html: echo: false resources: - '../../models/raycasting/*.js' - '../../models/raycasting/*.js.map' - '../../models/raycasting/*.json'---See also https://calculang-talk-belfastjs.pages.dev/apps/raycastingTODO:- quantize fov layer; in-model?- ray-level calcs for workings?Quarto issue? CSS; see https://observablehq.com/d/867e1424e1d093ab```{ojs}import {viewof keys} from 'd/867e1424e1d093ab'viewof keysviewof time_in = Inputs.range([0,keys.length],{step:1,value:keys.length,label:'time_in'})//time_in = keys.lengthfov = pos[2].valuepos = calcudata({ models: [controls], input_cursors: [{time_in,data_table_in:keys.map(d => d.key), speed_in:3, fov_0_in:[-1-Math.PI/2,1-Math.PI/2]}], input_domains:[], outputs: ['player_x','player_y','fov']})md`keys: ${keys.length == 0 ? '⌛' : keys.map(d => d.key).reverse().slice(0,10).map(d => d == 'ArrowUp' ? '⬆️' : d == 'ArrowDown' ? '⬇️' : d == 'ArrowLeft' ? '⬅️' : d == 'ArrowRight' ? '➡️' : d).join(' ')}`clamped_ray_angle_in = { if (ray_angle_in <= fov[1] && ray_angle_in >= fov[0]) return ray_angle_in else return undefined }//_.clamp(ray_angle_in,fov2[0],fov2[1])viewof ray_angle_in = Inputs.range([-4,4], {step:0.01, value:(fov[0]+fov[1]) / 2, label:'angle for active ray'})player_y_in = pos[1].valueplayer_x_in = pos[0].valueviewof scene = embed( calcuvizspec({ models: [main], input_cursors: [{player_x_in:pos[0].value,player_y_in,fov_in:fov}], mark: {type:'bar', point:false, clip:true, tooltip: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: [clamped_ray_angle_in, ..._.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} spec.params = [{"name": "ray_angle_in", "value": { "ray_angle_in": 0}, "select": { "type": "point", "on": "mouseover", "nearest": true, "encodings": ["x"], toggle:false}}]; spec.encoding.color.condition = {"test": `datum.ray_angle_in==${clamped_ray_angle_in || 999}`,"value": "red"} spec.encoding.opacity.condition = {"test": `datum.ray_angle_in==${clamped_ray_angle_in || 999}`,"value": 1} //spec.encoding.color.condition = {"param": "ray_angle_in", "empty":false, "value": "yellow"} // condition opacity also? return spec }}), {config: {background:'#f9f5f8'}})viewof ray_angle_in_step_size = Inputs.select([0.01,0.02,0.04,0.03], {value:0.02, label: 'ray_angle_in steps'})``````{ojs}viewof observable_world_v = Inputs.checkbox(["overlay field of view"], {value: ["overlay field of view"]})observable_world = observable_world_v.lengthviewof level = embed( calcuvizspec({ models: [main], input_cursors: [{player_x_in:pos[0].value,player_y_in:pos[1].value,fov_in:fov,ray_angle_in: clamped_ray_angle_in/*:(fov[0]+fov[1])/2*/}], mark: {type:'rect',tooltip:false}, encodings: { x: {grid: false, name: 'level_x_in', type:'nominal', domain: _.range(0,63.1,1)}, y: {grid: false, name: 'level_y_in', type: 'nominal', domain: _.range(0,63.1,1)}, color: {name: (observable_world ? 'level_player_ray_fov' : 'level_player'), type: 'quantitative', legend:false}, //row: {name: 'formula', type:'nominal', domain: ['level', 'level_plus_player', 'level_plus_player_plus_ray']}, }, width: 300, height:300, spec_post_process: spec => { spec.params = [{"name": "xy", "select": { "type": "point", "on": "mouseover", "nearest": true, "encodings": ["x", "y"], toggle:false}}]; let a = spec.encoding.x.axis; spec.encoding.x.axis = {...a, ticks:false, labels:false} a = spec.encoding.y.axis; spec.encoding.y.axis = {...a, ticks:false, labels:false} spec.encoding.color.scale = {scheme: 'turbo'} return spec; }}), {actions:true})```## credits*This blog was made with [calculang](https://github.com/calculang), a language for calculations for **transparency, education and certainty** about **numbers and maths, and maths art*** 🎨::: {.callout-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`).:::```{ojs}import { calcuvizspec, calcudata } 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`);controls = require(`../../${'models/raycasting/raycasting-playable'}.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 inputsformulae_not_inputs = Object.values(introspection.cul_functions).filter(d => d.reason == 'definition' && inputs.indexOf(d.name+'_in') == -1).map(d => d.name)```::: {.callout-tip}For calculang devtools adjust *entrypoint* in [devtools](/pages/some-devtools.qmd).:::```{ojs}// COORDINATED VIEWS// performance on hover would be far far better if I vega changeset & signal update on ray_angle changes// & only when != existing signal value (or no good); currently no time for this// first step would = detaching variable names// ray angle coordinationscene.addSignalListener("ray_angle_in", (_, r) => { if (observable_world == 0) return; viewof ray_angle_in.value = Math.round(r.ray_angle_in*100)/100; ray_angle_in.dispatchEvent(new CustomEvent('input'), {bubbles:true}); // I might never understand how to make this always work})level.addSignalListener("xy", (_, r) => { // this didn't improve perf a lot vs event listener: nearly every mousemove is a signal change, I supposeconsole.log('hi') if (observable_world == 0) return; console.log(r) viewof ray_angle_in.value = Math.round(Math.atan2((r.level_y_in[0] - player_y_in) , (r.level_x_in[0] - player_x_in))*100)/100; ray_angle_in.dispatchEvent(new CustomEvent('input'), {bubbles:true});})```