You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
11 KiB

2 years ago
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()
}
}
}