Fix rounding issues in collision handling
This commit is contained in:
parent
34d7b2197b
commit
6a02ea105a
2 changed files with 56 additions and 40 deletions
|
@ -6,7 +6,7 @@ import { loadMap } from '../view/map';
|
||||||
import { Renderer } from '../view/renderer/renderer';
|
import { Renderer } from '../view/renderer/renderer';
|
||||||
import { SpriteView } from '../view/sprite';
|
import { SpriteView } from '../view/sprite';
|
||||||
|
|
||||||
import { LineSegment } from '../math/line';
|
import { LineSegment, Movement } from '../math/line';
|
||||||
import { getJSON } from '../util';
|
import { getJSON } from '../util';
|
||||||
|
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
|
@ -40,10 +40,25 @@ export class GameContext {
|
||||||
private readonly entityMovement: vec2 = vec2.create();
|
private readonly entityMovement: vec2 = vec2.create();
|
||||||
|
|
||||||
private readonly walls: LineSegment[] = [
|
private readonly walls: LineSegment[] = [
|
||||||
new LineSegment(vec2.fromValues(1, 1), vec2.fromValues(1, 0), 10),
|
LineSegment.fromPoints(vec2.fromValues(1, 1), vec2.fromValues(11, 1)),
|
||||||
new LineSegment(vec2.fromValues(11, 1), vec2.fromValues(0, 1), 10),
|
|
||||||
new LineSegment(vec2.fromValues(11, 11), vec2.fromValues(-1, 0), 10),
|
LineSegment.fromPoints(vec2.fromValues(11, 1), vec2.fromValues(11, 5)),
|
||||||
new LineSegment(vec2.fromValues(1, 11), vec2.fromValues(0, -1), 10),
|
LineSegment.fromPoints(vec2.fromValues(11, 5), vec2.fromValues(12, 5)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(12, 5), vec2.fromValues(12, 7)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(12, 7), vec2.fromValues(11, 7)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(11, 7), vec2.fromValues(11, 11)),
|
||||||
|
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(11, 11), vec2.fromValues(7, 11)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(7, 11), vec2.fromValues(7, 12)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(7, 12), vec2.fromValues(5, 12)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(5, 12), vec2.fromValues(5, 11)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(5, 11), vec2.fromValues(1, 11)),
|
||||||
|
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(1, 11), vec2.fromValues(1, 7)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(1, 7), vec2.fromValues(0, 7)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(0, 7), vec2.fromValues(0, 5)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(0, 5), vec2.fromValues(1, 5)),
|
||||||
|
LineSegment.fromPoints(vec2.fromValues(1, 5), vec2.fromValues(1, 1)),
|
||||||
];
|
];
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
|
@ -70,34 +85,32 @@ export class GameContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateStep(): void {
|
private updateStep(): void {
|
||||||
let move = new LineSegment(this.entityPos, this.entityMovement, this.speed);
|
const dest = vec2.scaleAndAdd(vec2.create(), this.entityPos, this.entityMovement, this.speed);
|
||||||
const p = vec2.create();
|
const dest2 = vec2.create();
|
||||||
|
|
||||||
let rescan = true;
|
let rescan = true;
|
||||||
|
|
||||||
while (rescan) {
|
while (rescan) {
|
||||||
rescan = false;
|
rescan = false;
|
||||||
|
|
||||||
|
if (vec2.equals(dest, this.entityPos))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const move = new Movement(this.entityPos, dest);
|
||||||
|
|
||||||
for (const w of this.walls) {
|
for (const w of this.walls) {
|
||||||
if (!w.collidesMove(move))
|
if (!w.collidesMove(dest2, move))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
move.getP2(p);
|
if (!vec2.exactEquals(dest, dest2)) {
|
||||||
w.projectPoint(p, p);
|
vec2.copy(dest, dest2);
|
||||||
|
|
||||||
const move2 = LineSegment.fromPoints(this.entityPos, p);
|
|
||||||
if (move2.l === 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!move.equals(move2)) {
|
|
||||||
move = move2;
|
|
||||||
rescan = true;
|
rescan = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
move.getP2(this.entityPos);
|
vec2.copy(this.entityPos, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private update(time: number): void {
|
private update(time: number): void {
|
||||||
|
|
|
@ -37,9 +37,23 @@ export class Line {
|
||||||
const d2 = d / crossz(this.v, l2.v);
|
const d2 = d / crossz(this.v, l2.v);
|
||||||
return vec2.scaleAndAdd(out, l2.p, l2.v, d2);
|
return vec2.scaleAndAdd(out, l2.p, l2.v, d2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public equals(l2: Line): boolean {
|
export class Movement {
|
||||||
return vec2.equals(this.p, l2.p) && vec2.equals(this.v, l2.v);
|
public readonly v: vec2;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly p1: vec2,
|
||||||
|
public readonly p2: vec2,
|
||||||
|
) {
|
||||||
|
this.v = vec2.sub(vec2.create(), p2, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public intersectLine(out: vec2, l: Line): vec2 {
|
||||||
|
const vp = vec2.sub(vec2.create(), l.p, this.p1);
|
||||||
|
const d = crossz(vp, this.v);
|
||||||
|
const d2 = d / crossz(this.v, l.v);
|
||||||
|
return vec2.scaleAndAdd(out, l.p, l.v, d2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,30 +83,19 @@ export class LineSegment extends Line {
|
||||||
return (d >= 0 && d <= this.l);
|
return (d >= 0 && d <= this.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
public collidesLine(l2: Line): boolean {
|
public collidesMove(out: vec2, move: Movement): boolean {
|
||||||
const x = this.intersectLine(vec2.create(), l2);
|
if (this.distancePoint(move.p1) < 0)
|
||||||
return this.collidesPoint(x);
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public collidesLineSegment(l2: LineSegment): boolean {
|
if (this.distancePoint(move.p2) >= 0)
|
||||||
const x = this.intersectLine(vec2.create(), l2);
|
return false;
|
||||||
|
|
||||||
|
const x = move.intersectLine(vec2.create(), this);
|
||||||
if (!this.collidesPoint(x))
|
if (!this.collidesPoint(x))
|
||||||
return false;
|
return false;
|
||||||
if (!l2.collidesPoint(x))
|
|
||||||
return false;
|
this.projectPoint(out, move.p2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public collidesMove(move: LineSegment): boolean {
|
|
||||||
if (!this.collidesLineSegment(move))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const p2 = move.getP2(vec2.create());
|
|
||||||
return this.distancePoint(p2) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public equals(l2: LineSegment): boolean {
|
|
||||||
return super.equals(l2) && this.l === l2.l;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue