class Ball { constructor(collision) { this.collision = collision; this.w = 4; this.h = this.w; this.y = height / 2 - this.h / 2; this.x = width / 2 - this.w / 2; this.oldX = this.x; this.oldY = this.y; this.velX = 6; this.velY = 3.5 + Math.random(); } reset() { this.y = height / 2 - this.h / 2; this.x = width / 2 - this.w / 2; this.velX = 6; this.velY = 3.5 + Math.random(); } checkCollision(that, isLeft) { let test = false; if (isLeft) { test = this.x <= that.w + this.w && this.y > that.y && this.y < that.y + that.h; } else { test = this.x >= that.x + this.w && this.y > that.y && this.y < that.y + that.h; } if (test) { this.velX = -this.velX; this.velY = (3.5 + 2 * Math.random()) * this.velY / Math.abs(this.velY); if (isLeft) { right.follow = this; left.follow = null; } else { left.follow = this; right.follow = null; } } } move() { if (this.velX > 0) { this.checkCollision(right, false); } else { this.checkCollision(left, true); } this.x += this.velX; this.y += this.velY; if (this.y <= this.h) { this.y = this.h; this.velY = -this.velY; } if (this.y >= height - this.h) { this.y = height - this.h; this.velY = -this.velY; } if (this.x >= width) { left.scored(); restart(); } else if (this.x < 0) { right.scored(); restart(); } } } class Paddle { constructor(side) { this.side = side; this.w = 4; //15; this.h = 30; //80; this.y = height / 2 - this.h / 2; this.follow = null; this.target = height / 2 - this.h / 2; this.score = 99; this.hasLost = false; } reset() { this.follow = null; this.hasLost = false; this.target = height / 2 - this.h / 2; this.y = height / 2 - this.h / 2; this.move(); } scored() { let d = new Date(); let value = 0; if (this.side == "left") { value = d.getHours(); } else { value = d.getMinutes(); } if (this.score < value) { this.score++; } else { this.score = value; } } move() { if (this.follow && !this.hasLost) { var dy = this.follow.y - this.y - this.h / 2; this.y += dy / 2; } else { this.y += (this.target - this.y) / 10; } if (this.y < 0) { this.y = 0; } if (this.y > height - this.h) { this.y = height - this.h; } } } var updateTimeout = null; function update() { var d = new Date(); var lastStep = Date.now(); left.move(); right.move(); if (d.getHours() != left.score) { right.follow = null; right.hasLost = true; } if (d.getMinutes() != right.score) { left.follow = null; left.hasLost = true; } ball.move(); redraw(); var nextStep = 40 - (Date.now() - lastStep); //console.log(nextStep); updateTimeout = setTimeout(update, nextStep > 0 ? nextStep : 0); return lastStep; } function redraw() { let fontHeight = width / 3.6; let fontTop = top + height / 11; let topHeight = top + height; g.reset(); if (settings.isInvers) { g.setColor(g.theme.bg); g.setBgColor(g.theme.fg); } g.clearRect(0, top + left.oldY, left.w, top + left.oldY + left.h); g.clearRect(width - right.w, top + right.oldY, width, top + right.oldY + right.h); //g.clearRect(width / 2 - fontHeight * 1.4, fontTop, width / 2 + fontHeight * 1.4, fontTop + fontHeight); g.clearRect(ball.oldX - ball.w, top + ball.oldY - ball.h, ball.oldX + ball.w, top + ball.oldY + ball.h); g.setFontVector(fontHeight); /**/ g.setFontAlign(1, -1); g.drawString(("0" + left.score).substr(-2), 5 * width / 11, fontTop, true); g.setFontAlign(-1, -1); g.drawString(("0" + right.score).substr(-2), 6 * width / 11, fontTop, true); /**/ g.drawLine(width / 2, top, width / 2, topHeight); g.fillRect(0, top + left.y, left.w, top + left.y + left.h); left.oldY = left.y; g.fillRect(width - right.w, top + right.y, width, top + right.y + right.h); right.oldY = right.y; g.fillCircle(ball.x, top + ball.y, ball.w); ball.oldX = ball.x; ball.oldY = ball.y; } function restart() { g.reset(); if (settings.isInvers) { g.setColor(g.theme.bg); g.setBgColor(g.theme.fg); } g.clearRect(0, top, width, top + height); ball.reset(); left.reset(); right.reset(); right.follow = ball; left.move(); right.move(); if (settings.withWidgets) { Bangle.drawWidgets(); } } function stop() { if (updateTimeout) { clearTimeout(updateTimeout); } updateTimeout = null; if (pauseTimeout) { clearTimeout(pauseTimeout); } pauseTimeout = null; } var pauseTimeout = null; function pause() { stop(); left.scored(); right.scored(); redraw(); pauseTimeout = setTimeout(pause, Date.now() % 60000); } //load settings const SETTINGS_FILE = "pongclock.json"; var settings = Object.assign({ // default values withWidgets: true, isInvers: false, playLocked: true, }, require('Storage').readJSON(SETTINGS_FILE, true) || {}); require('Storage').writeJSON(SETTINGS_FILE, settings); //make clock Bangle.setUI("clock"); //setup play area var height = g.getHeight(), width = g.getWidth(); var top = 0; g.reset(); g.clearRect(0, top, width, height); if (settings.withWidgets) { Bangle.loadWidgets(); Bangle.drawWidgets(); //console.log(WIDGETS); if (global.WIDGETS) { let bottom = 0; for (var i in WIDGETS) { var w = WIDGETS[i]; if (w.area) { if (w.area.indexOf("t") >= 0) { top = Bangle.appRect.y; } if (w.area.indexOf("b") >= 0) { bottom = height - Bangle.appRect.y2; } } } height -= top + bottom; } } if (settings.isInvers) { g.setColor(g.theme.bg); g.setBgColor(g.theme.fg); } g.clearRect(0, top, width, top + height); //setup game var left = new Paddle("left"); var right = new Paddle("right"); var ball = new Ball(true); left.x = 20; right.x = width - 20; left.scored(); right.scored(); Bangle.on("lock", (on) => { //console.log(on); if (!settings.playLocked) { if (on) { pause(); } else { stop(); update(); } } }); //start clock restart(); if (!settings.playLocked && Bangle.isLocked()) { pause(); } else { update(); } /* //local testing require("Storage").write("pongclock.info",{ "id":"pongclock", "name":"Pong Clock", "type":"clock", "src":"pongclock.app.js", "icon":"pongclock.img" }); */