diff --git a/Readme.md b/Readme.md
index f5c5f52..c6dc4ea 100644
--- a/Readme.md
+++ b/Readme.md
@@ -23,8 +23,10 @@ There's also an easy mode for kids (slower ball).
# Next
-- check which color you get if picking a color related perk
-- sturdy bricks map of remaining hits
+- different visual effects on ball to represent which perks it's imbued with (pierce, sapper…). remove visual while it's not affected (can't pierce/sap anymore until touching the puck).
+- check which ball color you get right after picking a color related perk
+- sturdy bricks: map of remaining hits
+- looks like offline PWA mode does not work
# bugs
@@ -67,11 +69,10 @@ There's also an easy mode for kids (slower ball).
# graphics
-- apply global curve / brightness to canvas when things blow, or just always to make neon effect better
+
- lights shadows with background gradient light map ?
- webgl rendering
- shinier coins by applying glow to them
-- different visual effects on ball to represent which perks it's imbued with (pierce, sapper…). remove visual while it's not affected (can't pierce/sap anymore until touching the puck).
- experiment with showing the combo somewhere else, maybe top center, maybe instead of score.
- the white outline on bricks associated with picky eater kinda works but i feel it's more distracting than anything. maybe try something different ? put a cross on matching coloured bricks, or the contrary, grey out other bricks.
@@ -160,8 +161,7 @@ There's also an easy mode for kids (slower ball).
- [colin] perk: roulette - gagne instantanément 2 perks aléatoires
- let coins go out of bounds left and right, where they'll get lost, but +1 combo per brick
- more combo if no coin catch
-- combo climbs every time a ball bounces on puck (but bounce is random?)
--
+- combo climbs every time a ball bounces on puck (but bounce is random?)
# extra levels
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 90a2aae..9481027 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -11,8 +11,8 @@ android {
applicationId = "me.lecaro.breakout"
minSdk = 21
targetSdk = 34
- versionCode = 29038489
- versionName = "29038489"
+ versionCode = 29039826
+ versionName = "29039826"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html
index 0e7e7b6..2e794e0 100644
--- a/app/src/main/assets/index.html
+++ b/app/src/main/assets/index.html
@@ -1 +1,3760 @@
-
Breakout 71
\ No newline at end of file
+
+
+
+
+
+
+ Breakout 71
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dist/PWA/sw-b71.js b/dist/PWA/sw-b71.js
index c6e5413..e62fff8 100644
--- a/dist/PWA/sw-b71.js
+++ b/dist/PWA/sw-b71.js
@@ -1,2 +1,33 @@
-function e(e,t,n,r,a,i,c){try{var o=e[i](c),u=o.value}catch(e){n(e);return}o.done?t(u):Promise.resolve(u).then(r,a)}function t(t){return function(){var n=this,r=arguments;return new Promise(function(a,i){var c=t.apply(n,r);function o(t){e(c,a,i,o,u,"next",t)}function u(t){e(c,a,i,o,u,"throw",t)}o(void 0)})}}function n(e,t){var n,r,a,i,c={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return i={next:o(0),throw:o(1),return:o(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function o(i){return function(o){return function(i){if(n)throw TypeError("Generator is already executing.");for(;c;)try{if(n=1,r&&(a=2&i[0]?r.return:i[0]?r.throw||((a=r.return)&&a.call(r),0):r.next)&&!(a=a.call(r,i[1])).done)return a;switch(r=0,a&&(i=[2&i[0],a.value]),i[0]){case 0:case 1:a=i;break;case 4:return c.label++,{value:i[1],done:!1};case 5:c.label++,r=i[1],i=[0];continue;case 7:i=c.ops.pop(),c.trys.pop();continue;default:if(!(a=(a=c.trys).length>0&&a[a.length-1])&&(6===i[0]||2===i[0])){c=0;continue}if(3===i[0]&&(!a||i[1]>a[0]&&i[1]{
+ event.waitUntil((async ()=>{
+ const cache = await caches.open(CACHE_NAME);
+ cache.addAll(APP_STATIC_RESOURCES);
+ })());
+});
+// delete old caches on activate
+self.addEventListener("activate", (event)=>{
+ event.waitUntil((async ()=>{
+ const names = await caches.keys();
+ await Promise.all(names.map((name)=>{
+ if (name !== CACHE_NAME) return caches.delete(name);
+ }));
+ await clients.claim();
+ })());
+});
+self.addEventListener("fetch", (event)=>{
+ if (event.request.mode === "navigate" && event.request.url.endsWith("/index.html?isPWA=true")) {
+ event.respondWith(caches.match("/"));
+ return;
+ }
+});
+
//# sourceMappingURL=sw-b71.js.map
diff --git a/dist/PWA/sw-b71.js.map b/dist/PWA/sw-b71.js.map
index aee76cf..2667b32 100644
--- a/dist/PWA/sw-b71.js.map
+++ b/dist/PWA/sw-b71.js.map
@@ -1 +1 @@
-{"mappings":"A,S,E,C,C,C,C,C,C,C,C,C,C,C,C,C,E,G,C,I,E,C,C,E,C,G,E,E,K,A,C,M,E,C,E,G,M,C,E,I,C,E,G,Q,O,C,G,I,C,E,E,C,S,E,C,E,O,W,I,E,I,C,E,U,O,I,Q,S,C,C,C,E,I,E,E,K,C,E,G,S,E,C,E,E,E,E,E,E,E,O,E,C,S,E,C,E,E,E,E,E,E,E,Q,E,C,E,K,E,E,C,C,S,E,C,C,C,E,I,E,E,E,E,E,C,M,E,K,W,G,A,E,C,C,E,C,M,C,C,E,C,O,C,C,E,A,E,K,E,C,I,E,A,E,O,E,C,K,E,G,M,E,G,O,E,E,E,A,Y,O,Q,C,C,C,O,Q,C,C,W,O,I,A,C,E,E,S,E,C,E,O,S,C,E,O,A,S,C,E,G,E,M,A,U,mC,K,G,G,C,G,E,E,G,C,E,A,E,C,C,E,C,E,M,C,C,C,E,C,E,K,E,C,A,C,E,E,M,A,G,E,I,C,G,C,E,E,I,A,G,C,A,C,E,E,I,C,E,C,C,E,C,E,I,C,O,E,O,E,E,A,G,C,E,C,A,E,C,C,E,C,E,K,C,A,E,C,C,E,E,K,E,K,E,E,E,K,M,E,O,E,K,G,C,M,C,C,E,C,K,C,C,C,M,E,E,K,G,E,C,C,E,C,E,C,E,C,Q,M,E,E,E,G,C,G,G,E,I,C,G,G,Q,S,G,C,C,E,A,C,E,E,I,A,E,M,C,G,C,C,E,M,C,E,A,G,C,A,I,C,C,E,E,A,I,C,C,E,A,E,C,E,E,Q,C,G,A,I,C,C,E,E,C,C,G,C,C,E,C,C,C,E,E,C,C,E,C,C,C,E,A,E,C,E,K,C,C,C,E,C,K,C,G,A,I,C,C,E,E,E,K,C,C,C,E,C,C,E,K,C,C,C,E,C,E,E,K,C,G,G,E,K,C,C,C,E,C,C,E,K,C,C,C,E,C,E,G,C,I,C,G,K,C,C,C,E,E,E,G,C,G,G,E,I,C,G,G,Q,C,E,E,I,C,E,E,C,M,E,C,E,C,E,E,C,E,C,Q,C,E,E,C,C,G,A,E,C,C,E,C,M,C,C,E,C,M,C,M,C,C,E,C,C,C,E,C,K,E,K,C,C,C,E,C,E,E,C,C,C,CCIA,IAAM,EAAc,eAAsB,MAAA,CAH1B,YAMV,EAAuB,CAAC,IAAI,CAGlC,KAAK,gBAAgB,CAAC,UAAW,SAAC,CAAlC,EACE,EAAM,SAAS,CACb,EAAC,W,O,E,I,C,S,C,E,O,E,K,E,K,EACe,MAAA,C,EAAM,OAAO,IAAI,CAAC,G,A,M,E,OAChC,AADc,EAAR,IAAA,GACA,MAAM,CAAC,G,C,E,A,C,EACf,KAEJ,GAGA,KAAK,gBAAgB,CAAC,WAAY,SAAC,CAAnC,EACE,EAAM,SAAS,CACb,EAAC,W,O,E,I,C,S,C,E,O,E,K,E,K,EACe,MAAA,C,EAAM,OAAO,IAAI,G,A,M,EAC/B,MAAA,C,EAAM,QAAQ,GAAG,CACf,AAFY,EAAR,IAAA,GAEE,GAAG,CAAC,SAAC,CADP,EAEF,GAAI,IAAS,EACX,OAAO,OAAO,MAAM,CAAC,EAEzB,I,A,M,EAEF,OAPA,EAAA,IAAA,GAOA,C,EAAM,QAAQ,KAAK,G,A,M,E,OAAnB,EAAA,IAAA,G,C,E,A,C,EACF,KAEJ,GAEA,KAAK,gBAAgB,CAAC,QAAS,SAAC,CAAhC,EACE,GACE,AAAuB,aAAvB,EAAM,OAAO,CAAC,IAAI,EAClB,EAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,0BAC3B,CACA,EAAM,WAAW,CAAC,OAAO,KAAK,CAAC,MAC/B,MACF,CACF","sources":["","src/PWA/sw-b71.js"],"sourcesContent":["// The version of the cache.\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n try {\n var info = gen[key](arg);\n var value = info.value;\n } catch (error) {\n reject(error);\n return;\n }\n if (info.done) {\n resolve(value);\n } else {\n Promise.resolve(value).then(_next, _throw);\n }\n}\nfunction _async_to_generator(fn) {\n return function() {\n var self1 = this, args = arguments;\n return new Promise(function(resolve, reject) {\n var gen = fn.apply(self1, args);\n function _next(value) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n }\n function _throw(err) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n }\n _next(undefined);\n });\n };\n}\nfunction _ts_generator(thisArg, body) {\n var f, y, t, g, _ = {\n label: 0,\n sent: function() {\n if (t[0] & 1) throw t[1];\n return t[1];\n },\n trys: [],\n ops: []\n };\n return g = {\n next: verb(0),\n \"throw\": verb(1),\n \"return\": verb(2)\n }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() {\n return this;\n }), g;\n function verb(n) {\n return function(v) {\n return step([\n n,\n v\n ]);\n };\n }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while(_)try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [\n op[0] & 2,\n t.value\n ];\n switch(op[0]){\n case 0:\n case 1:\n t = op;\n break;\n case 4:\n _.label++;\n return {\n value: op[1],\n done: false\n };\n case 5:\n _.label++;\n y = op[1];\n op = [\n 0\n ];\n continue;\n case 7:\n op = _.ops.pop();\n _.trys.pop();\n continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {\n _ = 0;\n continue;\n }\n if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {\n _.label = op[1];\n break;\n }\n if (op[0] === 6 && _.label < t[1]) {\n _.label = t[1];\n t = op;\n break;\n }\n if (t && _.label < t[2]) {\n _.label = t[2];\n _.ops.push(op);\n break;\n }\n if (t[2]) _.ops.pop();\n _.trys.pop();\n continue;\n }\n op = body.call(thisArg, _);\n } catch (e) {\n op = [\n 6,\n e\n ];\n y = 0;\n } finally{\n f = t = 0;\n }\n if (op[0] & 5) throw op[1];\n return {\n value: op[0] ? op[1] : void 0,\n done: true\n };\n }\n}\nvar VERSION = \"29038489\";\n// The name of the cache\nvar CACHE_NAME = \"breakout-71-\".concat(VERSION);\n// The static resources that the app needs to function.\nvar APP_STATIC_RESOURCES = [\n \"/\"\n];\n// On install, cache the static resources\nself.addEventListener(\"install\", function(event) {\n event.waitUntil(_async_to_generator(function() {\n var cache;\n return _ts_generator(this, function(_state) {\n switch(_state.label){\n case 0:\n return [\n 4,\n caches.open(CACHE_NAME)\n ];\n case 1:\n cache = _state.sent();\n cache.addAll(APP_STATIC_RESOURCES);\n return [\n 2\n ];\n }\n });\n })());\n});\n// delete old caches on activate\nself.addEventListener(\"activate\", function(event) {\n event.waitUntil(_async_to_generator(function() {\n var names;\n return _ts_generator(this, function(_state) {\n switch(_state.label){\n case 0:\n return [\n 4,\n caches.keys()\n ];\n case 1:\n names = _state.sent();\n return [\n 4,\n Promise.all(names.map(function(name) {\n if (name !== CACHE_NAME) return caches[\"delete\"](name);\n }))\n ];\n case 2:\n _state.sent();\n return [\n 4,\n clients.claim()\n ];\n case 3:\n _state.sent();\n return [\n 2\n ];\n }\n });\n })());\n});\nself.addEventListener(\"fetch\", function(event) {\n if (event.request.mode === \"navigate\" && event.request.url.endsWith(\"/index.html?isPWA=true\")) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n\n//# sourceMappingURL=sw-b71.js.map\n","// The version of the cache.\nconst VERSION = \"29038489\";\n\n// The name of the cache\nconst CACHE_NAME = `breakout-71-${VERSION}`;\n\n// The static resources that the app needs to function.\nconst APP_STATIC_RESOURCES = [\"/\"];\n\n// On install, cache the static resources\nself.addEventListener(\"install\", (event) => {\n event.waitUntil(\n (async () => {\n const cache = await caches.open(CACHE_NAME);\n cache.addAll(APP_STATIC_RESOURCES);\n })(),\n );\n});\n\n// delete old caches on activate\nself.addEventListener(\"activate\", (event) => {\n event.waitUntil(\n (async () => {\n const names = await caches.keys();\n await Promise.all(\n names.map((name) => {\n if (name !== CACHE_NAME) {\n return caches.delete(name);\n }\n }),\n );\n await clients.claim();\n })(),\n );\n});\n\nself.addEventListener(\"fetch\", (event) => {\n if (\n event.request.mode === \"navigate\" &&\n event.request.url.endsWith(\"/index.html?isPWA=true\")\n ) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n"],"names":["asyncGeneratorStep","gen","resolve","reject","_next","_throw","key","arg","info","value","error","done","Promise","then","_async_to_generator","fn","self1","args","arguments","apply","err","undefined","_ts_generator","thisArg","body","f","y","t","g","_","label","sent","trys","ops","next","verb","Symbol","iterator","n","v","step","op","TypeError","call","pop","length","push","e","CACHE_NAME","concat","APP_STATIC_RESOURCES","self","addEventListener","event","waitUntil","_state","caches","open","cache","addAll","keys","all","names","map","name","clients","claim","request","mode","url","endsWith","respondWith","match"],"version":3,"file":"sw-b71.js.map"}
\ No newline at end of file
+{"mappings":"AAAA,4BAA4B;AAC5B,MAAM,UAAU;AAEhB,wBAAwB;AACxB,MAAM,aAAa,CAAC,YAAY,EAAE,SAAS;AAE3C,uDAAuD;AACvD,MAAM,uBAAuB;IAAC;CAAI;AAElC,yCAAyC;AACzC,KAAK,gBAAgB,CAAC,WAAW,CAAC;IAChC,MAAM,SAAS,CACb,AAAC,CAAA;QACC,MAAM,QAAQ,MAAM,OAAO,IAAI,CAAC;QAChC,MAAM,MAAM,CAAC;IACf,CAAA;AAEJ;AAEA,gCAAgC;AAChC,KAAK,gBAAgB,CAAC,YAAY,CAAC;IACjC,MAAM,SAAS,CACb,AAAC,CAAA;QACC,MAAM,QAAQ,MAAM,OAAO,IAAI;QAC/B,MAAM,QAAQ,GAAG,CACf,MAAM,GAAG,CAAC,CAAC;YACT,IAAI,SAAS,YACX,OAAO,OAAO,MAAM,CAAC;QAEzB;QAEF,MAAM,QAAQ,KAAK;IACrB,CAAA;AAEJ;AAEA,KAAK,gBAAgB,CAAC,SAAS,CAAC;IAC9B,IACE,MAAM,OAAO,CAAC,IAAI,KAAK,cACvB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,2BAC3B;QACA,MAAM,WAAW,CAAC,OAAO,KAAK,CAAC;QAC/B;IACF;AACF","sources":["src/PWA/sw-b71.js"],"sourcesContent":["// The version of the cache.\nconst VERSION = \"29039826\";\n\n// The name of the cache\nconst CACHE_NAME = `breakout-71-${VERSION}`;\n\n// The static resources that the app needs to function.\nconst APP_STATIC_RESOURCES = [\"/\"];\n\n// On install, cache the static resources\nself.addEventListener(\"install\", (event) => {\n event.waitUntil(\n (async () => {\n const cache = await caches.open(CACHE_NAME);\n cache.addAll(APP_STATIC_RESOURCES);\n })(),\n );\n});\n\n// delete old caches on activate\nself.addEventListener(\"activate\", (event) => {\n event.waitUntil(\n (async () => {\n const names = await caches.keys();\n await Promise.all(\n names.map((name) => {\n if (name !== CACHE_NAME) {\n return caches.delete(name);\n }\n }),\n );\n await clients.claim();\n })(),\n );\n});\n\nself.addEventListener(\"fetch\", (event) => {\n if (\n event.request.mode === \"navigate\" &&\n event.request.url.endsWith(\"/index.html?isPWA=true\")\n ) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n"],"names":[],"version":3,"file":"sw-b71.js.map","sourceRoot":"/__parcel_source_root/"}
\ No newline at end of file
diff --git a/dist/index.html b/dist/index.html
index 0e7e7b6..2e794e0 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -1 +1,3760 @@
-Breakout 71
\ No newline at end of file
+
+
+
+
+
+
+ Breakout 71
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/PWA/sw-b71.js b/src/PWA/sw-b71.js
index 2f44cf5..3beeea2 100644
--- a/src/PWA/sw-b71.js
+++ b/src/PWA/sw-b71.js
@@ -1,5 +1,5 @@
// The version of the cache.
-const VERSION = "29038489";
+const VERSION = "29039826";
// The name of the cache
const CACHE_NAME = `breakout-71-${VERSION}`;
diff --git a/src/data/version.json b/src/data/version.json
index fe47c5f..3575b04 100644
--- a/src/data/version.json
+++ b/src/data/version.json
@@ -1 +1 @@
-"29038489"
+"29039826"
diff --git a/src/game.ts b/src/game.ts
index 9523834..e332cc3 100644
--- a/src/game.ts
+++ b/src/game.ts
@@ -273,8 +273,6 @@ export async function openUpgradesPicker(gameState: GameState) {
gameState.runStatistics.upgrades_picked++;
}
- resetCombo(gameState, undefined, undefined);
- resetBalls(gameState);
}
gameCanvas.addEventListener("mouseup", (e) => {
diff --git a/src/gameStateMutators.ts b/src/gameStateMutators.ts
index 3325c4e..bdc28ec 100644
--- a/src/gameStateMutators.ts
+++ b/src/gameStateMutators.ts
@@ -82,7 +82,6 @@ export function resetBalls(gameState: GameState) {
sx: 0,
sy: 0,
- sparks: 0,
piercedSinceBounce: 0,
hitSinceBounce: 0,
hitItem: [],
@@ -166,9 +165,7 @@ export function resetCombo(
) {
const prev = gameState.combo;
gameState.combo = baseCombo(gameState);
- if (!gameState.levelTime) {
- gameState.combo += gameState.perks.hot_start * 15;
- }
+
if (prev > gameState.combo && gameState.perks.soft_reset) {
gameState.combo += Math.floor(
((prev - gameState.combo) * (gameState.perks.soft_reset * 10)) / 100,
@@ -467,14 +464,13 @@ export function addToScore(gameState: GameState, coin: Coin) {
gameState.runStatistics.score += coin.points;
}
-export function setLevel(gameState: GameState, l: number) {
+export async function setLevel(gameState: GameState, l: number) {
stopRecording();
pause(false);
if (l > 0) {
- openUpgradesPicker(gameState);
+ await openUpgradesPicker(gameState);
}
gameState.currentLevel = l;
-
gameState.levelTime = 0;
gameState.levelWallBounces = 0;
gameState.autoCleanUses = 0;
@@ -484,7 +480,9 @@ export function setLevel(gameState: GameState, l: number) {
gameState.levelMisses = 0;
gameState.runStatistics.levelsPlayed++;
- resetCombo(gameState, undefined, undefined);
+ // Reset combo silently
+ gameState.combo = baseCombo(gameState) + gameState.perks.hot_start * 15;
+
resetBalls(gameState);
const lvl = currentLevelInfo(gameState);
@@ -1161,21 +1159,36 @@ export function ballTick(gameState: GameState, ball: Ball, delta: number) {
}
if (!isOptionOn("basic")) {
- ball.sparks += (delta * (gameState.combo - 1)) / 30;
- if (ball.sparks > 1) {
+ const remainingPierce =
+ gameState.perks.pierce * 3 - ball.piercedSinceBounce;
+ const remainingSapper = ball.sapperUses < gameState.perks.sapper;
+ const extraCombo = gameState.combo - 1;
+ if (
+ (extraCombo && Math.random() > 0.1 / (1 + extraCombo)) ||
+ (remainingSapper && Math.random() > 0.1 / (1 + remainingSapper)) ||
+ (extraCombo && Math.random() > 0.1 / (1 + extraCombo))
+ ) {
+ const color = remainingSapper
+ ? Math.random() > 0.5
+ ? "orange"
+ : "red"
+ : gameState.ballsColor;
+
makeParticle(
gameState,
ball.x,
ball.y,
- (Math.random() - 0.5) * gameState.baseSpeed,
- (Math.random() - 0.5) * gameState.baseSpeed,
- gameState.ballsColor,
- false,
+ gameState.perks.pierce_color || remainingPierce
+ ? -ball.vx + ((Math.random() - 0.5) * gameState.baseSpeed) / 3
+ : (Math.random() - 0.5) * gameState.baseSpeed,
+ gameState.perks.pierce_color || remainingPierce
+ ? -ball.vy + ((Math.random() - 0.5) * gameState.baseSpeed) / 3
+ : (Math.random() - 0.5) * gameState.baseSpeed,
+ color,
+ true,
gameState.coinSize / 2,
- 100 * ball.sparks,
+ 100,
);
-
- ball.sparks = 0;
}
}
}
diff --git a/src/types.d.ts b/src/types.d.ts
index 5bdb231..c0acf3f 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -94,7 +94,6 @@ export type Ball = {
previousVY: number;
sx: number;
sy: number;
- sparks: number;
piercedSinceBounce: number;
hitSinceBounce: number;
hitItem: { index: number; color: string }[];