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
367 lines
11 KiB
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
|
|
}
|
|
}
|
|
} |