diff --git a/src/simulator/hitbox.ts b/src/simulator/hitbox.ts index ac00e60..3af1f93 100644 --- a/src/simulator/hitbox.ts +++ b/src/simulator/hitbox.ts @@ -5,12 +5,7 @@ import type { Point } from "./render/render"; import { Emitter, type Event } from "@/common/event"; import { Disposable, type IDisposable } from "@/common/lifecycle"; -export interface OnHitListenerData { - obj: CanvasObject - depth: number -} - -export interface IHitbox extends IDisposable { +export interface IHitbox extends IDisposable { anchor: Point /** @@ -33,12 +28,12 @@ export interface IHitbox extends IDisposable { */ cancelNextTest(): void - onHit: Event + onHit: Event } -export abstract class Hitbox extends Disposable implements IHitbox { +export abstract class Hitbox extends Disposable implements IHitbox { // events - protected _onHit = new Emitter(); + protected _onHit: Emitter = new Emitter(); protected _isNextTestCancelled: boolean = false; diff --git a/src/simulator/hitboxes/convexHitbox.ts b/src/simulator/hitboxes/convexHitbox.ts index 6e201e0..c1df030 100644 --- a/src/simulator/hitboxes/convexHitbox.ts +++ b/src/simulator/hitboxes/convexHitbox.ts @@ -6,12 +6,17 @@ import { Hitbox, type IHitbox } from "@/simulator/hitbox"; import { RoundHitbox } from "./roundHitbox"; -interface IConvexHitbox extends IHitbox { +interface OnHitListenerData { + overlayX: number + overlayY: number +} + +interface IConvexHitbox extends IHitbox { width: number height: number } -export class ConvexHitbox extends Hitbox implements IConvexHitbox { +export class ConvexHitbox extends Hitbox implements IConvexHitbox { public constructor( public width: number, @@ -36,7 +41,27 @@ export class ConvexHitbox extends Hitbox implements IConvexHitbox { this.anchor.y > hitbox.anchor.y - this.height && this.anchor.y < hitbox.anchor.y + hitbox.height ) { - this._onHit.fire({ obj, depth: 0 }); + this._onHit.fire({ + obj, + overlayX: ( + this.anchor.x === hitbox.anchor.x + ? 0 + : ( + this.anchor.x > hitbox.anchor.x + ? -(hitbox.width - this.anchor.x + hitbox.anchor.x) + : this.width - hitbox.anchor.x + this.anchor.x + ) + ), + overlayY: ( + this.anchor.y === hitbox.anchor.y + ? 0 + : ( + this.anchor.y > hitbox.anchor.y + ? -(hitbox.height - this.anchor.y + hitbox.anchor.y) + : this.height - hitbox.anchor.y + this.anchor.y + ) + ) + }); } } else if(hitbox instanceof RoundHitbox) { const diameter = 2 * hitbox.radius; @@ -47,7 +72,27 @@ export class ConvexHitbox extends Hitbox implements IConvexHitbox { hitbox.anchor.y > this.anchor.y - diameter && hitbox.anchor.y < this.anchor.y + this.height ) { - this._onHit.fire({ obj, depth: 0 }); + this._onHit.fire({ + obj, + overlayX: ( + this.anchor.x === hitbox.anchor.x + ? 0 + : ( + this.anchor.x > hitbox.anchor.x + ? -(diameter - this.anchor.x + hitbox.anchor.x) + : this.width - hitbox.anchor.x + this.anchor.x + ) + ), + overlayY: ( + this.anchor.y === hitbox.anchor.y + ? 0 + : ( + this.anchor.y > hitbox.anchor.y + ? -(diameter - this.anchor.y + hitbox.anchor.y) + : this.height - hitbox.anchor.y + this.anchor.y + ) + ) + }); } } } diff --git a/src/simulator/hitboxes/groundHitbox.ts b/src/simulator/hitboxes/groundHitbox.ts index 21fe91d..5f93888 100644 --- a/src/simulator/hitboxes/groundHitbox.ts +++ b/src/simulator/hitboxes/groundHitbox.ts @@ -6,11 +6,15 @@ import { Block } from "@/simulator/objects/block"; import { RoundHitbox } from "./roundHitbox"; -interface IGroundHitbox extends IHitbox { +interface OnHitListenerData { + depth: number +} + +interface IGroundHitbox extends IHitbox { } -export class GroundHitbox extends Hitbox implements IGroundHitbox { +export class GroundHitbox extends Hitbox implements IGroundHitbox { public constructor(anchor: Point) { // anchor = (0, canvas.height - GROUND_HEIGHT) super(anchor); } diff --git a/src/simulator/hitboxes/roundHitbox.ts b/src/simulator/hitboxes/roundHitbox.ts index 9da12ac..1858d6e 100644 --- a/src/simulator/hitboxes/roundHitbox.ts +++ b/src/simulator/hitboxes/roundHitbox.ts @@ -5,11 +5,16 @@ import type { Canvas } from "@/ui/canvas/canvas"; import { Hitbox, type IHitbox } from "@/simulator/hitbox"; import { getPointDistance } from "@/common/utils/utils"; -interface IRoundHitbox extends IHitbox { +interface OnHitListenerData { + depth: number +} + +interface IRoundHitbox extends IHitbox { radius: number } -export class RoundHitbox extends Hitbox implements IRoundHitbox { +export class RoundHitbox extends Hitbox implements IRoundHitbox { + public constructor(public radius: number, anchor: Point) { super(anchor); diff --git a/src/simulator/objects/ball.ts b/src/simulator/objects/ball.ts index a143321..1c51ae2 100644 --- a/src/simulator/objects/ball.ts +++ b/src/simulator/objects/ball.ts @@ -85,18 +85,36 @@ export class Ball extends CanvasObject { const massSum = this.mass + obj.mass; /** *m1 - m2* */ const massDiff = this.mass - obj.mass; + + const vx1 = this.velocity.getComponent(new Vector(1, 0)); + const vy1 = this.velocity.getComponent(new Vector(0, 1)); + const vx2 = obj.velocity.getComponent(new Vector(1, 0)); + const vy2 = obj.velocity.getComponent(new Vector(0, 1)); + + // X direction /** *((m2 - m1) v2) / (m1 + m2)* */ - const va = Vector.multiplyScalar(obj.velocity, -massDiff / massSum); + const vxa = Vector.multiplyScalar(vx2, -massDiff / massSum); + /** *(2 m1 v1) / (m1 + m2)* */ + const vxb = Vector.multiplyScalar(vx1, (2 * this.mass) / massSum); + /** *((m1 - m2) v1) / (m1 + m2)* */ + const vxc = Vector.multiplyScalar(vx1, massDiff / massSum); + /** *(2 m2 v2) / (m1 + m2)* */ + const vxd = Vector.multiplyScalar(vx2, (2 * obj.mass) / massSum); + + // Y direction + + /** *((m2 - m1) v2) / (m1 + m2)* */ + const vya = Vector.multiplyScalar(vy2, -massDiff / massSum); /** *(2 m1 v1) / (m1 + m2)* */ - const vb = Vector.multiplyScalar(this.velocity, (2 * this.mass) / massSum); + const vyb = Vector.multiplyScalar(vy1, (2 * this.mass) / massSum); /** *((m1 - m2) v1) / (m1 + m2)* */ - const vc = Vector.multiplyScalar(this.velocity, massDiff / massSum); + const vyc = Vector.multiplyScalar(vy1, massDiff / massSum); /** *(2 m2 v2) / (m1 + m2)* */ - const vd = Vector.multiplyScalar(obj.velocity, (2 * obj.mass) / massSum); + const vyd = Vector.multiplyScalar(vy2, (2 * obj.mass) / massSum); - obj.velocity = Vector.add(va, vb); // v2' - this.velocity = Vector.add(vc, vd); // v1' + obj.velocity = Vector.add(Vector.add(vxa, vxb), Vector.add(vya, vyb)); // v2' + this.velocity = Vector.add(Vector.add(vxc, vxd), Vector.add(vyc, vyd)); // v1' } })); diff --git a/src/simulator/objects/block.ts b/src/simulator/objects/block.ts index 2909214..39acba5 100644 --- a/src/simulator/objects/block.ts +++ b/src/simulator/objects/block.ts @@ -55,7 +55,7 @@ export class Block extends CanvasObject { })); this.applyGravity(); - this._register(this.hitbox.onHit(({ obj, depth }) => { + this._register(this.hitbox.onHit(({ obj, overlayX, overlayY }) => { if(obj instanceof Block || obj instanceof Ball) { obj.hitbox.cancelNextTest(); @@ -63,14 +63,14 @@ export class Block extends CanvasObject { * To prevent objects from going through each other */ - const p1 = this.hitbox.anchor; - const p2 = obj.hitbox.anchor; - const movement = Vector.multiplyScalar(Vector.fromPoints(p1, p2).getUnitVector(), depth); - - this.obj.x -= movement.x / 2; - this.obj.y -= movement.y / 2; - obj.obj.x += movement.x / 2; - obj.obj.y += movement.y / 2; + // Test which side the hit happens (left right side / top side) + if(Math.abs(overlayX) < Math.abs(overlayY) && overlayX !== 0) { + this.obj.x -= overlayX / 2; + obj.obj.x += overlayX / 2; + } else { + this.obj.y -= overlayY / 2; + obj.obj.y += overlayY / 2; + } this.updateHitboxAnchor(); obj.updateHitboxAnchor(); @@ -87,17 +87,35 @@ export class Block extends CanvasObject { /** *m1 - m2* */ const massDiff = this.mass - obj.mass; + const vx1 = this.velocity.getComponent(new Vector(1, 0)); + const vy1 = this.velocity.getComponent(new Vector(0, 1)); + const vx2 = obj.velocity.getComponent(new Vector(1, 0)); + const vy2 = obj.velocity.getComponent(new Vector(0, 1)); + + // X direction + + /** *((m2 - m1) v2) / (m1 + m2)* */ + const vxa = Vector.multiplyScalar(vx2, -massDiff / massSum); + /** *(2 m1 v1) / (m1 + m2)* */ + const vxb = Vector.multiplyScalar(vx1, (2 * this.mass) / massSum); + /** *((m1 - m2) v1) / (m1 + m2)* */ + const vxc = Vector.multiplyScalar(vx1, massDiff / massSum); + /** *(2 m2 v2) / (m1 + m2)* */ + const vxd = Vector.multiplyScalar(vx2, (2 * obj.mass) / massSum); + + // Y direction + /** *((m2 - m1) v2) / (m1 + m2)* */ - const va = Vector.multiplyScalar(obj.velocity, -massDiff / massSum); + const vya = Vector.multiplyScalar(vy2, -massDiff / massSum); /** *(2 m1 v1) / (m1 + m2)* */ - const vb = Vector.multiplyScalar(this.velocity, (2 * this.mass) / massSum); + const vyb = Vector.multiplyScalar(vy1, (2 * this.mass) / massSum); /** *((m1 - m2) v1) / (m1 + m2)* */ - const vc = Vector.multiplyScalar(this.velocity, massDiff / massSum); + const vyc = Vector.multiplyScalar(vy1, massDiff / massSum); /** *(2 m2 v2) / (m1 + m2)* */ - const vd = Vector.multiplyScalar(obj.velocity, (2 * obj.mass) / massSum); + const vyd = Vector.multiplyScalar(vy2, (2 * obj.mass) / massSum); - obj.velocity = Vector.add(va, vb); // v2' - this.velocity = Vector.add(vc, vd); // v1' + obj.velocity = Vector.add(Vector.add(vxa, vxb), Vector.add(vya, vyb)); // v2' + this.velocity = Vector.add(Vector.add(vxc, vxd), Vector.add(vyc, vyd)); // v1' } }));