summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@spork.org>2025-12-18 20:28:53 -0500
committerBrian Cully <bjc@spork.org>2025-12-18 20:36:39 -0500
commit0f990eb95a9ef3a1be8847a863f7216a8625692a (patch)
tree9742a3730168e0ed9b1b6d259a79a430eda71f31
parent8e65c1c439b2fc0d0ae5d8482e9350e283cde882 (diff)
downloadautomathon-0f990eb95a9ef3a1be8847a863f7216a8625692a.tar.gz
automathon-0f990eb95a9ef3a1be8847a863f7216a8625692a.zip
add bouncing when hitting arena edge
-rw-r--r--site/main.mjs30
-rw-r--r--site/robo.mjs3
-rw-r--r--site/samples/rob.fs2
-rw-r--r--src/forth/vm.rs6
-rwxr-xr-xsrc/lib.rs8
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<js_sys::Object, JsValue> {
let vm = (&mut self.vm).as_mut().ok_or(Error::NoVM)?;
let res = js_sys::Map::new();