Skip to content

Commit fd5321d

Browse files
committed
raycast fix
1 parent 0d4b236 commit fd5321d

File tree

2 files changed

+151
-69
lines changed

2 files changed

+151
-69
lines changed

src/bundles/robot_minigame/functions.ts

Lines changed: 148 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@
44
*/
55

66
import context from 'js-slang/context';
7+
import {
8+
accumulate,
9+
head,
10+
tail,
11+
type List
12+
} from 'js-slang/dist/stdlib/list';
713

814
type Point = {x: number, y: number};
15+
type Intersection = {x: number, y: number, dist: number}
916

1017
type Polygon = Point[];
1118

@@ -17,7 +24,8 @@ type StateData = {
1724
movePoints: Point[],
1825
message: string,
1926
success: boolean,
20-
messages: string[]
27+
messages: string[],
28+
rotations: Point[]
2129
};
2230

2331
type Robot = {
@@ -36,7 +44,8 @@ const stateData: StateData = {
3644
movePoints: [],
3745
message: 'moved successfully',
3846
success: true,
39-
messages: []
47+
messages: [],
48+
rotations: []
4049
};
4150

4251
const robot: Robot = {
@@ -49,7 +58,6 @@ const robot: Robot = {
4958

5059
let bounds: Point[] = [];
5160

52-
// default grid width and height is 25
5361
context.moduleContexts.robot_minigame.state = stateData;
5462

5563
export function set_pos(x: number, y: number): void {
@@ -82,23 +90,59 @@ export function init(width: number, height: number, posX: number, posY: number)
8290
}
8391

8492
export function turn_left() {
85-
if (alrCollided()) return;
93+
let currentAngle = Math.atan2(-robot.dy, robot.dx);
8694

87-
let currentAngle = Math.tan(robot.dy / robot.dx);
88-
currentAngle -= Math.PI / 2;
95+
currentAngle += Math.PI / 2;
8996

9097
robot.dx = Math.cos(currentAngle);
91-
robot.dy = Math.sin(currentAngle);
98+
robot.dy = -Math.sin(currentAngle);
99+
100+
if (robot.dx < 0.00001 && robot.dx > -0.00001) robot.dx = 0;
101+
if (robot.dy < 0.00001 && robot.dy > -0.00001) robot.dy = 0;
102+
103+
logCoordinates();
92104
}
93105

94106
export function turn_right() {
95-
if (alrCollided()) return;
107+
let currentAngle = Math.atan2(-robot.dy, robot.dx);
96108

97-
let currentAngle = Math.tan(robot.dy / robot.dx);
98-
currentAngle += Math.PI / 2;
109+
currentAngle -= Math.PI / 2;
99110

100111
robot.dx = Math.cos(currentAngle);
101-
robot.dy = Math.sin(currentAngle);
112+
robot.dy = -Math.sin(currentAngle);
113+
114+
if (robot.dx < 0.00001 && robot.dx > -0.00001) robot.dx = 0;
115+
if (robot.dy < 0.00001 && robot.dy > -0.00001) robot.dy = 0;
116+
117+
logCoordinates();
118+
}
119+
120+
export function rotate_right(angle: number) {
121+
let currentAngle = Math.atan2(-robot.dy, robot.dx);
122+
123+
currentAngle -= angle;
124+
125+
robot.dx = Math.cos(currentAngle);
126+
robot.dy = -Math.sin(currentAngle);
127+
128+
if (robot.dx < 0.00001 && robot.dx > -0.00001) robot.dx = 0;
129+
if (robot.dy < 0.00001 && robot.dy > -0.00001) robot.dy = 0;
130+
131+
logCoordinates();
132+
}
133+
134+
export function rotate_left(angle: number) {
135+
let currentAngle = Math.atan2(-robot.dy, robot.dx);
136+
137+
currentAngle += angle;
138+
139+
robot.dx = Math.cos(currentAngle);
140+
robot.dy = -Math.sin(currentAngle);
141+
142+
if (robot.dx < 0.00001 && robot.dx > -0.00001) robot.dx = 0;
143+
if (robot.dy < 0.00001 && robot.dy > -0.00001) robot.dy = 0;
144+
145+
logCoordinates();
102146
}
103147

104148
export function set_rect_wall(x: number, y: number, width: number, height: number) {
@@ -112,20 +156,15 @@ export function set_rect_wall(x: number, y: number, width: number, height: numbe
112156
stateData.walls.push(polygon);
113157
}
114158

115-
export function move_forward(): void {
116-
if (alrCollided()) return;
117-
118-
const collisionPoint: Point | null = raycast(stateData.walls);
119-
if (collisionPoint !== null) {
120-
const nextPoint: Point = {
121-
x: collisionPoint.x - robot.dx * (robot.radius + 5),
122-
y: collisionPoint.y - robot.dy * (robot.radius + 5)
123-
};
124-
125-
robot.x = nextPoint.x;
126-
robot.y = nextPoint.y;
127-
stateData.movePoints.push(nextPoint);
159+
export function set_polygon_wall(vertices: List) {
160+
const polygon: Polygon = []
161+
while (vertices != null) {
162+
const p = head(vertices);
163+
polygon.push({x: head(p), y: tail(p)});
164+
vertices = tail(vertices);
128165
}
166+
167+
stateData.walls.push(polygon);
129168
}
130169

131170
export function getX():number {
@@ -136,77 +175,117 @@ export function getY():number {
136175
return robot.y;
137176
}
138177

139-
function raycast(polygons: Polygon[]): Point | null {
178+
export function move_forward(): void {
179+
if (alrCollided()) return;
180+
181+
let distance = findCollision();
182+
distance = Math.max(distance - robot.radius - 5, 0)
183+
184+
const nextPoint: Point = {
185+
x: robot.x + distance * robot.dx,
186+
y: robot.y + distance * robot.dy
187+
}
188+
189+
190+
robot.x = nextPoint.x;
191+
robot.y = nextPoint.y;
192+
stateData.movePoints.push(nextPoint);
193+
stateData.messages.push(`Distance is ${distance} Collision point at x: ${nextPoint.x}, y: ${nextPoint.y}`);
194+
}
195+
196+
function findCollision(): number {
140197
let nearest: Point | null = null;
141-
let minDist = Infinity;
198+
let minDist: number = Infinity;
199+
200+
for (const wall of stateData.walls) {
201+
const intersection: Intersection | null = raycast(wall);
202+
if (intersection !== null && intersection.dist < minDist) {
203+
minDist = intersection.dist;
204+
nearest = {x: intersection.x, y: intersection.y};
205+
}
206+
}
142207

143-
for (const polygon of polygons) {
144-
stateData.messages.push('checking polygon');
145-
const numVertices = polygon.length;
208+
// check outer bounds as well
209+
const intersection: Intersection | null = raycast(bounds);
210+
if (intersection !== null && intersection.dist < minDist) {
211+
minDist = intersection.dist;
212+
nearest = {x: intersection.x, y: intersection.y};
213+
}
214+
215+
return minDist === Infinity ? 0 : minDist; // Closest intersection point
216+
}
146217

147-
for (let i = 0; i < numVertices; i++) {
148-
const x1 = polygon[i].x, y1 = polygon[i].y;
149-
const x2 = polygon[(i + 1) % numVertices].x, y2 = polygon[(i + 1) % numVertices].y;
218+
function raycast(polygon: Polygon): Intersection | null {
219+
let minDist = Infinity;
220+
let nearest: Intersection | null = null;
150221

151-
const intersection = getIntersection(robot.x, robot.y, robot.dx + robot.x, robot.dy + robot.y, x1, y1, x2, y2);
222+
for (let i = 0; i < polygon.length; i++) {
223+
const x1 = polygon[i].x, y1 = polygon[i].y;
224+
const x2 = polygon[(i + 1) % polygon.length].x, y2 = polygon[(i + 1) % polygon.length].y;
152225

153-
if (intersection.collided && intersection.dist < minDist) {
154-
minDist = intersection.dist;
155-
nearest = {x: intersection.x, y: intersection.y};
156-
}
157-
}
158-
}
226+
const topX = robot.x - robot.radius * robot.dy;
227+
const topY = robot.y - robot.radius * robot.dx;
159228

160-
// if no collisions with obstacles, check the outer bounds of map
161-
if (nearest === null) {
162-
for (let i = 0; i < bounds.length; i++) {
163-
const x1 = bounds[i].x, y1 = bounds[i].y;
164-
const x2 = bounds[(i + 1) % bounds.length].x, y2 = bounds[(i + 1) % bounds.length].y;
229+
const bottomX = robot.x + robot.radius * robot.dy;
230+
const bottomY = robot.y + robot.radius * robot.dx;
165231

166-
const intersection = getIntersection(robot.x, robot.y, robot.dx + robot.x, robot.dy + robot.y, x1, y1, x2, y2);
232+
const raycast_sources: Point[] = [
233+
{x: robot.x, y: robot.y},
234+
{x: topX, y: topY},
235+
{x: bottomX, y: bottomY}
236+
]
167237

168-
if (intersection.collided && intersection.dist < minDist) {
238+
for (const source of raycast_sources) {
239+
const intersection = getIntersection(source.x, source.y, robot.dx + source.x, robot.dy + source.y, x1, y1, x2, y2);
240+
if (intersection !== null && intersection.dist < minDist) {
169241
minDist = intersection.dist;
170-
nearest = {x: intersection.x, y: intersection.y};
242+
nearest = intersection;
171243
}
172244
}
173245
}
174-
175-
return nearest; // Closest intersection point
246+
247+
return nearest;
176248
}
177249

178250
// Determine if a ray and a line segment intersect, and if so, determine the collision point
179-
function getIntersection(x1, y1, x2, y2, x3, y3, x4, y4){
251+
function getIntersection(x1, y1, x2, y2, x3, y3, x4, y4): Intersection | null {
180252
const denom = ((x2 - x1)*(y4 - y3)-(y2 - y1)*(x4 - x3));
181253
let r;
182254
let s;
183255
let x;
184256
let y;
185257
let b = false;
186258

187-
// If lines not collinear or parallel
188-
if(denom != 0){
189-
// Intersection in ray "local" coordinates
190-
r = (((y1 - y3) * (x4 - x3)) - (x1 - x3) * (y4 - y3)) / denom;
191-
192-
// Intersection in segment "local" coordinates
193-
s = (((y1 - y3) * (x2 - x1)) - (x1 - x3) * (y2 - y1)) / denom;
194-
195-
// The algorithm gives the intersection of two infinite lines, determine if it lies on the side that the ray is defined on
196-
if (r >= 0) {
197-
// If point along the line segment
198-
if (s >= 0 && s <= 1) {
199-
b = true;
200-
// Get point coordinates (offset by r local units from start of ray)
201-
x = x1 + r * (x2 - x1);
202-
y = y1 + r * (y2 - y1);
203-
}
259+
// If lines are collinear or parallel
260+
if (denom === 0) return null;
261+
262+
// Intersection in ray "local" coordinates
263+
r = (((y1 - y3) * (x4 - x3)) - (x1 - x3) * (y4 - y3)) / denom;
264+
265+
// Intersection in segment "local" coordinates
266+
s = (((y1 - y3) * (x2 - x1)) - (x1 - x3) * (y2 - y1)) / denom;
267+
268+
// The algorithm gives the intersection of two infinite lines, determine if it lies on the side that the ray is defined on
269+
if (r >= 0) {
270+
// If point along the line segment
271+
if (s >= 0 && s <= 1) {
272+
b = true;
273+
// Get point coordinates (offset by r local units from start of ray)
274+
x = x1 + r * (x2 - x1);
275+
y = y1 + r * (y2 - y1);
204276
}
205277
}
206-
const p = {collided: b, x: x, y: y, dist: r};
207-
return p;
278+
279+
if (!b) return null
280+
281+
return {x: x, y: y, dist: r}
208282
}
209283

210284
function alrCollided() {
211285
return !stateData.success;
212286
}
287+
288+
// debug
289+
function logCoordinates() {
290+
stateData.messages.push(`x: ${robot.x}, y: ${robot.y}, dx: ${robot.dx}, dy: ${robot.dy}`)
291+
}

src/bundles/robot_minigame/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ export {
1212
init,
1313
set_pos,
1414
set_rect_wall,
15+
set_polygon_wall,
1516
move_forward,
1617
turn_left,
1718
turn_right,
19+
rotate_right,
20+
rotate_left,
1821
getX,
1922
getY
2023
} from './functions';

0 commit comments

Comments
 (0)