Improve physics

This commit is contained in:
schmelczerandras 2020-10-06 09:26:56 +02:00
parent 8b87b68dae
commit ec0b700313
14 changed files with 181 additions and 71 deletions

View file

@ -1,27 +1,64 @@
import { vec2 } from 'gl-matrix';
import { id, CharacterBase } from 'shared';
import {
id,
CharacterBase,
StepCommand,
settings,
CommandExecutors,
MoveActionCommand,
} from 'shared';
import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box';
import { CirclePhysical } from './circle-physical';
import { Physical } from '../physics/physical';
import { PhysicalContainer } from '../physics/containers/physical-container';
export class CharacterPhysical extends CharacterBase implements Physical {
public readonly canCollide = true;
public readonly isInverted = false;
public readonly canMove = true;
public head: CirclePhysical;
public leftFoot: CirclePhysical;
public rightFoot: CirclePhysical;
private movementActions: Array<MoveActionCommand> = [];
protected commandExecutors: CommandExecutors = {
[StepCommand.type]: this.step.bind(this),
[MoveActionCommand.type]: (c: MoveActionCommand) => this.movementActions.push(c),
};
private static readonly headOffset = vec2.fromValues(0, 40);
private static readonly leftFootOffset = vec2.fromValues(-20, -10);
private static readonly rightFootOffset = vec2.fromValues(20, -10);
constructor() {
constructor(container: PhysicalContainer) {
super(
id(),
new CirclePhysical(vec2.clone(CharacterPhysical.headOffset), 50, null),
new CirclePhysical(vec2.clone(CharacterPhysical.leftFootOffset), 20, null),
new CirclePhysical(vec2.clone(CharacterPhysical.rightFootOffset), 20, null)
new CirclePhysical(vec2.clone(CharacterPhysical.headOffset), 50, null, container),
new CirclePhysical(
vec2.clone(CharacterPhysical.leftFootOffset),
20,
null,
container
),
new CirclePhysical(
vec2.clone(CharacterPhysical.rightFootOffset),
20,
null,
container
)
);
this.head.owner = this;
this.leftFoot.owner = this;
this.rightFoot.owner = this;
container.addObject(this.head);
container.addObject(this.leftFoot);
container.addObject(this.rightFoot);
}
private _boundingBox?: ImmutableBoundingBox;
@ -42,16 +79,51 @@ export class CharacterPhysical extends CharacterBase implements Physical {
public distance(_: vec2): number {
return 0;
}
/*
public step() {
const movementForce = vec2.fromValues(right - left, up - down);
private sumAndResetMovementActions(): vec2 {
if (this.movementActions.length === 0) {
return vec2.create();
}
const movementForce = this.movementActions.reduce(
(sum, current) => vec2.add(sum, sum, current.delta),
vec2.create()
);
vec2.scale(movementForce, movementForce, 1 / this.movementActions.length);
this.movementActions = [];
return movementForce;
}
public step(c: StepCommand) {
const deltaTime = c.deltaTimeInMiliseconds;
const movementForce = this.sumAndResetMovementActions();
if (!this.leftFoot.isAirborne || !this.rightFoot.isAirborne) {
movementForce.y = 0;
}
this.head.applyForce(movementForce, deltaTime);
this.head.applyForce(settings.gravitationalForce, deltaTime);
const bodyCenter = vec2.sub(vec2.create(), this.head.center, this.headOffset);
const bodyCenter = vec2.sub(
vec2.create(),
this.head.center,
CharacterPhysical.headOffset
);
const leftFootPositon = vec2.add(vec2.create(), bodyCenter, this.leftFootOffset);
const rightFootPositon = vec2.add(vec2.create(), bodyCenter, this.rightFootOffset);
const leftFootPositon = vec2.add(
vec2.create(),
bodyCenter,
CharacterPhysical.leftFootOffset
);
const rightFootPositon = vec2.add(
vec2.create(),
bodyCenter,
CharacterPhysical.rightFootOffset
);
const leftFootDelta = vec2.sub(vec2.create(), this.leftFoot.center, leftFootPositon);
const rightFootDelta = vec2.sub(
@ -80,13 +152,13 @@ export class CharacterPhysical extends CharacterBase implements Physical {
this.leftFoot.step(deltaTime);
this.rightFoot.step(deltaTime);
this.flashlight.center = vec2.add(
/*this.flashlight.center = vec2.add(
vec2.create(),
this.head.center,
vec2.fromValues(0, 0)
);
);*/
}
*/
public toJSON(): any {
const { type, id, head, leftFoot, rightFoot } = this;
return [type, id, head, leftFoot, rightFoot];

View file

@ -1,9 +1,18 @@
import { vec2 } from 'gl-matrix';
import { Circle, clamp, GameObject, settings } from 'shared';
import {
Circle,
clamp,
CommandExecutors,
GameObject,
settings,
StepCommand,
} from 'shared';
import { Physical } from '../physics/physical';
import { BoundingBox } from '../physics/bounding-boxes/bounding-box';
import { BoundingBoxBase } from '../physics/bounding-boxes/bounding-box-base';
import { moveCircle } from '../physics/move-circle';
import { PhysicalContainer } from '../physics/containers/physical-container';
export class CirclePhysical implements Circle, Physical {
readonly isInverted = false;
@ -18,9 +27,18 @@ export class CirclePhysical implements Circle, Physical {
return this._isAirborne;
}
protected commandExecutors: CommandExecutors = {
[StepCommand.type]: this.step.bind(this),
};
private _boundingBox: BoundingBox;
constructor(private _center: vec2, private _radius: number, private owner: GameObject) {
constructor(
private _center: vec2,
private _radius: number,
public owner: GameObject,
private readonly container: PhysicalContainer
) {
this._boundingBox = new BoundingBox(null);
this.recalculateBoundingBox();
}
@ -59,11 +77,11 @@ export class CirclePhysical implements Circle, Physical {
return vec2.distance(target.center, this.center) - this.radius - target.radius;
}
public areIntersecting(other: CirclePhysical): boolean {
public areIntersecting(other: Physical): boolean {
return other.distance(this.center) < this.radius;
}
public isInside(other: CirclePhysical): boolean {
public isInside(other: Physical): boolean {
return other.distance(this.center) < -this.radius;
}
@ -105,12 +123,13 @@ export class CirclePhysical implements Circle, Physical {
this.velocity = vec2.create();
}
/*public step(timeInMilliseconds: number): boolean {
public step(timeInMilliseconds: number): boolean {
vec2.scale(
this.velocity,
this.velocity,
Math.pow(settings.velocityAttenuation, timeInMilliseconds)
);
const distance = vec2.scale(vec2.create(), this.velocity, timeInMilliseconds);
const distanceLength = vec2.length(distance);
const stepCount = Math.ceil(distanceLength / settings.physicsMaxStep);
@ -119,22 +138,21 @@ export class CirclePhysical implements Circle, Physical {
let wasHit = false;
for (let i = 0; i < stepCount; i++) {
const { normal, tangent, hitSurface } = this.physics.tryMovingDynamicCircle(
const { normal, tangent, hitSurface } = moveCircle(
this,
distance
distance,
this.container.findIntersecting(this.boundingBox)
);
if (hitSurface) {
vec2.scale(this.velocity, tangent, vec2.dot(tangent, this.velocity));
wasHit = true;
}
this._isAirborne = !(
hitSurface && vec2.dot(normal, settings.gravitationalForce) < 0
);
this._isAirborne = hitSurface;
}
return wasHit;
}*/
}
public toJSON(): any {
const { center, radius } = this;