diff --git a/apps/tetris/ChangeLog b/apps/tetris/ChangeLog index 86661f1b6..158cccc5b 100644 --- a/apps/tetris/ChangeLog +++ b/apps/tetris/ChangeLog @@ -2,3 +2,4 @@ 0.02: Better controls, implement game over. 0.03: Implement mode and level selection screens. 0.04: Bring back old controls as "swipe" in menu, exit with button press +0.10: Major overhaul: added score, levels, bugfixes and misc, inspired by NES tetris diff --git a/apps/tetris/metadata.json b/apps/tetris/metadata.json index ba73918d5..8b73ffb43 100644 --- a/apps/tetris/metadata.json +++ b/apps/tetris/metadata.json @@ -1,7 +1,7 @@ { "id": "tetris", "name": "Tetris", "shortName":"Tetris", - "version":"0.04", + "version":"0.10", "description": "Tetris", "icon": "tetris.png", "readme": "README.md", diff --git a/apps/tetris/tetris.app.js b/apps/tetris/tetris.app.js index e4295732b..baad84f77 100644 --- a/apps/tetris/tetris.app.js +++ b/apps/tetris/tetris.app.js @@ -41,7 +41,7 @@ const oy = 8; 2 .. accelerometer. 12 lines record. 3 .. altimeter */ -var control = 0, level = 0; +var control = 0, level = 0, lines = 0, score = 0; var alt_start = -9999; /* For altimeter control */ /* 0 .. menu 1 .. game @@ -77,7 +77,9 @@ function drawBoundingBox() { for (i=0; i<4; ++i) g.drawRect(ox-i-1, oy-i-1, ox+10*8+i, oy+20*8+i); } -function drawTile (tile, n, x, y, qClear) { +function drawTile(tile, n, x, y, qClear) { + if (state != 1) // stops tile from being drawn on the game over screen + return; if (qClear) g.setColor(0); else g.setColor(tcols[n].r, tcols[n].g, tcols[n].b); for (i=0; i0) pf[py+y][px+x+1] = ctn+1; // check for full lines + let clearCount = 0; for (y=19; y>0; y--) { var qFull = true; for (x=1; x<11; ++x) qFull &= pf[y][x]>0; if (qFull) { - nlines++; - dropInterval -= 5; - Bangle.buzz(30); + clearCount++; for (ny=y; ny>0; ny--) pf[ny] = JSON.parse(JSON.stringify(pf[ny-1])); redrawPF(y); - g.setColor(0).fillRect(5, 30, 41, 80).setColor(1, 1, 1).drawString(nlines.toString(), 22, 50); } } + if (clearCount) { + lines += clearCount; + let effectiveLevel = Math.max(level, 1); + if (clearCount == 1) { // single + score += 100 * effectiveLevel; + Bangle.buzz(80, 0.5); + } + else if (clearCount == 2) { // double + score += 300 * effectiveLevel; + Bangle.buzz(80); + } + else if (clearCount == 3) { // triple + score += 500 * effectiveLevel; + Bangle.buzz(150); + } + else if (clearCount >= 4) { // tetris + score += 800 * effectiveLevel; + Bangle.buzz(300); + } + if (lines != 0 && lines % 10 == 0) { + level++; + calculateSpeed(); + } + redrawStats(); + } // spawn new tile px = 4; py = 0; ctn = ntn; @@ -149,18 +204,33 @@ function insertAndCheck() { function moveOk(t, dx, dy) { var ok = true; - for (y=0; y 0) ok = false; return ok; } +function pauseGame() { + print("Paused"); + state = 3; +} + +function resumeGame() { + print("Resumed"); + state = 1; +} + function gameStep() { if (state != 1) return; if (Date.now()-time > dropInterval) { // drop one step time = Date.now(); - if (moveOk(ct, 0, 1)) { + if (level >= 15 && moveOk(ct, 0, 2)) { + // at level 15, pieces drop twile as quickly + drawTile(ct, ctn, ox+px*8, oy+py*8, true); + py += 2; + } + else if (moveOk(ct, 0, 1)) { drawTile(ct, ctn, ox+px*8, oy+py*8, true); py++; } @@ -181,16 +251,18 @@ function rotate() { } function move(x, y) { - if (moveOk(ct, x, y)) { + r = moveOk(ct, x, y); + if (r) { drawTile(ct, ctn, ox+px*8, oy+py*8, true); px += x; py += y; drawTile(ct, ctn, ox+px*8, oy+py*8, false); } + return r; } function linear(x) { - print("Linear: ", x); + //print("Linear: ", x); let now = px / 10; if (x < now-0.06) move(-1, 0); @@ -200,36 +272,16 @@ function linear(x) { function newGame() { E.showMenu(); - Bangle.setUI({mode : "custom", btn: () => load()}); - if (control == 4) { // Swipe - Bangle.on("touch", (e) => { - t = rotateTile(ct, 3); - if (moveOk(t, 0, 0)) { - drawTile(ct, ctn, ox+px*8, oy+py*8, true); - ct = t; - drawTile(ct, ctn, ox+px*8, oy+py*8, false); - } + Bangle.setUI(); + if (control == 2) { + Bangle.on("accel", (e) => { + if (state != 1) return; + if (control != 2) return; + print(e.x); + linear((0.2-e.x) * 2.5); }); - - Bangle.on("swipe", (x,y) => { - if (y<0) y = 0; - if (moveOk(ct, x, y)) { - drawTile(ct, ctn, ox+px*8, oy+py*8, true); - px += x; - py += y; - drawTile(ct, ctn, ox+px*8, oy+py*8, false); - } - }); - } else { // control != 4 - if (control == 2) { // Tilt - Bangle.on("accel", (e) => { - if (state != 1) return; - if (control != 2) return; - print(e.x); - linear((0.2-e.x) * 2.5); - }); - } - if (control == 3) { // Move + } + if (control == 3) { Bangle.setBarometerPower(true); Bangle.on("pressure", (e) => { if (state != 1) return; @@ -238,86 +290,83 @@ function newGame() { if (alt_start == -9999) alt_start = a; a = a - alt_start; - print(e.altitude, a); + //print(e.altitude, a); linear(a); }); - } - Bangle.on("drag", (e) => { - let h = 176/2; - if (state == 2) { - if (e.b) - selectGame(); - return; - } - if (!e.b) - return; - if (state == 0) return; - if (e.y < h) { - if (e.x < h) - rotate(); - else { - let i = 0; - for (i=0; i<10; i++) { - move(0, 1); - g.flip(); - } - } - } else { - if (control == 1) - linear((e.x - 20) / 156); - if (control != 0) - return; - if (e.x < h) - move(-1, 0); - else - move(1, 0); - } - }); } + Bangle.on("drag", (e) => { + let h = 176/2; + if (state == 2) { + if (e.b) + selectGame(); + return; + } + if (!e.b) + return; + if (state == 0) return; + if (e.y < h) { + if (e.x < h) + rotate(); + else { + while (move(0, 1)) { + score++; + g.flip(); + } + redrawStats(true); + } + } else { + if (control == 1) + linear((e.x - 20) / 156); + if (control != 0) + return; + if (e.x < h) + move(-1, 0); + else + move(1, 0); + } + }); + setWatch(() => { + if (state == 1) + pauseGame(); + else if (state == 3) + resumeGame(); + }, BTN1, {repeat: true}); initGame(); drawGame(); state = 1; - var step = 450 - 50*level; - if (control == 3) - step = step*2; - dropInterval = step; - var gi = setInterval(gameStep, 50); + calculateSpeed(); + var gi = setInterval(gameStep, 20); } function drawGame() { drawBoundingBox(); g.setColor(1, 1, 1).setFontAlign(0, 1, 0) - .setFont("6x15", 1).drawString("Lines", 22, 30) + .setFont("6x15", 1).drawString("Score", 22, 30) + .drawString("Level", 22, 80) + .drawString("Lines", 22, 130) .drawString("Next", 176-22, 30); showNext(ntn, ntr); - g.setColor(0).fillRect(5, 30, 41, 80) - .setColor(1, 1, 1).drawString(nlines.toString(), 22, 50); -} - -function selectLevel() { - print("Level selection menu"); - - var menu = {}; - menu["< Back"] = () => {selectGame();}; - menu[/*LANG*/"Level 1"] = () => { level = 0; selectGame(); }; - menu[/*LANG*/"Level 2"] = () => { level = 1; selectGame(); }; - menu[/*LANG*/"Level 3"] = () => { level = 2; selectGame(); }; - E.showMenu(menu); + redrawStats(); } function selectGame() { state = 0; print("Game selection menu"); - //for (let i = 0; i < 100000; i++) ; - + var menu = {}; - menu[/*LANG*/"Normal"] = () => { control = 0; newGame(); }; - menu[/*LANG*/"Drag"] = () => { control = 1; newGame(); }; - menu[/*LANG*/"Tilt"] = () => { control = 2; newGame(); }; - menu[/*LANG*/"Move"] = () => { control = 3; newGame(); }; - menu[/*LANG*/"Swipe"] = () => { control = 4; newGame(); }; - menu[/*LANG*/"Level"] = () => { selectLevel(); }; + menu["Normal"] = () => { control = 0; newGame(); }; + menu["Drag"] = () => { control = 1; newGame(); }; + menu["Tilt"] = () => { control = 2; newGame(); }; + menu["Pressure"] = () => { control = 3; newGame(); }; + level = 1; + menu["Level"] = { + value : 1, + min : 0, + max : 10, + wrap : true, + onchange : (l) => { level = l; } + }; E.showMenu(menu); }