diff --git a/apps.json b/apps.json index a312b90a3..98b8b8730 100644 --- a/apps.json +++ b/apps.json @@ -4675,5 +4675,20 @@ "data": [ {"name":"pooqroman.json"} ] + }, + { + "id": "flow", + "name": "FLOW", + "shortName": "FLOW", + "version": "0.01", + "description": "A game where you have to help a flow avoid white obstacles thing by tapping! This is a demake of an app which I forgot the name of. Press BTN(1) to restart. See if you can get to 2500 score!", + "icon": "app.png", + "tags": "game", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name": "flow.app.js", "url": "app.js" }, + {"name": "flow.img", "url": "app-icon.js","evaluate": true } + ] } ] diff --git a/apps/flow/README.md b/apps/flow/README.md new file mode 100644 index 000000000..caeaf92d9 --- /dev/null +++ b/apps/flow/README.md @@ -0,0 +1,12 @@ +# FLOW + +This is a game where you have to help a flow avoid white obstacles thing by tapping! +This is a demake of an app which I forgot the name of. +Press BTN(1) to restart. +See if you can get to 2500 score! + +## Screenshots + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) diff --git a/apps/flow/app-icon.js b/apps/flow/app-icon.js new file mode 100644 index 000000000..969a608f4 --- /dev/null +++ b/apps/flow/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AwX48EHgEC1WgCQkVqoDBBfuqBQcBqoLagEqGAguBqALaGAOoAoQuEBbEAKgIMBBQNUBbgMCyoKHBbBVBBYIKGBbEBtNVrQLfOgNaT4gLagp0CPQOABbcBFwNAgEKBgILbitVqAFClWq0ALZFwTDFGAQLZFwYwDBfg")) diff --git a/apps/flow/app.js b/apps/flow/app.js new file mode 100644 index 000000000..5f4da8f35 --- /dev/null +++ b/apps/flow/app.js @@ -0,0 +1,220 @@ +const isB2 = process.env.HWVERSION === 2; + +// Bangle.js 1 runs just too fast in direct mode??? (also no getPixel) +if (!isB2) Bangle.setLCDMode("120x120"); + +const options = Bangle.getOptions(); + +options.lockTimeout = 0; +options.lcdPowerTimeout = 0; + +Bangle.setOptions(options); + +g.reset(); +g.setBgColor(0, 0, 0); +g.setColor(255, 255, 255); +g.clear(); +const h = g.getHeight(); + +function trigToCoord(ret) { + return ((ret + 1) * h) / 2; +} + +function trigToLen(ret) { + return (ret * h) / 2; +} + +let i = 0.2; +let speedCoef = 0.014; + +let flowFile = require("Storage").readJSON("flow.json"); + +let highestI = (flowFile && flowFile.hiscore) || 0.1; + +let colorA = [255, 255, 0]; +let colorB = [0, 255, 255]; + +let x = 0; +let xt = 0; +let safeMode = false; +let lost = false; + +function offsetRect(g, x, y, w) { + g.fillRect(x, y, x + w, y + w); +} + +function getColor(num) { + return [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 1, 0], + [0, 1, 1], + [1, 0, 1], + [0.5, 0.5, 1], + [1, 0.5, 0], + [0, 1, 0.5], + [0.5, 0.5, 0.5], + ][num]; +} + +function calculateColor(num) { + colorA = getColor(Math.floor((num % 1) * 10)); + colorB = getColor(Math.floor((num % 10) - (num % 1))); +} + +calculateColor(highestI); + +Bangle.on("touch", () => (safeMode = !safeMode)); + +function resetGame() { + x = xt = 0; + safeMode = lost = false; + i = 0.2; + speedCoef = 0.014; + obstaclePeriod = 150; + obstacleMode = 1; + g.clear(); + shownScore = false; + intervalId = setInterval(draw); +} + +function checkCollision() { + lost = g.getPixel(trigToCoord(+x), (h * 2) / 3 - 4) !== 0; + if (lost) { + scoringI = i; + speedCoef = Math.min(speedCoef, 0.02); + g.setFont(isB2 ? "6x15" : "4x6", 3); + g.setColor(colorA[0], colorA[1], colorA[2]) + .drawString( + "Game over", + trigToCoord(0) - g.stringWidth("Game over") / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } +} + +function drawPlayer() { + if (!safeMode) xt = Math.cos(i * Math.PI * 4) / 7.5; + else xt = -Math.cos(i * Math.PI * 2) / 20 + 0.35; + x = x * 0.8 + xt * 0.2; + if (highestI > 250) calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + offsetRect(g, trigToCoord(+x), (h * 2) / 3, 3); + g.setColor(colorB[0], colorB[1], colorB[2]); + offsetRect(g, trigToCoord(-x), (h * 2) / 3, 3); +} + +let obstaclePeriod = 150; +let obstacleMode = 1; + +function drawObstracle() { + g.setColor(1, 1, 1); + switch (obstacleMode) { + case 0: + offsetRect(g, trigToCoord(-0.15), 0, trigToLen(0.3)); + break; + case 1: + offsetRect(g, trigToCoord(0.2), 0, trigToLen(0.2)); + offsetRect(g, trigToCoord(-0.4), 0, trigToLen(0.2)); + break; + case 2: + break; + } + obstaclePeriod--; + if (obstaclePeriod <= 0) { + // If we are off cooldown mode, pick a random actual mode + if (obstacleMode === 2) { + obstaclePeriod = Math.random() * 50 + 50; + obstacleMode = Math.round(Math.random()); + } else if (Math.random() > 0.5) { + // Give it a chance to repeat with no cooldown + obstaclePeriod = 25 + 2.5 * speedCoef; + obstacleMode = 2; + } + } +} + +let shownScore = false; +let scoringI = 0; + +function draw() { + if (!lost) { + drawPlayer(); + checkCollision(); + speedCoef *= 1.0005; + drawObstracle(); + } else { + speedCoef /= 1.05; + if (speedCoef <= 0.005) { + clearInterval(intervalId); + i -= speedCoef; + g.setFont(isB2 ? "6x15" : "4x6", 1); + const str = "Hiscore: " + Math.round(highestI * 10); + g.setColor( + scoringI > highestI ? 0 : 255, + 0, + scoringI > highestI ? 255 : 0 + ) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(255, 255, 255); + if (scoringI > highestI) { + highestI = scoringI; + require("Storage").writeJSON("flow.json", { + hiscore: highestI, + }); + calculateColor(highestI); + } + setTimeout(resetGame, 3000); + } else if (speedCoef <= 0.01 && !shownScore) { + shownScore = true; + g.setFont(isB2 ? "6x15" : "4x6", 2); + const str = "Score: " + Math.round(scoringI * 10); + g.setColor(colorB[0], colorB[1], colorB[2]) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } + } + i += speedCoef; + g.scroll(0, speedCoef * h); + g.flip(); +} + +let intervalId; + +if (BTN.read()) { + for (let i = 0; i < 10; i++) { + color = getColor(i); + g.setColor(color[0], color[1], color[2]); + g.fillRect((i / 10) * h, 0, ((i + 1) / 10) * h, h); + } + g.setColor(0); + g.setFont("Vector", 9); + let str = "Welcome to the debug screen!"; + g.drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) - 9 + ); + str = "Don't hold BTN while opening to play!"; + g.drawString(str, trigToCoord(0) - g.stringWidth(str) / 2, trigToCoord(0)); + g.flip(); + setInterval(() => { + g.scroll(0, 0.014 * h); + i += 0.014; + calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + g.fillRect(0, 0, trigToCoord(0), 0.014 * h); + g.setColor(colorB[0], colorB[1], colorB[2]); + g.fillRect(trigToCoord(0), 0, trigToCoord(1), 0.014 * h); + }, 1000 / 30); +} else intervalId = setInterval(draw, 1000 / 30); diff --git a/apps/flow/app.png b/apps/flow/app.png new file mode 100644 index 000000000..b35c3ca77 Binary files /dev/null and b/apps/flow/app.png differ diff --git a/apps/flow/screenshot1.png b/apps/flow/screenshot1.png new file mode 100644 index 000000000..fd5dee427 Binary files /dev/null and b/apps/flow/screenshot1.png differ diff --git a/apps/flow/screenshot2.png b/apps/flow/screenshot2.png new file mode 100644 index 000000000..e29691b69 Binary files /dev/null and b/apps/flow/screenshot2.png differ diff --git a/apps/flow/screenshot3.png b/apps/flow/screenshot3.png new file mode 100644 index 000000000..3e1c80ba7 Binary files /dev/null and b/apps/flow/screenshot3.png differ