From 0f990eb95a9ef3a1be8847a863f7216a8625692a Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Thu, 18 Dec 2025 20:28:53 -0500 Subject: add bouncing when hitting arena edge --- site/main.mjs | 30 ++++++++++++++++++++++++++++-- site/robo.mjs | 3 +++ site/samples/rob.fs | 2 +- src/forth/vm.rs | 6 +++--- src/lib.rs | 8 ++++++++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/site/main.mjs b/site/main.mjs index 31f1375..703062d 100644 --- a/site/main.mjs +++ b/site/main.mjs @@ -112,8 +112,7 @@ function renderArena(robos, delta=0.0) { robo.speedx, robo.speedy ].map(x => timeScale * x); - const x = robo.x + velx; - const y = robo.y + vely; + const [_, x, y] = bounce(25, robo.heading, robo.x + velx, robo.y + vely, canvas.width, canvas.height); //console.debug('bjc render robo', robo, velx, vely, x, y) renderRobo(ctx, x, y); }); @@ -154,6 +153,26 @@ function loadForth(taintedPath) { }); } +function bounce(radius, heading, x, y, width, height) { + // todo: don't just clamp the x/y, instead calculate based on + // where the intersection with the wall is. + if (y < radius) { + // top wall + return [-1 * heading, x, radius]; + } else if (y >= height-radius) { + // bottom wall + return [-1 * heading, x, height-radius]; + } else if (x < radius) { + // left wall + return [heading - 180, radius, y]; + } else if (x >= width-radius) { + // right wall + return [180 - heading, width-radius, y]; + } else { + return [heading, x, y]; + } +} + async function loaded() { const roboWorker = new Worker('robo.mjs', { type: 'module' }); const robo = { @@ -206,6 +225,13 @@ async function loaded() { robo.speedy = speedy; robo.x += speedx; robo.y += speedy; + const canvas = document.querySelector(CANVAS_SELECTOR); + const [newHeading, newx, newy] = bounce(25, trans.vars.heading, robo.x, robo.y, canvas.width, canvas.height); + if (newHeading != trans.vars.heading) { + roboWorker.postMessage({ kind: 'setHeading', heading: newHeading }); + robo.x = newx; + robo.y = newy; + } renderArena([robo]); break; default: diff --git a/site/robo.mjs b/site/robo.mjs index 1b7c3d8..d80baad 100644 --- a/site/robo.mjs +++ b/site/robo.mjs @@ -26,6 +26,9 @@ async function messageHandler(e) { case 'tick': tick(); break; + case 'setHeading': + vm.setheading(e.data.heading); + break; default: console.error('invalid message to robo worker', e.data); postMessage({ kind: 'error', error: 'badmsg' }); diff --git a/site/samples/rob.fs b/site/samples/rob.fs index 32112d4..59dc946 100644 --- a/site/samples/rob.fs +++ b/site/samples/rob.fs @@ -3,5 +3,5 @@ loop ; -4 setspeed +7 setspeed loop diff --git a/src/forth/vm.rs b/src/forth/vm.rs index 564a647..25ed516 100644 --- a/src/forth/vm.rs +++ b/src/forth/vm.rs @@ -4,9 +4,9 @@ use std::ops::Index; pub type DataStackType = isize; -const MIN_SPEED: DataStackType = 0; -const MAX_SPEED: DataStackType = 10; -const UNITS_PER_ROTATION: DataStackType = 360; +pub const MIN_SPEED: DataStackType = 0; +pub const MAX_SPEED: DataStackType = 10; +pub const UNITS_PER_ROTATION: DataStackType = 360; #[derive(Clone, Debug, Eq, PartialEq)] pub enum OpCode { diff --git a/src/lib.rs b/src/lib.rs index 2aedfff..240acf1 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,14 @@ impl ExportedVM { vm.ip.offset = 0; } + pub fn setheading(&mut self, v: forth::vm::DataStackType) { + let Some(vm) = &mut self.vm else { + return; + }; + use forth::vm::UNITS_PER_ROTATION; + vm.heading = (UNITS_PER_ROTATION + (v % UNITS_PER_ROTATION)) % UNITS_PER_ROTATION; + } + pub fn trans(&mut self) -> Result { let vm = (&mut self.vm).as_mut().ok_or(Error::NoVM)?; let res = js_sys::Map::new(); -- cgit v1.3