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.

367 lines
11 KiB

2 years ago
class Game{
//Absolute Main class for everything that is happening in pong
//Contains everything that appears in the gameplay
//Update method applies frame updates to every entity and/or process
//Settings
settings: Settings.Game
//Entities
players: Player[]
balls: Ball[]
//Items
boosts: Boost[]
wormholes: Wormhole[]
newBalls: NewBall[]
//Gameplay
finished: boolean
paused: boolean
constructor(settings: Settings.Game){
this.settings = settings
}
init(lobby?: Lobby): void{
this.players = this.createPlayers(['0', '1'])
this.balls = this.createBalls('0')
this.boosts = []
this.wormholes = []
this.newBalls = []
this.play()
}
createPlayer(side: Direction, id: string, otherCount: number): Player{
return new Player(side, id, this.settings.player, otherCount)
}
createPlayers(ids: string[]): Player[]{
switch (ids.length){
case 2:
return [
this.createPlayer(Direction.Left, ids[0], 2),
this.createPlayer(Direction.Right, ids[1], 2)
]
case 3:
return [
this.createPlayer(Direction.Left, ids[0], 3),
this.createPlayer(Direction.Right, ids[1], 3),
this.createPlayer(Direction.Top, ids[2], 3)
]
case 4:
return [
this.createPlayer(Direction.Left, ids[0], 4),
this.createPlayer(Direction.Right, ids[1], 4),
this.createPlayer(Direction.Top, ids[2], 4),
this.createPlayer(Direction.Bottom, ids[3], 4)
]
}
}
createBall(id: string): Ball{
return new Ball(this.settings.ball, id)
}
createBalls(...ids: string[]): Ball[]{
let balls = []
for (let id of ids)
balls.push(this.createBall(id))
return balls
}
finish(): void{
this.pause()
this.finished = true
}
restart(): void{
this.finished = false
this.init()
}
play(): void{
if (this.finished) this.restart()
this.paused = false
$('#toggle-play').addClass('paused')
}
pause(): void{
if (this.finished) return
this.paused = true
$('#toggle-play').removeClass('paused')
}
togglePlay(fromClient?: boolean, fromInitiator?: boolean): void{
$('#toggle-play').blur()
if (this.paused){
this.play()
} else {
this.pause()
}
}
update(online?: boolean): void{
if (this.paused) return
for (let p of this.players) p.update(online)
for (let b of this.balls) b.update(this.balls, this.players, this.boosts, this.wormholes, this.newBalls)
for (let b of this.boosts) b.update()
for (let b of this.wormholes) b.update()
for (let n of this.newBalls) n.update()
this.tryCreateItem(Boost, this.settings.item.boost, this.boosts)
this.tryCreateItem(Wormhole, this.settings.item.wormhole, this.wormholes)
this.tryCreateItem(NewBall, this.settings.item.newBall, this.newBalls)
for (let p of this.players) if (p.hasLost) this.finish()
}
tryCreateItem(Type: typeof Item, settings: Settings.Item, items: Item[]){
if (ranBool(p.int(p.frameRate()) * settings.spawnTime)){
items.push(Item.fromNew(this.players, settings, Type))
}
}
display(): void{
this.deadZone()
for (let p of this.players) p.show()
for (let b of this.balls) b.show()
for (let b of this.boosts) b.show()
for (let w of this.wormholes) w.show()
for (let n of this.newBalls) n.show()
}
deadZone(): void{
p.noFill()
p.stroke(255, 0, 0)
p.strokeWeight(3)
for (let pl of this.players){
p.beginShape()
if (pl.isLeft || pl.isRight){
for (let y = pl.boxTopSide; y < pl.boxBottomSide; y++){
let x = p.map(p.noise(p.random(p.frameCount)), 0, 1, -pl.width / 2, pl.width / 2) + pl.centerX
p.vertex(x, y)
}
}
if (pl.isTop || pl.isBottom){
for (let x = pl.boxLeftSide; x < pl.boxRightSide; x++){
let y = p.map(p.noise(p.random(p.frameCount)), 0, 1, -pl.height / 2, pl.height / 2) + pl.centerY
p.vertex(x, y)
}
}
p.endShape()
}
}
}
class OnlineGame extends Game{
//Main class for a game that is played via WebRTC Connection
id: string
lobby: Lobby
socket: any
p2p: any
input: Serialized.Player.Input
initiator: boolean
packetManager: {
count: number
lastTime: number
deltaTime: number
time: number
}
constructor(socket: any, p2p: any, settings: Settings.Game){
super(settings)
this.socket = socket
this.p2p = p2p
this.packetManager = {
count: 0,
lastTime: Date.now(),
deltaTime: 0,
time: 0
}
}
set data(data: Serialized.Game){
let pm = this.packetManager
pm.count++
pm.deltaTime = Date.now() - pm.lastTime
pm.lastTime = Date.now()
pm.time += pm.deltaTime
if (pm.time > 5000){
console.log(pm.count + ' Data packs received from leading Peer, last one: ', data)
pm.count = 0
pm.time = 0
}
//Function to apply new values to objects which can disappear or appear
function applyValues(Type: typeof GameObject | typeof Player | typeof Ball | typeof Item,
objects1: Serialized.GameObject[], objects2: GameObject[],
settings: any): void{
for (let o1 of objects1){
let found = false
for (let o2 of objects2){
if (o1.id === o2.id){
o2.applyValues(o1)
found = true
}
}
if (!found){
let newObject
switch (Type){
case Boost:
case Wormhole:
newObject = Item.fromSerialized(o1, settings, Type)
break
case Ball:
newObject = Ball.fromSerialized(o1, settings)
break
case NewBall:
newObject = Item.fromSerialized(o1, settings, Type)
break
}
objects2.push(newObject)
}
}
for (let o2 of objects2){
let found = false
for (let o1 of objects1){
if (o1.id === o2.id) found = true
}
if (!found){
let index = objects2.indexOf(o2)
objects2.splice(index, 1)
}
}
}
applyValues(Player, data.players, this.players, this.settings.player)
applyValues(Ball, data.balls, this.balls, this.settings.ball)
applyValues(Boost, data.boosts, this.boosts, this.settings.item.boost)
applyValues(Wormhole, data.wormholes, this.wormholes, this.settings.item.wormhole)
applyValues(NewBall, data.newBalls, this.newBalls, this.settings.item.newBall)
}
init(lobby: Lobby): void{
this.input = {up: false, down: false, left: false, right: false}
this.lobby = lobby
this.id = this.lobby.id
//The initiator runs the actual game
//and sends the game to other peers
this.initiator = (this.socket.id === this.lobby.leader.id)
let ids = []
for (let p of this.lobby.clients) ids.push(p.id)
this.players = this.createPlayers(ids)
this.balls = this.createBalls(this.lobby.leader.id)
this.boosts = []
this.wormholes = []
this.newBalls = []
}
createPlayer(side: Direction, id: string, otherCount: number): Player{
return new Player(side, id, this.settings.player, otherCount, this.lobby)
}
setPlayerInput(player: any): void{
for (let p of this.players){
if (p.id === player.id){
p.input = player.input
}
}
}
sendInput(): void{
let player = {
id: this.getThisPlayer().id,
input: this.input,
lobby: this.getThisPlayer().lobby
}
if (this.initiator){
this.setPlayerInput(player)
} else {
this.p2p.emit('player-input', player)
}
}
getThisPlayer(): Player{
for (let p of this.players){
if (p.id === this.socket.id)
return p
}
}
togglePlay(fromClient: boolean, fromInitiator: boolean): void{
if (this.initiator){
super.togglePlay()
this.emitAction('togglePlay')
} else {
if (fromInitiator){
super.togglePlay()
} else {
if (fromClient){
this.emitAction('togglePlay')
}
}
}
}
update(): void{
if (this.initiator){
super.update(true)
this.p2p.emit('game-data', this.serialized())
}
}
emitAction(action: string){
this.p2p.emit('game-action', {
action: action,
lobby: this.lobby.serialized(),
fromInitiator: this.initiator
})
}
finish(): void{
super.finish()
if (this.initiator)
this.emitAction('finish')
}
restart(){
this.finished = false
this.init(this.lobby)
}
serialized(): Serialized.Game{
let players: Serialized.Player[] = [],
balls: Serialized.Ball[] = [],
boosts: Serialized.Boost[] = [],
wormholes: Serialized.Wormhole[] = [],
newBalls: Serialized.NewBall[] = []
for (let b of this.balls) balls.push(b.serialized())
for (let p of this.players) players.push(p.serialized())
for (let b of this.boosts) boosts.push(b.serialized())
for (let w of this.wormholes) wormholes.push(w.serialized())
for (let n of this.newBalls) newBalls.push(n.serialized())
return {
players: players,
balls: balls,
boosts: boosts,
wormholes: wormholes,
newBalls: newBalls,
id: this.id
}
}
}