diff --git a/bkcore/hexgl/Gameplay.js b/bkcore/hexgl/Gameplay.js index 9827deef..cccfea10 100644 --- a/bkcore/hexgl/Gameplay.js +++ b/bkcore/hexgl/Gameplay.js @@ -1,231 +1,250 @@ - /* +/* * HexGL * @author Thibaut 'BKcore' Despoulain - * @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License. + * @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License. * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/. */ var bkcore = bkcore || {}; bkcore.hexgl = bkcore.hexgl || {}; -bkcore.hexgl.Gameplay = function(opts) -{ - var self = this; - - this.startDelay = opts.hud == null ? 0 : 1000; - this.countDownDelay = opts.hud == null ? 1000 : 1500; - - this.active = false; - this.timer = new bkcore.Timer(); - this.modes = { - 'timeattack':null, - 'survival':null, - 'replay':null - }; - this.mode = opts.mode == undefined || !(opts.mode in this.modes) ? "timeattack" : opts.mode; - this.step = 0; - - this.hud = opts.hud; - this.shipControls = opts.shipControls; - this.cameraControls = opts.cameraControls; - this.track = opts.track; - this.analyser = opts.analyser; - this.pixelRatio = opts.pixelRatio; - - this.previousCheckPoint = -1; - - this.results = { - FINISH: 1, - DESTROYED: 2, - WRONGWAY: 3, - REPLAY: 4, - NONE: -1 - }; - this.result = this.results.NONE; - - this.lap = 1; - this.lapTimes = []; - this.lapTimeElapsed = 0; - this.maxLaps = 3; - this.score = null; - this.finishTime = null; - this.onFinish = opts.onFinish == undefined ? function(){console.log("FINISH");} : opts.onFinish; - - this.raceData = null; - - this.modes.timeattack = function() - { - self.raceData.tick(this.timer.time.elapsed); - - self.hud != null && self.hud.updateTime(self.timer.getElapsedTime()); - var cp = self.checkPoint(); - - if(cp == self.track.checkpoints.start && self.previousCheckPoint == self.track.checkpoints.last) - { - self.previousCheckPoint = cp; - var t = self.timer.time.elapsed; - self.lapTimes.push(t - self.lapTimeElapsed); - self.lapTimeElapsed = t; - - if(self.lap == this.maxLaps) - { - self.end(self.results.FINISH); - } - else - { - self.lap++; - self.hud != null && self.hud.updateLap(self.lap, self.maxLaps); - - if(self.lap == self.maxLaps) - self.hud != null && self.hud.display("Final lap", 0.5); - } - } - else if(cp != -1 && cp != self.previousCheckPoint) - { - self.previousCheckPoint = cp; - //self.hud.display("Checkpoint", 0.5); - } - - if(self.shipControls.destroyed == true) - { - self.end(self.results.DESTROYED); - } - }; - - this.modes.replay = function() - { - self.raceData.applyInterpolated(this.timer.time.elapsed); - - if(self.raceData.seek == self.raceData.last) - { - self.end(self.result.REPLAY); - } - }; -} - -bkcore.hexgl.Gameplay.prototype.simu = function() -{ - this.lapTimes = [92300, 91250, 90365]; - this.finishTime = this.lapTimes[0]+this.lapTimes[1]+this.lapTimes[2]; - if(this.hud != null) this.hud.display("Finish"); - this.step = 100; - this.result = this.results.FINISH; - this.shipControls.active = false; -} - -bkcore.hexgl.Gameplay.prototype.start = function(opts) -{ - this.finishTime = null; - this.score = null; - this.lap = 1; - - this.shipControls.reset(this.track.spawn, this.track.spawnRotation); - this.shipControls.active = false; - - this.previousCheckPoint = this.track.checkpoints.start; - - this.raceData = new bkcore.hexgl.RaceData(this.track.name, this.mode, this.shipControls); - if(this.mode == 'replay') - { - this.cameraControls.mode = this.cameraControls.modes.ORBIT; - if(this.hud != null) this.hud.messageOnly = true; - - try { - var d = localStorage['race-'+this.track.name+'-replay']; - if(d == undefined) - { - console.error('No replay data for '+'race-'+this.track.name+'-replay'+'.'); - return false; - } - this.raceData.import( - JSON.parse(d) - ); - } - catch(e) { console.error('Bad replay format : '+e); return false; } - } - - this.active = true; - this.step = 0; - this.timer.start(); - if(this.hud != null) - { - this.hud.resetTime(); - this.hud.display("Get ready", 1); - this.hud.updateLap(this.lap, this.maxLaps); - } -} - -bkcore.hexgl.Gameplay.prototype.end = function(result) -{ - this.score = this.timer.getElapsedTime(); - this.finishTime = this.timer.time.elapsed; - this.timer.start(); - this.result = result; - - this.shipControls.active = false; - - if(result == this.results.FINISH) - { - if(this.hud != null) this.hud.display("Finish"); - this.step = 100; - } - else if(result == this.results.DESTROYED) - { - if(this.hud != null) this.hud.display("Destroyed"); - this.step = 100; - } -} - -bkcore.hexgl.Gameplay.prototype.update = function() -{ - if(!this.active) return; - - this.timer.update(); - - if(this.step == 0 && this.timer.time.elapsed >= this.countDownDelay+this.startDelay) - { - if(this.hud != null) this.hud.display("3"); - this.step = 1; - } - else if(this.step == 1 && this.timer.time.elapsed >= 2*this.countDownDelay+this.startDelay) - { - if(this.hud != null) this.hud.display("2"); - this.step = 2; - } - else if(this.step == 2 && this.timer.time.elapsed >= 3*this.countDownDelay+this.startDelay) - { - if(this.hud != null) this.hud.display("1"); - this.step = 3; - } - else if(this.step == 3 && this.timer.time.elapsed >= 4*this.countDownDelay+this.startDelay) - { - if(this.hud != null) this.hud.display("Go", 0.5); - this.step = 4; - this.timer.start(); - - if(this.mode != "replay") - this.shipControls.active = true; - } - else if(this.step == 4) - { - this.modes[this.mode].call(this); - } - else if(this.step == 100 && this.timer.time.elapsed >= 2000) - { - this.active = false; - this.onFinish.call(this); - } -} - -bkcore.hexgl.Gameplay.prototype.checkPoint = function() -{ - var x = Math.round(this.analyser.pixels.width/2 + this.shipControls.dummy.position.x * this.pixelRatio); - var z = Math.round(this.analyser.pixels.height/2 + this.shipControls.dummy.position.z * this.pixelRatio); - - var color = this.analyser.getPixel(x, z); - - if(color.r == 255 && color.g == 255 && color.b < 250) - return color.b; - else - return -1; -} \ No newline at end of file +bkcore.hexgl.Gameplay = function (opts) { + var self = this; + + this.startDelay = opts.hud == null ? 0 : 1000; + this.countDownDelay = opts.hud == null ? 1000 : 1500; + this.lastCoinUpdate = 0; // Track when we last updated the coin counter + + this.active = false; + this.timer = new bkcore.Timer(); + this.modes = { + timeattack: null, + survival: null, + replay: null, + }; + this.mode = + opts.mode == undefined || !(opts.mode in this.modes) + ? "timeattack" + : opts.mode; + this.step = 0; + + this.hud = opts.hud; + this.shipControls = opts.shipControls; + this.cameraControls = opts.cameraControls; + this.track = opts.track; + this.analyser = opts.analyser; + this.pixelRatio = opts.pixelRatio; + + this.previousCheckPoint = -1; + + this.results = { + FINISH: 1, + DESTROYED: 2, + WRONGWAY: 3, + REPLAY: 4, + NONE: -1, + }; + this.result = this.results.NONE; + + this.lap = 1; + this.lapTimes = []; + this.lapTimeElapsed = 0; + this.maxLaps = 3; + this.score = null; + this.finishTime = null; + this.onFinish = + opts.onFinish == undefined + ? function () { + console.log("FINISH"); + } + : opts.onFinish; + + this.raceData = null; + + this.modes.timeattack = function () { + self.raceData.tick(this.timer.time.elapsed); + + self.hud != null && self.hud.updateTime(self.timer.getElapsedTime()); + var cp = self.checkPoint(); + + if ( + cp == self.track.checkpoints.start && + self.previousCheckPoint == self.track.checkpoints.last + ) { + self.previousCheckPoint = cp; + var t = self.timer.time.elapsed; + self.lapTimes.push(t - self.lapTimeElapsed); + self.lapTimeElapsed = t; + + if (self.lap == this.maxLaps) { + self.end(self.results.FINISH); + } else { + self.lap++; + self.hud != null && self.hud.updateLap(self.lap, self.maxLaps); + + if (self.lap == self.maxLaps) + self.hud != null && self.hud.display("Final lap", 0.5); + } + } else if (cp != -1 && cp != self.previousCheckPoint) { + self.previousCheckPoint = cp; + //self.hud.display("Checkpoint", 0.5); + } + + if (self.shipControls.destroyed == true) { + self.end(self.results.DESTROYED); + } + }; + + this.modes.replay = function () { + self.raceData.applyInterpolated(this.timer.time.elapsed); + + if (self.raceData.seek == self.raceData.last) { + self.end(self.result.REPLAY); + } + }; +}; + +bkcore.hexgl.Gameplay.prototype.simu = function () { + this.lapTimes = [92300, 91250, 90365]; + this.finishTime = this.lapTimes[0] + this.lapTimes[1] + this.lapTimes[2]; + if (this.hud != null) this.hud.display("Finish"); + this.step = 100; + this.result = this.results.FINISH; + this.shipControls.active = false; +}; + +bkcore.hexgl.Gameplay.prototype.start = function (opts) { + this.finishTime = null; + this.score = null; + this.lap = 1; + + this.shipControls.reset(this.track.spawn, this.track.spawnRotation); + this.shipControls.active = false; + + this.previousCheckPoint = this.track.checkpoints.start; + + this.raceData = new bkcore.hexgl.RaceData( + this.track.name, + this.mode, + this.shipControls, + ); + if (this.mode == "replay") { + this.cameraControls.mode = this.cameraControls.modes.ORBIT; + if (this.hud != null) this.hud.messageOnly = true; + + try { + var d = localStorage["race-" + this.track.name + "-replay"]; + if (d == undefined) { + console.error( + "No replay data for " + "race-" + this.track.name + "-replay" + ".", + ); + return false; + } + this.raceData.import(JSON.parse(d)); + } catch (e) { + console.error("Bad replay format : " + e); + return false; + } + } + + this.active = true; + this.step = 0; + this.timer.start(); + if (this.hud != null) { + this.hud.resetTime(); + this.hud.display("Get ready", 1); + this.hud.updateLap(this.lap, this.maxLaps); + } +}; + +bkcore.hexgl.Gameplay.prototype.end = function (result) { + this.score = this.timer.getElapsedTime(); + this.finishTime = this.timer.time.elapsed; + this.timer.start(); + this.result = result; + + this.shipControls.active = false; + + if (result == this.results.FINISH) { + if (this.hud != null) this.hud.display("Finish"); + this.step = 100; + } else if (result == this.results.DESTROYED) { + if (this.hud != null) this.hud.display("Destroyed"); + this.step = 100; + } +}; + +bkcore.hexgl.Gameplay.prototype.update = function () { + if (!this.active) return; + + this.timer.update(); + + if ( + this.step == 0 && + this.timer.time.elapsed >= this.countDownDelay + this.startDelay + ) { + if (this.hud != null) this.hud.display("3"); + this.step = 1; + } else if ( + this.step == 1 && + this.timer.time.elapsed >= 2 * this.countDownDelay + this.startDelay + ) { + if (this.hud != null) this.hud.display("2"); + this.step = 2; + } else if ( + this.step == 2 && + this.timer.time.elapsed >= 3 * this.countDownDelay + this.startDelay + ) { + if (this.hud != null) this.hud.display("1"); + this.step = 3; + } else if ( + this.step == 3 && + this.timer.time.elapsed >= 4 * this.countDownDelay + this.startDelay + ) { + if (this.hud != null) this.hud.display("Go", 0.5); + this.step = 4; + this.timer.start(); + + if (this.mode != "replay") this.shipControls.active = true; + } else if (this.step == 4) { + this.modes[this.mode].call(this); + + // Update coin counter every 10 seconds, but only if the vehicle is moving + if (this.shipControls) { + // Check if the ship is moving using speed ratio (0-1) + var speedRatio = this.shipControls.getSpeedRatio(); + var isMoving = speedRatio > 0.01; // 1% of max speed threshold + var currentTime = this.timer.time.elapsed / 1000; // Convert to seconds + + // Debug: Uncomment to see the speed ratio in console + // if (this.debugCounter++ % 60 === 0) console.log('Speed Ratio:', speedRatio, 'Moving:', isMoving); + + if (isMoving && currentTime - this.lastCoinUpdate >= 10) { + this.lastCoinUpdate = currentTime; + if (this.hud) { + this.hud.coinCount++; + this.hud.updateCoins(this.hud.coinCount); + } + } + } + } else if (this.step == 100 && this.timer.time.elapsed >= 2000) { + this.active = false; + this.onFinish.call(this); + } +}; + +bkcore.hexgl.Gameplay.prototype.checkPoint = function () { + var x = Math.round( + this.analyser.pixels.width / 2 + + this.shipControls.dummy.position.x * this.pixelRatio, + ); + var z = Math.round( + this.analyser.pixels.height / 2 + + this.shipControls.dummy.position.z * this.pixelRatio, + ); + + var color = this.analyser.getPixel(x, z); + + if (color.r == 255 && color.g == 255 && color.b < 250) return color.b; + else return -1; +}; diff --git a/bkcore/hexgl/HUD.js b/bkcore/hexgl/HUD.js index 068e123d..b04d3246 100644 --- a/bkcore/hexgl/HUD.js +++ b/bkcore/hexgl/HUD.js @@ -1,270 +1,295 @@ - /* +/* * HexGL * @author Thibaut 'BKcore' Despoulain - * @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License. + * @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License. * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/. */ var bkcore = bkcore || {}; bkcore.hexgl = bkcore.hexgl || {}; -bkcore.hexgl.HUD = function(opts) -{ - var self = this; - - this.visible = true; - this.messageOnly = false; - - this.width = opts.width; - this.height = opts.height; - - this.canvas = document.createElement('canvas'); - this.canvas.width = this.width; - this.canvas.height = this.height; - - this.ctx = this.canvas.getContext('2d'); - this.ctx.textAlign = "center"; - - this.bg = opts.bg;//"textures/hud/hud-bg.png"; - - this.fgspeed = opts.speed;//"textures/hud/hud-fg-speed.png"; - - this.fgshield = opts.shield;//"textures/hud/hud-fg-shield.png"; - - this.speedFontRatio = 24; - this.speedBarRatio = 2.91; - this.shieldFontRatio = 64; - this.shieldBarYRatio = 34; - this.shieldBarWRatio = 18.3; - this.shieldBarHRatio = 14.3; - this.timeMarginRatio = 18; - this.timeFontRatio = 19.2; - - this.font = opts.font || "Arial"; - - this.time = ""; - - this.message = ""; - this.previousMessage = ""; - this.messageTiming = 0; - this.messagePos = 0.0; - this.messagePosTarget = 0.0; - this.messagePosTargetRatio = 12; - this.messageA = 1.0; - this.messageAS = 1.0; - this.messageDuration = 2*60; - this.messageDurationD = 2*60; - this.messageDurationS = 30; - this.messageYRatio = 34; - this.messageFontRatio = 10; - this.messageFontRatioStart = 6; - this.messageFontRatioEnd = 10; - this.messageFontLerp = 0.4; - this.messageLerp = 0.4; - this.messageFontAlpha = 0.8; - - this.lapMarginRatio = 14; - this.lap = ""; - this.lapSeparator = "/"; - - this.timeSeparators = ["","'", "''",""]; - - this.step = 0; - this.maxStep = 2; +bkcore.hexgl.HUD = function (opts) { + var self = this; + + this.visible = true; + this.messageOnly = false; + + this.width = opts.width; + this.height = opts.height; + + this.canvas = document.createElement("canvas"); + this.canvas.width = this.width; + this.canvas.height = this.height; + + this.ctx = this.canvas.getContext("2d"); + this.ctx.textAlign = "center"; + + this.bg = opts.bg; //"textures/hud/hud-bg.png"; + + this.fgspeed = opts.speed; //"textures/hud/hud-fg-speed.png"; + + this.fgshield = opts.shield; //"textures/hud/hud-fg-shield.png"; + + this.speedFontRatio = 24; + this.speedBarRatio = 2.91; + this.shieldFontRatio = 64; + this.shieldBarYRatio = 34; + this.shieldBarWRatio = 18.3; + this.shieldBarHRatio = 14.3; + this.timeMarginRatio = 18; + this.timeFontRatio = 19.2; + + this.font = opts.font || "Arial"; + + this.time = ""; + this.coinCount = 0; + this.coinFontRatio = 20; // Font size (smaller number = larger text) + this.coinMarginRatio = 30; // Distance from left edge + this.coinYRatio = 10; // Distance from top + + this.message = ""; + this.previousMessage = ""; + this.messageTiming = 0; + this.messagePos = 0.0; + this.messagePosTarget = 0.0; + this.messagePosTargetRatio = 12; + this.messageA = 1.0; + this.messageAS = 1.0; + this.messageDuration = 2 * 60; + this.messageDurationD = 2 * 60; + this.messageDurationS = 30; + this.messageYRatio = 34; + this.messageFontRatio = 10; + this.messageFontRatioStart = 6; + this.messageFontRatioEnd = 10; + this.messageFontLerp = 0.4; + this.messageLerp = 0.4; + this.messageFontAlpha = 0.8; + + this.lapMarginRatio = 14; + this.lap = ""; + this.lapSeparator = "/"; + + this.timeSeparators = ["", ":", ":", ""]; + + this.step = 0; + this.maxStep = 2; }; -bkcore.hexgl.HUD.prototype.resize = function(w, h) -{ - this.width = w; - this.height = h; - this.canvas.width = w; - this.canvas.height = h; -} - -bkcore.hexgl.HUD.prototype.display = function(msg, duration) -{ - this.messageTiming = 0; - - if(this.message != "") - { - this.messageA = this.messageFontAlpha; - this.messagePos = 0.0; - this.messagePosTarget = this.width/this.messagePosTargetRatio; - this.previousMessage = this.message; - } - - this.messageFontRatio = this.messageFontRatioStart; - this.messageAS = 0.0; - this.message = msg; - this.messageDuration = duration == undefined ? this.messageDurationD : duration*60; -} - -bkcore.hexgl.HUD.prototype.updateLap = function(current, total) -{ - this.lap = current + this.lapSeparator + total; -} - -bkcore.hexgl.HUD.prototype.resetLap = function() -{ - this.lap = ""; -} - -bkcore.hexgl.HUD.prototype.updateTime = function(time) -{ - this.time = this.timeSeparators[0] + time.m + this.timeSeparators[1] + time.s + this.timeSeparators[2] + time.ms + this.timeSeparators[3]; -} - -bkcore.hexgl.HUD.prototype.resetTime = function() -{ - this.time = ""; -} - -bkcore.hexgl.HUD.prototype.update = function(speed, speedRatio, shield, shieldRatio) -{ - var SCREEN_WIDTH = this.width; - var SCREEN_HEIGHT = this.height; - - var SCREEN_HW = SCREEN_WIDTH / 2; - var SCREEN_HH = SCREEN_HEIGHT / 2; - - if(!this.visible) - { - this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT); - return; - } - - var w = this.bg.width; - var h = this.bg.height; - var r = h/w; - var nw = SCREEN_WIDTH; - var nh = nw*r; - var oh = SCREEN_HEIGHT - nh; - var o = 0; - //speedbar - var ba = nh; - var bl = SCREEN_WIDTH/this.speedBarRatio; - var bw = bl * speedRatio; - //shieldbar - var sw = SCREEN_WIDTH/this.shieldBarWRatio; - var sho = SCREEN_WIDTH/this.shieldBarHRatio; - var sh = sho*shieldRatio; - var sy = (SCREEN_WIDTH/this.shieldBarYRatio)+sho-sh; - - - if(this.step == 0) - { - this.ctx.clearRect(0 , oh , SCREEN_WIDTH , nh); - - if(!this.messageOnly) - { - this.ctx.drawImage(this.bg, o, oh, nw, nh); - - this.ctx.save(); - this.ctx.beginPath(); - this.ctx.moveTo(bw+ba+SCREEN_HW, oh); - this.ctx.lineTo(-(bw+ba)+SCREEN_HW, oh); - this.ctx.lineTo(-bw+SCREEN_HW, SCREEN_HEIGHT); - this.ctx.lineTo(bw+SCREEN_HW, SCREEN_HEIGHT); - this.ctx.lineTo(bw+ba+SCREEN_HW, oh); - this.ctx.clip(); - this.ctx.drawImage(this.fgspeed, o, oh, nw, nh); - this.ctx.restore(); - - this.ctx.save(); - this.ctx.beginPath(); - this.ctx.moveTo(-sw+SCREEN_HW, oh+sy); - this.ctx.lineTo(sw+SCREEN_HW, oh+sy); - this.ctx.lineTo(sw+SCREEN_HW, oh+sh+sy); - this.ctx.lineTo(-sw+SCREEN_HW, oh+sh+sy); - this.ctx.lineTo(-sw+SCREEN_HW, oh+sh); - this.ctx.clip(); - this.ctx.drawImage(this.fgshield, o, oh, nw, nh); - this.ctx.restore(); - - // SPEED - this.ctx.font = (SCREEN_WIDTH/this.speedFontRatio)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; - this.ctx.fillText(speed, SCREEN_HW, SCREEN_HEIGHT - nh*0.57); - - // SHIELD - this.ctx.font = (SCREEN_WIDTH/this.shieldFontRatio)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)"; - this.ctx.fillText(shield, SCREEN_HW, SCREEN_HEIGHT - nh*0.44); - } - } - else if(this.step == 1) - { - this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , oh); - - // TIME - if(this.time != "") - { - this.ctx.font = (SCREEN_WIDTH/this.timeFontRatio)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; - this.ctx.fillText(this.time, SCREEN_HW, SCREEN_WIDTH/this.timeMarginRatio); - } - - // LAPS - if(this.lap != "") - { - this.ctx.font = (SCREEN_WIDTH/this.timeFontRatio)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; - this.ctx.fillText(this.lap, SCREEN_WIDTH-SCREEN_WIDTH/this.lapMarginRatio, SCREEN_WIDTH/this.timeMarginRatio); - } - - // MESSAGE - var my = SCREEN_HH-SCREEN_WIDTH/this.messageYRatio; - - if(this.messageTiming > this.messageDuration+2000) - { - this.previousMessage = ""; - this.message = ""; - this.messageA = 0.0; - } - else if(this.messageTiming > this.messageDuration && this.message != "") - { - this.previousMessage = this.message; - this.message = ""; - this.messagePos = 0.0; - this.messagePosTarget = SCREEN_WIDTH/this.messagePosTargetRatio; - this.messageA = this.messageFontAlpha; - } - - if(this.previousMessage != "") - { - if(this.messageA < 0.001) - this.messageA = 0.0; - else - this.messageA += (0.0 - this.messageA) * this.messageLerp; - - this.messagePos += (this.messagePosTarget - this.messagePos) * this.messageLerp; - - this.ctx.font = (SCREEN_WIDTH/this.messageFontRatioEnd)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, "+this.messageA+")"; - this.ctx.fillText(this.previousMessage, SCREEN_HW, my+this.messagePos); - } - - if(this.message != "") - { - if(this.messageTiming < this.messageDurationS) - { - this.messageAS += (this.messageFontAlpha - this.messageAS) * this.messageFontLerp; - this.messageFontRatio += (this.messageFontRatioEnd - this.messageFontRatio) * this.messageFontLerp; - } - else - { - this.messageAS = this.messageFontAlpha; - this.messageFontRatio = this.messageFontRatioEnd; - } - - this.ctx.font = (SCREEN_WIDTH/this.messageFontRatio)+"px "+this.font; - this.ctx.fillStyle = "rgba(255, 255, 255, "+this.messageAS+")"; - this.ctx.fillText(this.message, SCREEN_HW, my); - } - } - - this.messageTiming++; - - this.step++; - if(this.step == this.maxStep) this.step = 0; -} \ No newline at end of file +bkcore.hexgl.HUD.prototype.resize = function (w, h) { + this.width = w; + this.height = h; + this.canvas.width = w; + this.canvas.height = h; +}; + +bkcore.hexgl.HUD.prototype.display = function (msg, duration) { + this.messageTiming = 0; + + if (this.message != "") { + this.messageA = this.messageFontAlpha; + this.messagePos = 0.0; + this.messagePosTarget = this.width / this.messagePosTargetRatio; + this.previousMessage = this.message; + } + + this.messageFontRatio = this.messageFontRatioStart; + this.messageAS = 0.0; + this.message = msg; + this.messageDuration = + duration == undefined ? this.messageDurationD : duration * 60; +}; + +bkcore.hexgl.HUD.prototype.updateLap = function (current, total) { + this.lap = current + this.lapSeparator + total; +}; + +bkcore.hexgl.HUD.prototype.resetLap = function () { + this.lap = ""; +}; + +bkcore.hexgl.HUD.prototype.updateTime = function (time) { + this.time = + this.timeSeparators[0] + + time.m + + this.timeSeparators[1] + + time.s + + this.timeSeparators[2] + + time.ms + + this.timeSeparators[3]; +}; +bkcore.hexgl.HUD.prototype.updateCoins = function (coins) { + this.coinCount = coins; +}; +bkcore.hexgl.HUD.prototype.resetCoins = function () { + this.coinCount = 0; +}; +bkcore.hexgl.HUD.prototype.resetTime = function () { + this.time = ""; +}; + +bkcore.hexgl.HUD.prototype.update = function ( + speed, + speedRatio, + shield, + shieldRatio, +) { + var SCREEN_WIDTH = this.width; + var SCREEN_HEIGHT = this.height; + + var SCREEN_HW = SCREEN_WIDTH / 2; + var SCREEN_HH = SCREEN_HEIGHT / 2; + + if (!this.visible) { + this.ctx.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + return; + } + + var w = this.bg.width; + var h = this.bg.height; + var r = h / w; + var nw = SCREEN_WIDTH; + var nh = nw * r; + var oh = SCREEN_HEIGHT - nh; + var o = 0; + //speedbar + var ba = nh; + var bl = SCREEN_WIDTH / this.speedBarRatio; + var bw = bl * speedRatio; + //shieldbar + var sw = SCREEN_WIDTH / this.shieldBarWRatio; + var sho = SCREEN_WIDTH / this.shieldBarHRatio; + var sh = sho * shieldRatio; + var sy = SCREEN_WIDTH / this.shieldBarYRatio + sho - sh; + + if (this.step == 0) { + this.ctx.clearRect(0, oh, SCREEN_WIDTH, nh); + + if (!this.messageOnly) { + this.ctx.drawImage(this.bg, o, oh, nw, nh); + + this.ctx.save(); + this.ctx.beginPath(); + this.ctx.moveTo(bw + ba + SCREEN_HW, oh); + this.ctx.lineTo(-(bw + ba) + SCREEN_HW, oh); + this.ctx.lineTo(-bw + SCREEN_HW, SCREEN_HEIGHT); + this.ctx.lineTo(bw + SCREEN_HW, SCREEN_HEIGHT); + this.ctx.lineTo(bw + ba + SCREEN_HW, oh); + this.ctx.clip(); + this.ctx.drawImage(this.fgspeed, o, oh, nw, nh); + this.ctx.restore(); + + this.ctx.save(); + this.ctx.beginPath(); + this.ctx.moveTo(-sw + SCREEN_HW, oh + sy); + this.ctx.lineTo(sw + SCREEN_HW, oh + sy); + this.ctx.lineTo(sw + SCREEN_HW, oh + sh + sy); + this.ctx.lineTo(-sw + SCREEN_HW, oh + sh + sy); + this.ctx.lineTo(-sw + SCREEN_HW, oh + sh); + this.ctx.clip(); + this.ctx.drawImage(this.fgshield, o, oh, nw, nh); + this.ctx.restore(); + + // SPEED + this.ctx.font = SCREEN_WIDTH / this.speedFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + this.ctx.fillText(speed, SCREEN_HW, SCREEN_HEIGHT - nh * 0.57); + + // SHIELD + this.ctx.font = SCREEN_WIDTH / this.shieldFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)"; + this.ctx.fillText(shield, SCREEN_HW, SCREEN_HEIGHT - nh * 0.44); + } + } else if (this.step == 1) { + this.ctx.clearRect(0, 0, SCREEN_WIDTH, oh); + + // TIME + if (this.time != "") { + this.ctx.font = SCREEN_WIDTH / this.timeFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + this.ctx.fillText( + this.time, + SCREEN_HW, + SCREEN_WIDTH / this.timeMarginRatio, + ); + } + + // COINS + if (this.coinCount >= 0) { + this.ctx.save(); // Save current context state + this.ctx.textAlign = "left"; + this.ctx.font = SCREEN_WIDTH / this.coinFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + this.ctx.fillText( + "Coins: " + this.coinCount, + SCREEN_WIDTH / this.coinMarginRatio, // X position (from left) + SCREEN_HEIGHT / this.coinYRatio, // Y position (from top) + ); + this.ctx.restore(); // Restore previous context state (which includes textAlign: 'center') + } + + // LAPS + if (this.lap != "") { + this.ctx.font = SCREEN_WIDTH / this.timeFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + this.ctx.fillText( + this.lap, + SCREEN_WIDTH - SCREEN_WIDTH / this.lapMarginRatio, + SCREEN_WIDTH / this.timeMarginRatio, + ); + } + + // MESSAGE + var my = SCREEN_HH - SCREEN_WIDTH / this.messageYRatio; + + if (this.messageTiming > this.messageDuration + 2000) { + this.previousMessage = ""; + this.message = ""; + this.messageA = 0.0; + } else if ( + this.messageTiming > this.messageDuration && + this.message != "" + ) { + this.previousMessage = this.message; + this.message = ""; + this.messagePos = 0.0; + this.messagePosTarget = SCREEN_WIDTH / this.messagePosTargetRatio; + this.messageA = this.messageFontAlpha; + } + + if (this.previousMessage != "") { + if (this.messageA < 0.001) this.messageA = 0.0; + else this.messageA += (0.0 - this.messageA) * this.messageLerp; + + this.messagePos += + (this.messagePosTarget - this.messagePos) * this.messageLerp; + + this.ctx.font = + SCREEN_WIDTH / this.messageFontRatioEnd + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, " + this.messageA + ")"; + this.ctx.fillText(this.previousMessage, SCREEN_HW, my + this.messagePos); + } + + if (this.message != "") { + if (this.messageTiming < this.messageDurationS) { + this.messageAS += + (this.messageFontAlpha - this.messageAS) * this.messageFontLerp; + this.messageFontRatio += + (this.messageFontRatioEnd - this.messageFontRatio) * + this.messageFontLerp; + } else { + this.messageAS = this.messageFontAlpha; + this.messageFontRatio = this.messageFontRatioEnd; + } + + this.ctx.font = SCREEN_WIDTH / this.messageFontRatio + "px " + this.font; + this.ctx.fillStyle = "rgba(255, 255, 255, " + this.messageAS + ")"; + this.ctx.fillText(this.message, SCREEN_HW, my); + } + } + + this.messageTiming++; + + this.step++; + if (this.step == this.maxStep) this.step = 0; +}; diff --git a/bkcore/hexgl/HexGL.js b/bkcore/hexgl/HexGL.js index 4da8e46e..b14a0fcd 100644 --- a/bkcore/hexgl/HexGL.js +++ b/bkcore/hexgl/HexGL.js @@ -1,446 +1,478 @@ - /* +/* * HexGL * @author Thibaut 'BKcore' Despoulain * @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License. * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/. */ -'use strict'; -'v1.0.1'; +"use strict"; +"v1.0.1"; var bkcore = bkcore || {}; bkcore.hexgl = bkcore.hexgl || {}; -bkcore.hexgl.HexGL = function(opts) -{ - var self = this; +bkcore.hexgl.HexGL = function (opts) { + var self = this; - this.document = opts.document || document; + this.document = opts.document || document; - this.a = window.location.href; - - this.active = true; - this.displayHUD = opts.hud == undefined ? true : opts.hud; - this.width = opts.width == undefined ? window.innerWidth : opts.width; - this.height = opts.height == undefined ? window.innerHeight : opts.height; - - this.difficulty = opts.difficulty == undefined ? 0 : opts.difficulty; - this.player = opts.player == undefined ? "Anonym" : opts.player; - - this.track = bkcore.hexgl.tracks[ opts.track == undefined ? 'Cityscape' : opts.track ]; - - this.mode = opts.mode == undefined ? 'timeattack' : opts.mode; - - this.controlType = opts.controlType == undefined ? 1 : opts.controlType; - - // 0 == low, 1 == mid, 2 == high, 3 == very high - // the old platform+quality combinations map to these new quality values - // as follows: - // mobile + low quality => 0 (LOW) - // mobile + mid quality OR desktop + low quality => 1 (MID) - // mobile + high quality => 2 (HIGH) - // desktop + mid or high quality => 3 (VERY HIGH) - this.quality = opts.quality == undefined ? 3 : opts.quality; - - if(this.quality === 0) - { - this.width /= 2; - this.height /=2; - } + this.a = window.location.href; - this.settings = null; - this.renderer = null; - this.manager = null; - this.lib = null; - this.materials = {}; - this.components = {}; - this.extras = { - vignetteColor: new THREE.Color(0x458ab1), - bloom: null, - fxaa: null - }; - - this.containers = {}; - this.containers.main = opts.container == undefined ? document.body : opts.container; - this.containers.overlay = opts.overlay == undefined ? document.body : opts.overlay; - - this.gameover = opts.gameover == undefined ? null : opts.gameover; - - this.godmode = opts.godmode == undefined ? false : opts.godmode; - - this.hud = null; - - this.gameplay = null; - - this.composers = { - game: null - }; - - this.initRenderer(); - - function onKeyPress(event) - { - if(event.keyCode == 27/*escape*/) - { - self.reset(); - } - } - - this.document.addEventListener('keydown', onKeyPress, false); -} - -bkcore.hexgl.HexGL.prototype.start = function() -{ - - this.manager.setCurrent("game"); - - var self = this; - - function raf() - { - if(self && self.active) requestAnimationFrame( raf ); - self.update(); - } - - //if(this.a[15] == "o") - raf(); - - this.initGameplay(); -} - -bkcore.hexgl.HexGL.prototype.reset = function() -{ - this.manager.get('game').objects.lowFPS = 0; - this.gameplay.start(); - - bkcore.Audio.stop('bg'); - bkcore.Audio.stop('wind'); - bkcore.Audio.volume('wind', 0.35); - bkcore.Audio.play('bg'); - bkcore.Audio.play('wind'); -} - -bkcore.hexgl.HexGL.prototype.restart = function() -{ - try{ this.document.getElementById('finish').style.display = 'none'; } - catch(e){}; - this.reset(); -} - -bkcore.hexgl.HexGL.prototype.update = function() -{ - if(!this.active) return; - - if(this.gameplay != null) - this.gameplay.update(); - - this.manager.renderCurrent(); -} - -bkcore.hexgl.HexGL.prototype.init = function() -{ - this.initHUD(); - - this.track.buildMaterials(this.quality); - - this.track.buildScenes(this, this.quality); - - this.initGameComposer(); -} - -bkcore.hexgl.HexGL.prototype.load = function(opts) -{ - this.track.load(opts, this.quality); -} - -bkcore.hexgl.HexGL.prototype.initGameplay = function() -{ - var self = this; - - this.gameplay = new bkcore.hexgl.Gameplay({ - mode: this.mode, - hud: this.hud, - shipControls: this.components.shipControls, - cameraControls: this.components.cameraChase, - analyser: this.track.analyser, - pixelRatio: this.track.pixelRatio, - track: this.track, - onFinish: function() { - self.components.shipControls.terminate(); - self.displayScore(this.finishTime, this.lapTimes); - } - }); - - this.gameplay.start(); - - bkcore.Audio.play('bg'); - bkcore.Audio.play('wind'); - bkcore.Audio.volume('wind', 0.35); -} - -bkcore.hexgl.HexGL.prototype.displayScore = function(f, l) -{ - this.active = false; - - var tf = bkcore.Timer.msToTimeString(f); - var tl = [ - bkcore.Timer.msToTimeString(l[0]), - bkcore.Timer.msToTimeString(l[1]), - bkcore.Timer.msToTimeString(l[2]) - ]; - - if(this.gameover !== null) - { - this.gameover.style.display = "block"; - this.gameover.children[0].innerHTML = tf.m + "'" + tf.s + "''" + tf.ms; - this.containers.main.parentElement.style.display = "none"; - return; - } - - var t = this.track; - var dc = this.document.getElementById("finish"); - var ds = this.document.getElementById("finish-state"); - var dh = this.document.getElementById("finish-hallmsg"); - var dr = this.document.getElementById("finish-msg"); - var dt = this.document.getElementById("finish-result"); - var dl1 = this.document.getElementById("finish-lap1"); - var dl2 = this.document.getElementById("finish-lap2"); - var dl3 = this.document.getElementById("finish-lap3"); - var dd = this.document.getElementById("finish-diff") - var st = this.document.getElementById("finish-twitter"); - var sf = this.document.getElementById("finish-fb"); - var sl = this.document.getElementById("lowfps-msg"); - var d = this.difficulty == 0 ? 'casual' : 'hard'; - var ts = this.hud.timeSeparators; - - if(this.gameplay.result == this.gameplay.results.FINISH) - { - ds != undefined && (ds.innerHTML = "Finished!"); - // local record - if(typeof(Storage)!=="undefined") - { - if(localStorage['score-'+t+'-'+d] == undefined || localStorage['score-'+t+'-'+d] > f) - { - dr != undefined && (dr.innerHTML = "New local record!"); - localStorage['score-'+t+'-'+d] = f; - - // Export race data - localStorage['race-'+t+'-replay'] = JSON.Stringify(this.gameplay.raceData.export()); - } - else - { - dr != undefined && (dr.innerHTML = "Well done!"); - } - } - // ladder record - var p = bkcore.hexgl.Ladder.global[t][d][bkcore.hexgl.Ladder.global[t][d].length-2]; - if(p != undefined && p['score'] > f) - { - dh != undefined && (dh.innerHTML = "You made it to the HOF!"); - } - else - { - dh != undefined && (dh.innerHTML = "Hall Of Fame"); - } - - dt != undefined && (dt.innerHTML = tf.m + ts[1] + tf.s + ts[2] + tf.ms); - dl1 != undefined && (dl1.innerHTML = tl[0]["m"] != undefined ? tl[0].m + ts[1] + tl[0].s + ts[2] + tl[0].ms : "-"); - dl2 != undefined && (dl2.innerHTML = tl[1]["m"] != undefined ? tl[1].m + ts[1] + tl[1].s + ts[2] + tl[1].ms : "-"); - dl3 != undefined && (dl3.innerHTML = tl[2]["m"] != undefined ? tl[2].m + ts[1] + tl[2].s + ts[2] + tl[2].ms : "-"); - - // Ladder save - // Undisclosed - } - else - { - ds != undefined && (ds.innerHTML = "Destroyed!"); - dr != undefined && (dr.innerHTML = "Maybe next time!"); - dh != undefined && (dh.innerHTML = "Hall Of Fame"); - dt != undefined && (dt.innerHTML = "None"); - dl1 != undefined && (dl1.innerHTML = "None"); - dl2 != undefined && (dl2.innerHTML = "None"); - dl3 != undefined && (dl3.innerHTML = "None"); - } - - dd != undefined && (dd.innerHTML = d); - st != undefined && (st.href='http://twitter.com/share?text='+encodeURIComponent('I just scored '+dt.innerHTML+' in '+'Cityscape ('+d+') on #HexGL! Come try it and beat my record on ')); - sf != undefined && (sf.href='http://www.facebook.com/sharer.php?s=100' - +'&p[title]='+encodeURIComponent('I just scored '+dt.innerHTML+' in '+'Cityscape ('+d+') on HexGL!') - +'&p[summary]='+encodeURIComponent('HexGL is a futuristic racing game built by Thibaut Despoulain (BKcore) using HTML5, Javascript and WebGL. Come challenge your friends on this fast-paced 3D game!') - +'&p[url]='+encodeURIComponent('http://hexgl.bkcore.com') - +'&p[images][0]='+encodeURIComponent('http://hexgl.bkcore.com/image.png')); - - bkcore.hexgl.Ladder.displayLadder('finish-ladder', t, d, 8); - - if(this.manager.get('game').objects.lowFPS >= 999) - sl != undefined && (sl.innerHTML = 'Note: Your framerate was pretty low, you should try a lesser graphic setting!'); - else - sl != undefined && (sl.innerHTML = ''); - - dc.style.display = 'block'; -} - -bkcore.hexgl.HexGL.prototype.initRenderer = function() -{ - var renderer = new THREE.WebGLRenderer({ - antialias: false, - clearColor: 0x000000 - }); - - // desktop + quality mid or high - if(this.quality > 2) - { - renderer.physicallyBasedShading = true; - renderer.gammaInput = true; - renderer.gammaOutput = true; - renderer.shadowMapEnabled = true; - renderer.shadowMapSoft = true; - } - - renderer.autoClear = false; - renderer.sortObjects = false; - renderer.setSize( this.width, this.height ); - renderer.domElement.style.position = "relative"; - - this.containers.main.appendChild( renderer.domElement ); - this.canvas = renderer.domElement; - this.renderer = renderer; - this.manager = new bkcore.threejs.RenderManager(renderer); -} - -bkcore.hexgl.HexGL.prototype.initHUD = function() -{ - if(!this.displayHUD) return; - this.hud = new bkcore.hexgl.HUD({ - width: this.width, - height: this.height, - font: "BebasNeueRegular", - bg: this.track.lib.get("images", "hud.bg"), - speed: this.track.lib.get("images", "hud.speed"), - shield: this.track.lib.get("images", "hud.shield") - }); - this.containers.overlay.appendChild(this.hud.canvas); -} - -bkcore.hexgl.HexGL.prototype.initGameComposer = function() -{ - var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; - var renderTarget = new THREE.WebGLRenderTarget( this.width, this.height, renderTargetParameters ); - - // GAME COMPOSER - var renderSky = new THREE.RenderPass( this.manager.get("sky").scene, this.manager.get("sky").camera ); - - var renderModel = new THREE.RenderPass( this.manager.get("game").scene, this.manager.get("game").camera ); - renderModel.clear = false; - - this.composers.game = new THREE.EffectComposer( this.renderer, renderTarget ); - - var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] ); - effectScreen.renderToScreen = true; - var effectVignette = new THREE.ShaderPass( THREE.ShaderExtras[ "vignette" ] ); - - var effectHex = new THREE.ShaderPass( bkcore.threejs.Shaders[ "hexvignette" ] ); - effectHex.uniforms[ 'size' ].value = 512.0 * (this.width/1633); - effectHex.uniforms[ 'rx' ].value = this.width; - effectHex.uniforms[ 'ry' ].value = this.height; - effectHex.uniforms[ 'tHex' ].texture = this.track.lib.get("textures", "hex"); - effectHex.uniforms[ 'color' ].value = this.extras.vignetteColor; - - effectHex.renderToScreen = true; - - this.composers.game.addPass( renderSky ); - this.composers.game.addPass( renderModel ); - - // if(this.quality > 0 && !this.mobile) - // { - // var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] ); - // effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height ); - - // this.composers.game.addPass( effectFXAA ); - - // this.extras.fxaa = effectFXAA; - - // } - - // desktop + quality mid or high - if(this.quality > 2) - { - var effectBloom = new THREE.BloomPass( 0.8, 25, 4 , 256); - - this.composers.game.addPass( effectBloom ); - - this.extras.bloom = effectBloom; - } - - // desktop + quality low, mid or high - // OR - // mobile + quality mid or high - if(this.quality > 0) - this.composers.game.addPass( effectHex ); - else - this.composers.game.addPass( effectScreen ); -} - -bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, mat) -{ - geometry.computeTangents(); - - var mesh = new THREE.Mesh( geometry, mat ); - mesh.position.set( x, y, z ); - parent.add(mesh); - - // desktop + quality mid or high - if(this.quality > 2) - { - mesh.castShadow = true; - mesh.receiveShadow = true; - } - - return mesh; -} - -bkcore.hexgl.HexGL.prototype.tweakShipControls = function() -{ - var c = this.components.shipControls; - if(this.difficulty == 1) - { - c.airResist = 0.035; - c.airDrift = 0.07; - c.thrust = 0.035; - c.airBrake = 0.04; - c.maxSpeed = 9.6; - c.boosterSpeed = c.maxSpeed * 0.35; - c.boosterDecay = 0.007; - c.angularSpeed = 0.0140; - c.airAngularSpeed = 0.0165; - c.rollAngle = 0.6; - c.shieldDamage = 0.03; - c.collisionSpeedDecrease = 0.8; - c.collisionSpeedDecreaseCoef = 0.5; - c.rollLerp = 0.1; - c.driftLerp = 0.4; - c.angularLerp = 0.4; - } - else if(this.difficulty == 0) - { - c.airResist = 0.02; - c.airDrift = 0.06; - c.thrust = 0.02; - c.airBrake = 0.025; - c.maxSpeed = 7.0; - c.boosterSpeed = c.maxSpeed * 0.5; - c.boosterDecay = 0.007; - c.angularSpeed = 0.0125; - c.airAngularSpeed = 0.0135; - c.rollAngle = 0.6; - c.shieldDamage = 0.06; - c.collisionSpeedDecrease = 0.8; - c.collisionSpeedDecreaseCoef = 0.5; - c.rollLerp = 0.07; - c.driftLerp = 0.3; - c.angularLerp = 0.4; - } - - if(this.godmode) - c.shieldDamage = 0.0; -} + this.active = true; + this.displayHUD = opts.hud == undefined ? true : opts.hud; + this.width = opts.width == undefined ? window.innerWidth : opts.width; + this.height = opts.height == undefined ? window.innerHeight : opts.height; + + this.difficulty = opts.difficulty == undefined ? 0 : opts.difficulty; + this.player = opts.player == undefined ? "Anonym" : opts.player; + + this.track = + bkcore.hexgl.tracks[opts.track == undefined ? "Cityscape" : opts.track]; + + this.mode = opts.mode == undefined ? "timeattack" : opts.mode; + + this.controlType = opts.controlType == undefined ? 1 : opts.controlType; + + // 0 == low, 1 == mid, 2 == high, 3 == very high + // the old platform+quality combinations map to these new quality values + // as follows: + // mobile + low quality => 0 (LOW) + // mobile + mid quality OR desktop + low quality => 1 (MID) + // mobile + high quality => 2 (HIGH) + // desktop + mid or high quality => 3 (VERY HIGH) + this.quality = opts.quality == undefined ? 3 : opts.quality; + + if (this.quality === 0) { + this.width /= 2; + this.height /= 2; + } + + this.settings = null; + this.renderer = null; + this.manager = null; + this.lib = null; + this.materials = {}; + this.components = {}; + this.extras = { + vignetteColor: new THREE.Color(0x458ab1), + bloom: null, + fxaa: null, + }; + + this.containers = {}; + this.containers.main = + opts.container == undefined ? document.body : opts.container; + this.containers.overlay = + opts.overlay == undefined ? document.body : opts.overlay; + + this.gameover = opts.gameover == undefined ? null : opts.gameover; + + this.godmode = opts.godmode == undefined ? false : opts.godmode; + + this.hud = null; + + this.gameplay = null; + + this.composers = { + game: null, + }; + + this.initRenderer(); + + function onKeyPress(event) { + if (event.keyCode == 27 /*escape*/) { + self.reset(); + } + } + + this.document.addEventListener("keydown", onKeyPress, false); +}; + +bkcore.hexgl.HexGL.prototype.start = function () { + this.manager.setCurrent("game"); + + var self = this; + + function raf() { + if (self && self.active) requestAnimationFrame(raf); + self.update(); + } + + //if(this.a[15] == "o") + raf(); + + this.initGameplay(); +}; + +bkcore.hexgl.HexGL.prototype.reset = function () { + this.manager.get("game").objects.lowFPS = 0; + this.gameplay.start(); + + bkcore.Audio.stop("bg"); + bkcore.Audio.stop("wind"); + bkcore.Audio.volume("wind", 0.35); + bkcore.Audio.play("bg"); + bkcore.Audio.play("wind"); +}; + +bkcore.hexgl.HexGL.prototype.restart = function () { + try { + this.document.getElementById("finish").style.display = "none"; + } catch (e) {} + this.reset(); +}; + +bkcore.hexgl.HexGL.prototype.update = function () { + if (!this.active) return; + + if (this.gameplay != null) this.gameplay.update(); + + this.manager.renderCurrent(); +}; + +bkcore.hexgl.HexGL.prototype.init = function () { + this.initHUD(); + + this.track.buildMaterials(this.quality); + + this.track.buildScenes(this, this.quality); + + this.initGameComposer(); +}; + +bkcore.hexgl.HexGL.prototype.load = function (opts) { + this.track.load(opts, this.quality); +}; + +bkcore.hexgl.HexGL.prototype.initGameplay = function () { + var self = this; + + this.gameplay = new bkcore.hexgl.Gameplay({ + mode: this.mode, + hud: this.hud, + shipControls: this.components.shipControls, + cameraControls: this.components.cameraChase, + analyser: this.track.analyser, + pixelRatio: this.track.pixelRatio, + track: this.track, + onFinish: function () { + self.components.shipControls.terminate(); + self.displayScore(this.finishTime, this.lapTimes); + }, + }); + + this.gameplay.start(); + + bkcore.Audio.play("bg"); + bkcore.Audio.play("wind"); + bkcore.Audio.volume("wind", 0.35); +}; + +bkcore.hexgl.HexGL.prototype.displayScore = function (f, l) { + this.active = false; + + var tf = bkcore.Timer.msToTimeString(f); + var tl = [ + bkcore.Timer.msToTimeString(l[0]), + bkcore.Timer.msToTimeString(l[1]), + bkcore.Timer.msToTimeString(l[2]), + ]; + + if (this.gameover !== null) { + this.gameover.style.display = "block"; + this.gameover.children[0].innerHTML = tf.m + ":" + tf.s + ":" + tf.ms; + this.containers.main.parentElement.style.display = "none"; + return; + } + + var t = this.track; + var dc = this.document.getElementById("finish"); + var ds = this.document.getElementById("finish-state"); + var dh = this.document.getElementById("finish-hallmsg"); + var dr = this.document.getElementById("finish-msg"); + var dt = this.document.getElementById("finish-result"); + var dl1 = this.document.getElementById("finish-lap1"); + var dl2 = this.document.getElementById("finish-lap2"); + var dl3 = this.document.getElementById("finish-lap3"); + var dd = this.document.getElementById("finish-diff"); + var st = this.document.getElementById("finish-twitter"); + var sf = this.document.getElementById("finish-fb"); + var sl = this.document.getElementById("lowfps-msg"); + var d = this.difficulty == 0 ? "casual" : "hard"; + var ts = this.hud.timeSeparators; + + if (this.gameplay.result == this.gameplay.results.FINISH) { + ds != undefined && (ds.innerHTML = "Finished!"); + // local record + if (typeof Storage !== "undefined") { + if ( + localStorage["score-" + t + "-" + d] == undefined || + localStorage["score-" + t + "-" + d] > f + ) { + dr != undefined && (dr.innerHTML = "New local record!"); + localStorage["score-" + t + "-" + d] = f; + + // Export race data + localStorage["race-" + t + "-replay"] = JSON.Stringify( + this.gameplay.raceData.export(), + ); + } else { + dr != undefined && (dr.innerHTML = "Well done!"); + } + } + // ladder record + var p = + bkcore.hexgl.Ladder.global[t][d][ + bkcore.hexgl.Ladder.global[t][d].length - 2 + ]; + if (p != undefined && p["score"] > f) { + dh != undefined && (dh.innerHTML = "You made it to the HOF!"); + } else { + dh != undefined && (dh.innerHTML = "Hall Of Fame"); + } + + dt != undefined && (dt.innerHTML = tf.m + ts[1] + tf.s + ts[2] + tf.ms); + dl1 != undefined && + (dl1.innerHTML = + tl[0]["m"] != undefined + ? tl[0].m + ts[1] + tl[0].s + ts[2] + tl[0].ms + : "-"); + dl2 != undefined && + (dl2.innerHTML = + tl[1]["m"] != undefined + ? tl[1].m + ts[1] + tl[1].s + ts[2] + tl[1].ms + : "-"); + dl3 != undefined && + (dl3.innerHTML = + tl[2]["m"] != undefined + ? tl[2].m + ts[1] + tl[2].s + ts[2] + tl[2].ms + : "-"); + + // Ladder save + // Undisclosed + } else { + ds != undefined && (ds.innerHTML = "Destroyed!"); + dr != undefined && (dr.innerHTML = "Maybe next time!"); + dh != undefined && (dh.innerHTML = "Hall Of Fame"); + dt != undefined && (dt.innerHTML = "None"); + dl1 != undefined && (dl1.innerHTML = "None"); + dl2 != undefined && (dl2.innerHTML = "None"); + dl3 != undefined && (dl3.innerHTML = "None"); + } + + dd != undefined && (dd.innerHTML = d); + st != undefined && + (st.href = + "http://twitter.com/share?text=" + + encodeURIComponent( + "I just scored " + + dt.innerHTML + + " in " + + "Cityscape (" + + d + + ") on #HexGL! Come try it and beat my record on ", + )); + sf != undefined && + (sf.href = + "http://www.facebook.com/sharer.php?s=100" + + "&p[title]=" + + encodeURIComponent( + "I just scored " + + dt.innerHTML + + " in " + + "Cityscape (" + + d + + ") on HexGL!", + ) + + "&p[summary]=" + + encodeURIComponent( + "HexGL is a futuristic racing game built by Thibaut Despoulain (BKcore) using HTML5, Javascript and WebGL. Come challenge your friends on this fast-paced 3D game!", + ) + + "&p[url]=" + + encodeURIComponent("http://hexgl.bkcore.com") + + "&p[images][0]=" + + encodeURIComponent("http://hexgl.bkcore.com/image.png")); + + bkcore.hexgl.Ladder.displayLadder("finish-ladder", t, d, 8); + + if (this.manager.get("game").objects.lowFPS >= 999) + sl != undefined && + (sl.innerHTML = + "Note: Your framerate was pretty low, you should try a lesser graphic setting!"); + else sl != undefined && (sl.innerHTML = ""); + + dc.style.display = "block"; +}; + +bkcore.hexgl.HexGL.prototype.initRenderer = function () { + var renderer = new THREE.WebGLRenderer({ + antialias: false, + clearColor: 0x000000, + }); + + // desktop + quality mid or high + if (this.quality > 2) { + renderer.physicallyBasedShading = true; + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.shadowMapEnabled = true; + renderer.shadowMapSoft = true; + } + + renderer.autoClear = false; + renderer.sortObjects = false; + renderer.setSize(this.width, this.height); + renderer.domElement.style.position = "relative"; + + this.containers.main.appendChild(renderer.domElement); + this.canvas = renderer.domElement; + this.renderer = renderer; + this.manager = new bkcore.threejs.RenderManager(renderer); +}; + +bkcore.hexgl.HexGL.prototype.initHUD = function () { + if (!this.displayHUD) return; + this.hud = new bkcore.hexgl.HUD({ + width: this.width, + height: this.height, + font: "BebasNeueRegular", + bg: this.track.lib.get("images", "hud.bg"), + speed: this.track.lib.get("images", "hud.speed"), + shield: this.track.lib.get("images", "hud.shield"), + }); + this.containers.overlay.appendChild(this.hud.canvas); +}; + +bkcore.hexgl.HexGL.prototype.initGameComposer = function () { + var renderTargetParameters = { + minFilter: THREE.LinearFilter, + magFilter: THREE.LinearFilter, + format: THREE.RGBFormat, + stencilBuffer: false, + }; + var renderTarget = new THREE.WebGLRenderTarget( + this.width, + this.height, + renderTargetParameters, + ); + + // GAME COMPOSER + var renderSky = new THREE.RenderPass( + this.manager.get("sky").scene, + this.manager.get("sky").camera, + ); + + var renderModel = new THREE.RenderPass( + this.manager.get("game").scene, + this.manager.get("game").camera, + ); + renderModel.clear = false; + + this.composers.game = new THREE.EffectComposer(this.renderer, renderTarget); + + var effectScreen = new THREE.ShaderPass(THREE.ShaderExtras["screen"]); + effectScreen.renderToScreen = true; + var effectVignette = new THREE.ShaderPass(THREE.ShaderExtras["vignette"]); + + var effectHex = new THREE.ShaderPass(bkcore.threejs.Shaders["hexvignette"]); + effectHex.uniforms["size"].value = 512.0 * (this.width / 1633); + effectHex.uniforms["rx"].value = this.width; + effectHex.uniforms["ry"].value = this.height; + effectHex.uniforms["tHex"].texture = this.track.lib.get("textures", "hex"); + effectHex.uniforms["color"].value = this.extras.vignetteColor; + + effectHex.renderToScreen = true; + + this.composers.game.addPass(renderSky); + this.composers.game.addPass(renderModel); + + // if(this.quality > 0 && !this.mobile) + // { + // var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] ); + // effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height ); + + // this.composers.game.addPass( effectFXAA ); + + // this.extras.fxaa = effectFXAA; + + // } + + // desktop + quality mid or high + if (this.quality > 2) { + var effectBloom = new THREE.BloomPass(0.8, 25, 4, 256); + + this.composers.game.addPass(effectBloom); + + this.extras.bloom = effectBloom; + } + + // desktop + quality low, mid or high + // OR + // mobile + quality mid or high + if (this.quality > 0) this.composers.game.addPass(effectHex); + else this.composers.game.addPass(effectScreen); +}; + +bkcore.hexgl.HexGL.prototype.createMesh = function ( + parent, + geometry, + x, + y, + z, + mat, +) { + geometry.computeTangents(); + + var mesh = new THREE.Mesh(geometry, mat); + mesh.position.set(x, y, z); + parent.add(mesh); + + // desktop + quality mid or high + if (this.quality > 2) { + mesh.castShadow = true; + mesh.receiveShadow = true; + } + + return mesh; +}; + +bkcore.hexgl.HexGL.prototype.tweakShipControls = function () { + var c = this.components.shipControls; + if (this.difficulty == 1) { + c.airResist = 0.035; + c.airDrift = 0.07; + c.thrust = 0.035; + c.airBrake = 0.04; + c.maxSpeed = 9.6; + c.boosterSpeed = c.maxSpeed * 0.35; + c.boosterDecay = 0.007; + c.angularSpeed = 0.014; + c.airAngularSpeed = 0.0165; + c.rollAngle = 0.6; + c.shieldDamage = 0.03; + c.collisionSpeedDecrease = 0.8; + c.collisionSpeedDecreaseCoef = 0.5; + c.rollLerp = 0.1; + c.driftLerp = 0.4; + c.angularLerp = 0.4; + } else if (this.difficulty == 0) { + c.airResist = 0.02; + c.airDrift = 0.06; + c.thrust = 0.02; + c.airBrake = 0.025; + c.maxSpeed = 7.0; + c.boosterSpeed = c.maxSpeed * 0.5; + c.boosterDecay = 0.007; + c.angularSpeed = 0.0125; + c.airAngularSpeed = 0.0135; + c.rollAngle = 0.6; + c.shieldDamage = 0.06; + c.collisionSpeedDecrease = 0.8; + c.collisionSpeedDecreaseCoef = 0.5; + c.rollLerp = 0.07; + c.driftLerp = 0.3; + c.angularLerp = 0.4; + } + + if (this.godmode) c.shieldDamage = 0.0; +};