Merge pull request #236 from paulcockrell/master
Mario Clock [Enhancement] - Multi characters and Night Modemaster
commit
7cf9f117d4
|
|
@ -911,8 +911,8 @@
|
|||
{ "id": "marioclock",
|
||||
"name": "Mario Clock",
|
||||
"icon": "marioclock.png",
|
||||
"version":"0.06",
|
||||
"description": "Animated Mario clock, jumps to change the time!",
|
||||
"version":"0.07",
|
||||
"description": "Animated Mario clock, jumps to change the time! Swipe right to change the character, and swipe left to toggle night mode. Press BTN1 to jump.",
|
||||
"tags": "clock,mario,retro",
|
||||
"type": "clock",
|
||||
"allow_emulator":true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
0.01: Create mario app
|
||||
0.01: Create mario app [Paul Cockrell https://github.com/paulcockrell]
|
||||
0.02: Fix day of the week and add padding
|
||||
0.03: use short date format from locale, take timeout from settings
|
||||
0.04: modify date to display to be more at the original idea but still localized
|
||||
0.05: use 12/24 hour clock from settings
|
||||
0.06: Performance refactor, and enhanced graphics!
|
||||
0.07: Swipe right to change between Mario and Toad characters, swipe left to toggle night mode
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
/**********************************
|
||||
BangleJS MARIO CLOCK
|
||||
+ Based on Espruino Mario Clock V3 https://github.com/paulcockrell/espruino-mario-clock
|
||||
+ Converting images to 1bit BMP: Image > Mode > Indexed and tick the "Use black and white (1-bit) palette", Then export as BMP.
|
||||
+ Online Image convertor: https://www.espruino.com/Image+Converter
|
||||
+ Images must be converted 1Bit White/Black !!! Not Black/White
|
||||
**********************************/
|
||||
/**
|
||||
* BangleJS MARIO CLOCK
|
||||
*
|
||||
* + Original Author: Paul Cockrell https://github.com/paulcockrell
|
||||
* + Created: April 2020
|
||||
* + Based on Espruino Mario Clock V3 https://github.com/paulcockrell/espruino-mario-clock
|
||||
* + Online Image convertor: https://www.espruino.com/Image+Converter, Use transparency + compression + 8bit Web + export as Image String
|
||||
* + Images must be drawn as PNGs with transparent backgrounds
|
||||
*/
|
||||
|
||||
const locale = require("locale");
|
||||
const storage = require('Storage');
|
||||
|
|
@ -22,14 +24,20 @@ const LIGHTEST = "#effedd";
|
|||
const LIGHT = "#add795";
|
||||
const DARK = "#588d77";
|
||||
const DARKEST = "#122d3e";
|
||||
const NIGHT = "#001818";
|
||||
|
||||
const marioSprite = {
|
||||
// Character names
|
||||
const TOAD = "toad";
|
||||
const MARIO = "mario";
|
||||
|
||||
const characterSprite = {
|
||||
frameIdx: 0,
|
||||
x: 35,
|
||||
y: 55,
|
||||
jumpCounter: 0,
|
||||
jumpIncrement: Math.PI / 6,
|
||||
isJumping: false
|
||||
isJumping: false,
|
||||
character: MARIO,
|
||||
};
|
||||
|
||||
const coinSprite = {
|
||||
|
|
@ -49,6 +57,27 @@ const ONE_SECOND = 1000;
|
|||
|
||||
let timer = 0;
|
||||
let backgroundArr = [];
|
||||
let nightMode = false;
|
||||
|
||||
function genRanNum(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
function switchCharacter() {
|
||||
const curChar = characterSprite.character;
|
||||
let newChar;
|
||||
if (curChar === MARIO) {
|
||||
newChar = TOAD;
|
||||
} else {
|
||||
newChar = MARIO;
|
||||
}
|
||||
|
||||
characterSprite.character = newChar;
|
||||
}
|
||||
|
||||
function toggleNightMode() {
|
||||
nightMode = !nightMode;
|
||||
}
|
||||
|
||||
function incrementTimer() {
|
||||
if (timer > 1000) {
|
||||
|
|
@ -61,19 +90,28 @@ function incrementTimer() {
|
|||
|
||||
function drawBackground() {
|
||||
// Clear screen
|
||||
g.setColor(LIGHTEST);
|
||||
if (nightMode) {
|
||||
g.setColor(NIGHT);
|
||||
} else {
|
||||
g.setColor(LIGHTEST);
|
||||
}
|
||||
g.fillRect(0, 10, W, H);
|
||||
|
||||
// Date bar
|
||||
g.setColor(DARKEST);
|
||||
g.fillRect(0, 0, W, 9);
|
||||
|
||||
// draw sky
|
||||
g.setColor(LIGHT);
|
||||
// set cloud colors
|
||||
if (nightMode) {
|
||||
g.setColor(DARKEST);
|
||||
} else {
|
||||
g.setColor(LIGHT);
|
||||
}
|
||||
// draw clouds
|
||||
g.fillRect(0, 10, g.getWidth(), 15);
|
||||
g.fillRect(0, 17, g.getWidth(), 17);
|
||||
g.fillRect(0, 19, g.getWidth(), 19);
|
||||
g.fillRect(0, 21, g.getWidth(), 21);
|
||||
|
||||
// Date bar
|
||||
g.setColor(DARKEST);
|
||||
g.fillRect(0, 0, W, 9);
|
||||
}
|
||||
|
||||
function drawFloor() {
|
||||
|
|
@ -105,9 +143,14 @@ function drawTreesFrame(x, y) {
|
|||
g.drawLine(x + 6 /* Match stalk to palm tree */, y + 6 /* Match stalk to palm tree */, x + 6, H - 6);
|
||||
}
|
||||
|
||||
function drawTrees() {
|
||||
let newSprite = {x: 90, y: Math.floor(Math.random() * (40 /* max */ - 5 /* min */ + 1) + 15 /* min */)};
|
||||
function generateTreeSprite() {
|
||||
return {
|
||||
x: 90,
|
||||
y: Math.floor(Math.random() * (60 /* max */ - 30 /* min */ + 1) + 30 /* min */)
|
||||
};
|
||||
}
|
||||
|
||||
function drawTrees() {
|
||||
// remove first sprite if offscreen
|
||||
let firstBackgroundSprite = backgroundArr[0];
|
||||
if (firstBackgroundSprite) {
|
||||
|
|
@ -117,6 +160,7 @@ function drawTrees() {
|
|||
// set background sprite if array empty
|
||||
let lastBackgroundSprite = backgroundArr[backgroundArr.length - 1];
|
||||
if (!lastBackgroundSprite) {
|
||||
const newSprite = generateTreeSprite();
|
||||
lastBackgroundSprite = newSprite;
|
||||
backgroundArr.push(lastBackgroundSprite);
|
||||
}
|
||||
|
|
@ -125,6 +169,7 @@ function drawTrees() {
|
|||
if (backgroundArr.length < 2 && lastBackgroundSprite.x < (16 * 7)) {
|
||||
const randIdx = Math.floor(Math.random() * 25);
|
||||
if (randIdx < 2) {
|
||||
const newSprite = generateTreeSprite();
|
||||
backgroundArr.push(newSprite);
|
||||
}
|
||||
}
|
||||
|
|
@ -155,50 +200,70 @@ function drawCoin() {
|
|||
}
|
||||
|
||||
function drawMarioFrame(idx, x, y) {
|
||||
const mFr1 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw52FSg2HAAIoDAgIOMB5AAFGQTtKeBLuNcQwOJFwgJFA=")); // Mario Frame 1
|
||||
const mFr2 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw+HCQYEBSowOBBQIdCCgTOIFgiVHFwYCBUhA9FBwz8HAo73GACQA=")); // Mario frame 2
|
||||
|
||||
switch(idx) {
|
||||
case 0:
|
||||
const mFr1 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw52FSg2HAAIoDAgIOMB5AAFGQTtKeBLuNcQwOJFwgJFA=")); // Mario Frame 1
|
||||
g.drawImage(mFr1, x, y);
|
||||
break;
|
||||
case 1:
|
||||
const mFr2 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw+HCQYEBSowOBBQIdCCgTOIFgiVHFwYCBUhA9FBwz8HAo73GACQA=")); // Mario frame 2
|
||||
g.drawImage(mFr2, x, y);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
function drawMario(date) {
|
||||
function drawToadFrame(idx, x, y) {
|
||||
switch(idx) {
|
||||
case 0:
|
||||
const tFr1 = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYYrCCAwbFFwgQEM4gAEeA4OIH4ghFAAYLD")); // Toad Frame 1
|
||||
g.drawImage(tFr1, x, y);
|
||||
break;
|
||||
case 1:
|
||||
const tFr2 = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYQrDb4wcGFxYLDMoYgHRYgwKABAMBA")); // Mario frame 2
|
||||
g.drawImage(tFr2, x, y);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
function drawCharacter(date, character) {
|
||||
// calculate jumping
|
||||
const seconds = date.getSeconds(),
|
||||
milliseconds = date.getMilliseconds();
|
||||
|
||||
if (seconds == 59 && milliseconds > 800 && !marioSprite.isJumping) {
|
||||
marioSprite.isJumping = true;
|
||||
if (seconds == 59 && milliseconds > 800 && !characterSprite.isJumping) {
|
||||
characterSprite.isJumping = true;
|
||||
}
|
||||
|
||||
if (marioSprite.isJumping) {
|
||||
marioSprite.y = (Math.sin(marioSprite.jumpCounter) * -12) + 50 /* Mario Y base value */;
|
||||
marioSprite.jumpCounter += marioSprite.jumpIncrement;
|
||||
if (characterSprite.isJumping) {
|
||||
characterSprite.y = (Math.sin(characterSprite.jumpCounter) * -12) + 50 /* Character Y base value */;
|
||||
characterSprite.jumpCounter += characterSprite.jumpIncrement;
|
||||
|
||||
if (parseInt(marioSprite.jumpCounter) === 2 && !coinSprite.isAnimating) {
|
||||
if (parseInt(characterSprite.jumpCounter) === 2 && !coinSprite.isAnimating) {
|
||||
coinSprite.isAnimating = true;
|
||||
}
|
||||
|
||||
if (marioSprite.jumpCounter.toFixed(1) >= 4) {
|
||||
marioSprite.jumpCounter = 0;
|
||||
marioSprite.isJumping = false;
|
||||
if (characterSprite.jumpCounter.toFixed(1) >= 4) {
|
||||
characterSprite.jumpCounter = 0;
|
||||
characterSprite.isJumping = false;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate animation timing
|
||||
if (timer % 50 === 0) {
|
||||
// shift to next frame
|
||||
marioSprite.frameIdx ^= 1;
|
||||
characterSprite.frameIdx ^= 1;
|
||||
}
|
||||
|
||||
drawMarioFrame(marioSprite.frameIdx, marioSprite.x, marioSprite.y);
|
||||
switch(characterSprite.character) {
|
||||
case("toad"):
|
||||
drawToadFrame(characterSprite.frameIdx, characterSprite.x, characterSprite.y);
|
||||
break;
|
||||
case("mario"):
|
||||
default:
|
||||
drawMarioFrame(characterSprite.frameIdx, characterSprite.x, characterSprite.y);
|
||||
}
|
||||
}
|
||||
|
||||
function drawBrickFrame(x, y) {
|
||||
|
|
@ -244,7 +309,7 @@ function redraw() {
|
|||
drawTrees();
|
||||
drawTime(date);
|
||||
drawDate(date);
|
||||
drawMario(date);
|
||||
drawCharacter(date);
|
||||
drawCoin();
|
||||
|
||||
// Render new frame
|
||||
|
|
@ -294,7 +359,7 @@ function init() {
|
|||
|
||||
// Get Mario to jump!
|
||||
setWatch(() => {
|
||||
if (intervalRef && !marioSprite.isJumping) marioSprite.isJumping = true;
|
||||
if (intervalRef && !characterSprite.isJumping) characterSprite.isJumping = true;
|
||||
resetDisplayTimeout();
|
||||
}, BTN1, {repeat:true});
|
||||
|
||||
|
|
@ -311,13 +376,28 @@ function init() {
|
|||
}
|
||||
});
|
||||
|
||||
Bangle.on('faceUp',function(up){
|
||||
Bangle.on('faceUp', (up) => {
|
||||
if (up && !Bangle.isLCDOn()) {
|
||||
clearTimers();
|
||||
Bangle.setLCDPower(true);
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.on('swipe', (sDir) => {
|
||||
resetDisplayTimeout();
|
||||
|
||||
switch(sDir) {
|
||||
// Swipe right (1) - change character (on a loop)
|
||||
case(1):
|
||||
switchCharacter();
|
||||
break;
|
||||
// Swipe left (-1) - change day/night mode (on a loop)
|
||||
case(-1):
|
||||
default:
|
||||
toggleNightMode();
|
||||
}
|
||||
});
|
||||
|
||||
startTimers();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue