mirror of https://github.com/espruino/BangleApps
commit
473e916878
|
@ -0,0 +1 @@
|
|||
0.01: First release
|
|
@ -0,0 +1,15 @@
|
|||
# Pong Clock
|
||||
|
||||
A clock which is playing Pong while showing the current time as score
|
||||
* Settings
|
||||
* Show or hide widgets (auto detecting the used widgets areas)
|
||||
* Use inverted or standard theme colors for the play area
|
||||
* Optionally pause while locked (saving battery)
|
||||
* Loosely based on [https://codepen.io/Rabrennie/pen/WxNEoe](https://codepen.io/Rabrennie/pen/WxNEoe)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Creator
|
||||
[@pidajo](https://github.com/pidajo)
|
|
@ -0,0 +1,310 @@
|
|||
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"
|
||||
});
|
||||
*/
|
|
@ -0,0 +1,20 @@
|
|||
{ "id": "pongclock",
|
||||
"name": "Pong Clock",
|
||||
"shortName":"Pong Clock",
|
||||
"icon": "pongclock.png",
|
||||
"version":"0.01",
|
||||
"description": "A Pong playing clock",
|
||||
"tags": "",
|
||||
"allow_emulator":true,
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme":"README.md",
|
||||
"screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot_settings.png" }, { "url":"screenshot_invers_full.png" } ],
|
||||
"storage": [
|
||||
{"name":"pongclock.app.js","url":"app.js"},
|
||||
{"name":"pongclock.img","url":"pongclock-icon.js","evaluate":true},
|
||||
{"name":"pongclock.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"pongclock.json"}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
atob("MDCEBAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAIiAAAAAAAAAAEAAAAAAAABP/EAE//yAAAAAAAD8wAAAT//IAAAAAAv//EA////IAAAAAAP8gAAH///8gAAAAAvP/EB/xA/MAIiAAAf8QAAL/ED8wAAAAAxD/EC8wAf8ALyAAAv8AAAPyAC/wAAAAAAD/ED/wAf8ALyAAD/MAAA/zAC8wAAAAAAD/EAAAAv8ALyAAH/EAAAAAAD8wAAAAAAD/EAAAA/IALyAAL/AAAAAAAP8gAAAAAAD/EAAAH/EALyAAPzD/IAAAAv8AAAAAAAD/EAAAPzAALyAA/yD/IAAAD/IAAAAAAAD/EAAB/xAALyAB/xD/IAAAL/AAAAAAAAD/EAAP8wAALyAC/wD/IAAB/yAAAAAAAAD/EAAv8QAAIiAP8wD/IAAD/wAAAAAAAAD/EAD/MAAAAAAf/zP/MwAf8gAAAA//AAD/EAL/AAAAAAAf////8wA/8AAAAA//AAD/EB/zAAAAIiACIiL/MgL/IAAAAA//AAD/EC////8ALyAAAAD/IAP////wAA//AAD/EC////8ALyAAAAD/IAP////wAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAAIiAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAD/8A//AAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAIiAAAAAAAAAAAAD/8AAAAAAAASEAAAAALyAAAAAAAAAAAAD/8AAAAAAAP/8wAAAALyAAAAAAAAAAAAD/8AAAAAAB///xAAAALyAAAAAAAAAAAAD/8AAAAAAC///yAAAALyAAAAAAAAAAAAD/8AAAAAAB///xAAAALyAAAAAAAAAAAAD/8AAAAAAAP/8wAAAALyAAAAAAAAAAAAD/8AAAAAAAASEAAAAALyAAAAAAAAAAAAD/8AAAAAAAAAAAAAAALyAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAIiAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAA==")
|
Binary file not shown.
After Width: | Height: | Size: 934 B |
Binary file not shown.
After Width: | Height: | Size: 755 B |
Binary file not shown.
After Width: | Height: | Size: 480 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,44 @@
|
|||
(function(back) {
|
||||
var FILE = "pongclock.json";
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
withWidgets: true,
|
||||
isInvers: false,
|
||||
playLocked: true,
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "Pong Clock" },
|
||||
"< Back" : () => back(),
|
||||
'Widgets?': {
|
||||
value: !!settings.withWidgets, // !! converts undefined to false
|
||||
format: v => v?"Show":"Hide",
|
||||
onchange: v => {
|
||||
settings.withWidgets = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Inverted?': {
|
||||
value: !!settings.isInvers, // !! converts undefined to false
|
||||
format: v => v?"Yes":"No",
|
||||
onchange: v => {
|
||||
settings.isInvers = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'On Lock?': {
|
||||
value: !!settings.playLocked, // !! converts undefined to false
|
||||
format: v => v?"Play":"Pause",
|
||||
onchange: v => {
|
||||
settings.playLocked = v;
|
||||
writeSettings();
|
||||
}
|
||||
}
|
||||
});
|
||||
})/*(load)/**/
|
|
@ -0,0 +1 @@
|
|||
0.01: First release
|
|
@ -0,0 +1,9 @@
|
|||
# Day Widget
|
||||
|
||||
Just shows the day of the current date, to save space in the widget area. The month and year should be known because they don't change that often. Just the number in maximum size for readability.
|
||||
|
||||

|
||||
|
||||
## Creator
|
||||
[@pidajo](https://github.com/pidajo)
|
||||
|
|
@ -0,0 +1 @@
|
|||
atob("MDCEAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIBEREREREREREREREREREREREREREQIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////zMz////8zMzMzMzP////xIiIf///////czM////PMzMzMzMzP///xIiIf/////zzMzM////PMzMzMzMzP///xIiIf////PczMzM////PMzMzMzMzP///xIiIf////3MzMzM////8zMzMz3MzP///xIiIf////3MM8zM//////////zMw////xIiIf////0/88zM/////////zzMz////xIiIf//////88zM/////////8zM3////xIiIf//////88zM////////88zM/////xIiIf//////88zM/////////MzN/////xIiIf//////88zM////////PMzD/////xIiIf//////88zM////////3Mzf/////xIiIf//////88zM////////zMw//////xIiIf//////88zM///////9zMz//////xIiIf//////88zM///////8zMP//////xIiIf//////88zM//////88zM///////xIiIf//////88zM///////MzN///////xIiIf////8zM8zM//////PMzD///////xIiIf////3MzMzMzM3///3Mzf///////xIiIf////3MzMzMzM3//zzMw////////xIiIf////PMzMzMzM3//9zMz////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIBEREREREREREREREREREREREREREQIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIg==")
|
|
@ -0,0 +1,15 @@
|
|||
{ "id": "widday",
|
||||
"name": "Day Widget",
|
||||
"shortName":"My Timer",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"version":"0.01",
|
||||
"description": "Just the day of the current date as widget",
|
||||
"readme": "README.md",
|
||||
"tags": "widget,say,date",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"screenshots" : [ { "url":"screenshot.png" } ],
|
||||
"storage": [
|
||||
{"name":"widday.wid.js","url":"widget.js"}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 938 B |
|
@ -0,0 +1,27 @@
|
|||
(() => {
|
||||
var width = 32; // width of the widget
|
||||
|
||||
function draw() {
|
||||
var date = new Date();
|
||||
g.reset(); // reset the graphics context to defaults (color/font/etc)
|
||||
g.setFontAlign(0,1); // center fonts
|
||||
//g.drawRect(this.x, this.y, this.x+width-1, this.y+23); // check the bounds!
|
||||
|
||||
var text = date.getDate();
|
||||
g.setFont("Vector", 24);
|
||||
g.drawString(text, this.x+width/2+1, this.y + 28);
|
||||
//g.setColor(0, 0, 1);
|
||||
//g.drawRect(this.x, this.y, this.x+width-2, this.y+1);
|
||||
}
|
||||
|
||||
setInterval(function() {
|
||||
WIDGETS["widday"].draw(WIDGETS["widdateday"]);
|
||||
}, 10*60000); // update every 10 minutes
|
||||
|
||||
// add your widget
|
||||
WIDGETS["widday"]={
|
||||
area:"bl", // tl (top left), tr (top right), bl (bottom left), br (bottom right)
|
||||
width: width, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
|
||||
draw:draw // called to draw the widget
|
||||
};
|
||||
})()
|
Binary file not shown.
After Width: | Height: | Size: 778 B |
Loading…
Reference in New Issue