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.
401 lines
11 KiB
401 lines
11 KiB
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()
|
|
}
|
|
}
|
|
}
|
|
|