import { Vector, VectorInteger } from "./Vector.js"; import { Component, Moving } from "./interface.js"; class Rectangle implements Component { pos: VectorInteger; width: number; height: number; constructor(pos: VectorInteger, width: number, height: number) { this.pos = Object.assign({}, pos); this.width = width; this.height = height; } collision(collider: Rectangle): boolean { const thisLeft = this.pos.x; const thisRight = this.pos.x + this.width; const thisTop = this.pos.y; const thisBottom = this.pos.y + this.height; const colliderLeft = collider.pos.x; const colliderRight = collider.pos.x + collider.width; const colliderTop = collider.pos.y; const colliderBottom = collider.pos.y + collider.height; if ((thisBottom < colliderTop) || (thisTop > colliderBottom) || (thisRight < colliderLeft) || (thisLeft > colliderRight)) { return false; } else { return true; } } } class MovingRectangle extends Rectangle implements Moving { dir: Vector = new Vector(0,0); speed: number; readonly baseSpeed: number; constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) { super(pos, width, height); this.baseSpeed = baseSpeed; this.speed = baseSpeed; } move(delta: number) { // Math.floor WIP until VectorInteger debug // console.log("delta: "+ delta); // console.log("speed: "+ this.speed); // console.log("speed*delta: "+ this.speed * delta); this.pos.x += Math.floor(this.dir.x * this.speed * delta); this.pos.y += Math.floor(this.dir.y * this.speed * delta); } moveAndCollide(delta: number, colliderArr: Rectangle[]) { let oldPos = Object.assign({}, this.pos); this.move(delta); if (colliderArr.some(this.collision, this)) { this.pos.x = oldPos.x; this.pos.y = oldPos.y; } } } class Racket extends MovingRectangle { constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) { super(pos, width, height, baseSpeed); } } class Ball extends MovingRectangle { readonly speedIncrease: number; constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number) { super(pos, size, size, baseSpeed); this.speedIncrease = speedIncrease; } bounce(collider?: Rectangle) { this._bounceAlgo(collider); } protected _bounceAlgo(collider?: Rectangle) { /* Could be more generic, but testing only Racket is enough, because in Pong collider can only be Racket or Wall. */ if (collider instanceof Racket) { this._bounceRacket(collider); } else { this._bounceWall(); } } moveAndBounce(delta: number, colliderArr: Rectangle[]) { this.move(delta); let i = colliderArr.findIndex(this.collision, this); if (i != -1) { this.bounce(colliderArr[i]); this.move(delta); } } protected _bounceWall() { // Should be enough for Wall this.dir.y = this.dir.y * -1; } protected _bounceRacket(racket: Racket) { this._bounceRacketAlgo(racket); } protected _bounceRacketAlgo(racket: Racket) { this.speed += this.speedIncrease; let x = this.dir.x * -1; const angleFactorDegree = 60; const angleFactor = angleFactorDegree / 90; const racketHalf = racket.height/2; const ballMid = this.pos.y + this.height/2; const racketMid = racket.pos.y + racketHalf; let impact = ballMid - racketMid; const horizontalMargin = racketHalf * 0.15; if (impact < horizontalMargin && impact > -horizontalMargin) { impact = 0; } else if (impact > 0) { impact = impact - horizontalMargin; } else if (impact < 0) { impact = impact + horizontalMargin; } let y = impact / (racketHalf - horizontalMargin) * angleFactor; // Normalize Vector (for consistency in speed independent of direction) this.dir.assign(x, y); this.dir = this.dir.normalized(); // console.log(`x: ${this.dir.x}, y: ${this.dir.y}`); } } export {Rectangle, MovingRectangle, Racket, Ball}