class Player extends GameObject{ //Main class for the Players involved in the game //including real life input and the paddleboard //Settings settings: Settings.Player //Online players lobby: Lobby //General color: Settings.Color thisStroke: string otherCount: number //Position and dimensions pos: Vector side: Direction dim: Vector margin: number //Movement vel: Vector absVel: number acc: Vector moveMargin: number //Competitive points: number hasLost: boolean //Boosts / Modifications boosts: ActiveBoost[] frameRate: number vision: boolean blinkProcess: TimeProcess constructor(side: Direction, id: string, settings: Settings.Player, otherCount: number, lobby?: Lobby){ super(id) this.settings = settings this.lobby = lobby this.otherCount = otherCount this.side = side this.setup(settings) } _input: Serialized.Player.Input get input(): Serialized.Player.Input{ let input = {up: null, down: null, right: null, left: null}; if (this.isRight){ if (p.keyIsDown(38)) input.up = true; if (p.keyIsDown(40)) input.down = true; } if (this.isLeft){ if (p.keyIsDown(87)) input.up = true; if (p.keyIsDown(83)) input.down = true; } if (this.isTop){ if (p.keyIsDown(65)) input.left = true; if (p.keyIsDown(68)) input.right = true; } if (this.isBottom){ if (p.keyIsDown(37)) input.left = true; if (p.keyIsDown(39)) input.right = true; } return input; } set input(input: Serialized.Player.Input){ this._input = input } get startPosition(): Vector{ let s = this.settings let side = this.side, d = s.depth, l = s.length, m = s.margin, cw = p.width, ch = p.height let x = (side === Direction.Left) ? m : (side === Direction.Right) ? (cw - m - d) : (side === Direction.Top || side === Direction.Bottom) ? (this.boxLeftSide + this.boxWidth / 2 - l / 2) : null let y = (side === Direction.Left || side === Direction.Right) ? (this.boxTopSide + this.boxHeight / 2 - l / 2) : (side === Direction.Top) ? m : (side === Direction.Bottom) ? (ch - m - d) : null if (x == null || y == null){ console.error('Something went wrong with computing the players positions. Side:', side) } return new Vector(x, y) } get startDimension(): Vector{ let s = this.settings let d = s.depth, l = s.length, side = this.side let x = (side === Direction.Left || side === Direction.Right) ? d : (side === Direction.Top || side === Direction.Bottom) ? l : null let y = (side === Direction.Left || side === Direction.Right) ? l : (side === Direction.Top || side === Direction.Bottom) ? d : null if (x == null || y == null){ console.error('Something went wrong with computing the players dimensions. Side:', side) } return new Vector(x, y) } get future(): Player{ let future = new Player(this.side, this.id, this.settings, this.otherCount) future.pos = this.pos.copy() future.vel = this.vel.copy() future.move() return future } get moveTopSide(): number{return this.boxTopSide + this.moveMargin} get moveBottomSide(): number{return this.boxBottomSide - this.moveMargin} get moveLeftSide(): number{return this.boxLeftSide + this.moveMargin} get moveRightSide(): number{return this.boxRightSide - this.moveMargin} get boxTopSide(): number{return (this.isTop ? 0 : (this.isBottom ? (p.height - this.margin) : (this.otherCount === 2 ? 0 : this.margin)))} get boxBottomSide(): number {return (this.isTop ? this.margin : ((this.isBottom || this.otherCount != 4) ? p.height : p.height - this.margin))} get boxLeftSide(): number {return this.isLeft ? 0 : (this.isRight ? p.width - this.margin : this.margin)} get boxRightSide(): number {return this.isLeft ? this.margin : (this.isRight ? p.width : p.width - this.margin)} get boxCenterX(): number {return (this.boxLeftSide + this.boxRightSide) / 2} get boxCenterY(): number {return (this.boxTopSide + this.boxBottomSide) / 2} get boxWidth(): number {return (this.isLeft || this.isRight) ? this.margin : p.width - 2 * this.margin} get boxHeight(): number {return ((this.isTop || this.isBottom) ? this.margin : (this.otherCount === 2) ? p.height : (this.otherCount === 3) ? p.height - this.margin : p.height - 2 * this.margin)} get isLeft(): boolean {return this.side === Direction.Left} get isRight(): boolean {return this.side === Direction.Right} get isTop(): boolean {return this.side === Direction.Top} get isBottom(): boolean {return this.side === Direction.Bottom} get leftSide(): number {return this.pos.x} get rightSide(): number {return this.pos.x + this.dim.x} get downSide(): number {return this.pos.y + this.dim.y} get upSide(): number {return this.pos.y} get toGameSide(): number {return this.isLeft ? this.rightSide : (this.isRight ? this.leftSide : (this.isTop ? this.downSide : (this.isBottom ? this.upSide : null)))} get centerX(): number {return this.leftSide + this.width / 2} get centerY(): number {return this.upSide + this.height / 2} get width(): number {return this.dim.x} get height(): number {return this.dim.y} setup(settings: Settings.Player): void{ this._input = {up: false, down: false, left: false, right: false} this.color = { stroke: settings.color.stroke, fill: settings.color.fill } this.thisStroke = settings.thisStroke this.margin = settings.margin this.pos = this.startPosition this.dim = this.startDimension this.vel = new Vector(0, 0) this.absVel = settings.absVel this.moveMargin = settings.moveMargin this.points = settings.points this.hasLost = false this.boosts = [] this.vision = false this.frameRate = 60 } applyValues(state: Serialized.GameObject | {[key: string]: number}): void{ let recurse = (objIn: any, objOut: any): void => { if (Array.isArray(objIn)){ for (let o1 of objOut){ let found = false for (let o2 of objIn){ if (o2 === o1){ found = true break } } if (!found){ objOut.splice(objOut.indexOf(o1), 1) } } } for (let p in objIn){ if (typeof objIn[p] == 'object' && objIn[p] != null){ if (!objOut[p]) objOut[p] = {}; recurse(objIn[p], objOut[p]) } else objOut[p] = objIn[p] } } recurse(state, this) } applyBoost(boost: Boost): void{ for (let b of this.boosts){ let index = this.boosts.indexOf(b) if (b.type === boost.type){ this.boosts.splice(index, 1) } } this.boosts.push(new ActiveBoost(this, boost)) } reset(): void{ this.setup(this.settings); } checkInputs(online: boolean): void{ let input: Serialized.Player.Input this.vel.mult(0) if (online) input = this._input else input = this.input if (this.isLeft || this.isRight){ if (input.up && this.upSide > this.boxTopSide + this.moveMargin) this.vel.y -= this.absVel if (input.down && this.downSide < this.boxBottomSide - this.moveMargin) this.vel.y += this.absVel } if (this.isTop || this.isBottom){ if (input.left && this.leftSide > this.boxLeftSide + this.moveMargin) this.vel.x -= this.absVel if (input.right && this.rightSide < this.boxRightSide - this.moveMargin) this.vel.x += this.absVel } } update(online: boolean): void{ this.checkInputs(online) this.updateBoosts() this.move() this.updateBlink() } updateBoosts(): void{ for (let b of this.boosts){ b.update() } } move(): void{ this.pos.add(this.vel) } equals(other: Player): boolean{ return this === other } lost(ball: Ball): void{ this.points-- this.blink({ stroke: 'rgb(255, 0, 0)', fill: 'rgb(100, 0, 0)' }) ball.reset(false) if (!this.points) this.hasLost = true } blink(color: Settings.Color): void{ this.color = color this.blinkProcess = new TimeProcess(this.settings.blinkTime) } updateBlink(): void{ if (this.blinkProcess){ this.blinkProcess.update() if (this.blinkProcess.finished){ this.color = { stroke: this.settings.color.stroke, fill: this.settings.color.fill } this.blinkProcess = null } } } copy(): Player{ let copy = new Player(this.side, this.id, this.settings, this.otherCount) copy.pos = this.pos.copy() copy.vel = this.vel.copy() return copy } serialized(): Serialized.Player{ let boosts: Serialized.ActiveBoost[] = [] for (let b of this.boosts) boosts.push(b.serialized()) return { id: this.id, pos: this.pos.serialized(), vel: this.vel.serialized(), dim: this.dim.serialized(), margin: this.margin, moveMargin: this.moveMargin, color: this.color, points: this.points, lobby: this.lobby.serialized(), input: this.input, boosts: boosts, frameRate: this.frameRate, vision: this.vision } } show(): void{ let stroke = this.color.stroke if (game instanceof OnlineGame){ if (game.getThisPlayer().id === this.id) stroke = this.thisStroke } p.fill(this.color.fill) p.stroke(stroke) p.strokeWeight(2) p.rect(this.leftSide, this.upSide, this.width, this.height, p.min([this.width, this.height]) * 0.5) p.fill(0, 255, 0) p.stroke(0) p.strokeWeight(5) if (this.isLeft || this.isRight){ p.line(this.leftSide, this.moveTopSide, this.rightSide, this.moveTopSide) p.line(this.leftSide, this.moveBottomSide, this.rightSide, this.moveBottomSide) } if (this.isTop || this.isBottom){ p.line(this.moveLeftSide, this.upSide, this.moveLeftSide, this.downSide) p.line(this.moveRightSide, this.upSide, this.moveRightSide, this.downSide) } p.textAlign('center', 'center') p.textSize(20) p.fill(0) p.strokeWeight(3) p.stroke(255, 0, 0) p.text(p.str(this.points), this.boxCenterX, this.boxCenterY) //TODO: Boost display for top and bottom players and add boost images let positiveCount = 0, negativeCount = 0 for (let b of this.boosts){ let positive = b.positive if (positive) positiveCount++ else negativeCount++ let boxX, boxY, boxSize = this.margin * 0.8, imgSize = boxSize * 0.7, imgX = (boxSize - imgSize) / 2, imgY = boxSize * 0.05, barW = boxSize * 0.9, barH = boxSize * 0.15, barX = (boxSize - barW) / 2, barY = boxSize - barH - boxSize * 0.05, processW = barW * (1 - b.time.now / b.time.max), margin = boxSize * 0.1 if (this.isLeft || this.isRight){ boxX = this.boxLeftSide + (this.margin - boxSize) / 2 boxY = this.boxCenterY - boxSize / 2 + (boxSize + margin) * (positive ? -positiveCount : negativeCount) } if (this.isTop || this.isBottom){ boxX = this.boxCenterX - boxSize / 2 + (boxSize + margin) * (positive ? -positiveCount : negativeCount) boxY = this.boxTopSide + (this.margin - boxSize) / 2 } //Box content p.push() p.translate(boxX, boxY) //Bar p.noFill() p.stroke(0) p.strokeWeight(1) p.rect(barX, barY, barW, barH, barH / 5) p.fill(b.color.fill) p.rect(barX, barY, processW, barH, barH / 5) //Image p.image(icons[b.type][b.bool], imgX, imgY, imgSize, imgSize) p.pop() } } }