Fix collision detection

This commit is contained in:
schmelczerandras 2020-08-17 18:55:47 +02:00
parent 006ab3c4e6
commit 5b4e67cbf0
9 changed files with 169 additions and 49 deletions

View file

@ -9,18 +9,21 @@ import { TeleportToCommand } from '../../physics/commands/teleport-to';
import { Physics } from '../../physics/physics';
import { GameObject } from '../game-object';
import { Camera } from './camera';
import { IShape } from '../../shapes/i-shape';
import { rotate90Deg } from '../../helper/rotate-90-deg';
import { max } from 'gl-matrix/src/gl-matrix/vec2';
export class Character extends GameObject {
private keysDown: Set<string> = new Set();
private primitive: Circle;
private shape: Circle;
private static speed = 1.5;
constructor(private physics: Physics, private camera: Camera) {
super();
this.primitive = new Circle();
this.primitive.radius = 40;
this.shape = new Circle();
this.shape.radius = 80;
this.addCommandExecutor(StepCommand, this.stepHandler.bind(this));
this.addCommandExecutor(TeleportToCommand, (c) =>
@ -28,57 +31,100 @@ export class Character extends GameObject {
);
this.addCommandExecutor(KeyDownCommand, (c) => this.keysDown.add(c.key));
this.addCommandExecutor(KeyUpCommand, (c) => this.keysDown.delete(c.key));
this.addCommandExecutor(SwipeCommand, (c) =>
this.checkAndSetPosition(
vec2.add(
vec2.create(),
this.primitive.center,
vec2.multiply(vec2.create(), c.delta, this.camera.viewAreaSize)
)
)
);
this.addCommandExecutor(SwipeCommand, (c) => {
this.tryMoving(
vec2.multiply(vec2.create(), c.delta, this.camera.viewAreaSize)
);
});
}
private checkAndSetPosition(value: vec2) {
const nextPrimitive = this.primitive.clone();
nextPrimitive.center = value;
private tryMoving(delta: vec2, isFirstIteration = true) {
const maxStep = 2;
if (vec2.length(delta) > maxStep) {
let steppedDelta = vec2.normalize(vec2.create(), delta);
vec2.scale(steppedDelta, steppedDelta, maxStep - 0.001);
const intersects = this.physics
.findIntersecting(nextPrimitive.boundingBox)
.filter((b) => b.shape)
.map(
(b) => b.shape.distance(nextPrimitive.center) + nextPrimitive.radius
for (let i = 0; i <= vec2.length(delta) / maxStep - 1; i++) {
this.tryMoving(vec2.clone(steppedDelta), isFirstIteration);
}
steppedDelta = vec2.normalize(vec2.create(), delta);
vec2.scale(steppedDelta, steppedDelta, vec2.length(delta) % maxStep);
this.tryMoving(vec2.clone(steppedDelta), isFirstIteration);
return;
}
const nextShape = this.shape.clone();
vec2.add(nextShape.center, nextShape.center, delta);
const nextNearShapes = this.getNearShapesTo(nextShape);
if (nextNearShapes.length && nextNearShapes[0].distance < 0) {
this.setPosition(nextShape.center);
} else {
if (!isFirstIteration) {
return;
}
const currentNearShapes = this.getNearShapesTo(this.shape);
const intersecting = nextNearShapes
.filter(
(n) =>
currentNearShapes.find(
(c) => c.shape === n.shape && c.distance <= 0
) !== undefined
)
.sort((e) => Math.abs(e.distance));
const normal = intersecting[0].shape.normal(this.shape.center);
const maxDistance = intersecting.reduce((p, c) =>
p.distance > c.distance ? p : c
).distance;
vec2.add(
delta,
delta,
vec2.scale(vec2.create(), normal, -maxDistance - 2)
);
console.log(intersects);
if (intersects.find((d) => d < 0) !== undefined) {
this.setPosition(value);
this.tryMoving(delta, false);
}
}
private setPosition(value: vec2) {
// console.log('character', value);
private getNearShapesTo(
shape: Circle
): Array<{ shape: IShape; distance: number }> {
return this.physics
.findIntersecting(shape.boundingBox)
.filter((b) => b.shape)
.map((b) => ({
shape: b.shape,
distance: b.shape.distance(shape.center) + shape.radius,
}))
.sort((e) => e.distance);
}
this.primitive.center = value;
this.camera.sendCommand(new MoveToCommand(this.primitive.center));
private setPosition(value: vec2) {
this.shape.center = value;
this.camera.sendCommand(new MoveToCommand(this.shape.center));
}
public stepHandler(c: StepCommand) {
const deltaTime = c.deltaTimeInMiliseconds;
const up = ~~this.keysDown.has('w');
const down = ~~this.keysDown.has('s');
const left = ~~this.keysDown.has('a');
const right = ~~this.keysDown.has('d');
const up = ~~(this.keysDown.has('w') || this.keysDown.has('arrowup'));
const down = ~~(this.keysDown.has('s') || this.keysDown.has('arrowdown'));
const left = ~~(this.keysDown.has('a') || this.keysDown.has('arrowleft'));
const right = ~~(this.keysDown.has('d') || this.keysDown.has('arrowright'));
const movementVector = vec2.fromValues(right - left, up - down);
if (movementVector.length > 0) {
if (vec2.length(movementVector) > 0) {
vec2.normalize(movementVector, movementVector);
vec2.scale(movementVector, movementVector, Character.speed * deltaTime);
this.checkAndSetPosition(
vec2.add(vec2.create(), this.primitive.center, movementVector)
);
this.tryMoving(movementVector);
}
}
}

View file

@ -2,6 +2,7 @@ import { vec2 } from 'gl-matrix';
import { Physics } from '../../physics/physics';
import { Objects } from '../objects';
import { Tunnel } from '../types/tunnel';
import { Random } from '../../helper/random';
export const createDungeon = (objects: Objects, physics: Physics): Tunnel => {
let previousRadius = 350;
@ -10,10 +11,10 @@ export const createDungeon = (objects: Objects, physics: Physics): Tunnel => {
let first: Tunnel;
for (let i = 0; i < 50000; i += 500) {
const deltaHeight = (Math.random() - 0.5) * 2000;
const deltaHeight = (Random.getRandom() - 0.5) * 2000;
const height = previousEnd.y + deltaHeight;
const currentEnd = vec2.fromValues(i, height);
const currentToRadius = Math.random() * 300 + 150;
const currentToRadius = Random.getRandom() * 300 + 150;
const tunnel = new Tunnel(
physics,
@ -29,15 +30,15 @@ export const createDungeon = (objects: Objects, physics: Physics): Tunnel => {
objects.addObject(tunnel);
/*if (deltaHeight > 0 && Math.random() > 0.8) {
/*if (deltaHeight > 0 && Random.getRandom() > 0.8) {
objects.addObject(
new Lamp(
currentEnd,
Math.random() * 20 + 30,
Random.getRandom() * 20 + 30,
vec3.scale(
vec3.create(),
vec3.normalize(vec3.create(), vec3.fromValues(0.5, 0.1, 0.8)),
Math.random() * 0.5 + 0.5
Random.getRandom() * 0.5 + 0.5
),
1
)