1
0
Fork 0

tetris: major overhaul

Added score, levels, bugfixes and misc, inspired by NES tetris
master
Anonymous941 2024-01-21 19:24:31 -05:00
parent daf7e745ec
commit 1a1b79d41b
3 changed files with 154 additions and 104 deletions

View File

@ -2,3 +2,4 @@
0.02: Better controls, implement game over. 0.02: Better controls, implement game over.
0.03: Implement mode and level selection screens. 0.03: Implement mode and level selection screens.
0.04: Bring back old controls as "swipe" in menu, exit with button press 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

View File

@ -1,7 +1,7 @@
{ "id": "tetris", { "id": "tetris",
"name": "Tetris", "name": "Tetris",
"shortName":"Tetris", "shortName":"Tetris",
"version":"0.04", "version":"0.10",
"description": "Tetris", "description": "Tetris",
"icon": "tetris.png", "icon": "tetris.png",
"readme": "README.md", "readme": "README.md",

View File

@ -41,7 +41,7 @@ const oy = 8;
2 .. accelerometer. 12 lines record. 2 .. accelerometer. 12 lines record.
3 .. altimeter 3 .. altimeter
*/ */
var control = 0, level = 0; var control = 0, level = 0, lines = 0, score = 0;
var alt_start = -9999; /* For altimeter control */ var alt_start = -9999; /* For altimeter control */
/* 0 .. menu /* 0 .. menu
1 .. game 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); 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); if (qClear) g.setColor(0);
else g.setColor(tcols[n].r, tcols[n].g, tcols[n].b); else g.setColor(tcols[n].r, tcols[n].g, tcols[n].b);
for (i=0; i<tile.length; ++i) for (i=0; i<tile.length; ++i)
@ -99,8 +101,25 @@ var ctn = Math.floor(Math.random()*7); // current tile number
var ntn = Math.floor(Math.random()*7); // next tile number var ntn = Math.floor(Math.random()*7); // next tile number
var ntr = Math.floor(Math.random()*4); // next tile rotation var ntr = Math.floor(Math.random()*4); // next tile rotation
var ct = rotateTile(tiles[ctn], Math.floor(Math.random()*4)); // current tile (rotated) var ct = rotateTile(tiles[ctn], Math.floor(Math.random()*4)); // current tile (rotated)
var dropInterval = 450; var dropInterval;
var nlines = 0;
function calculateSpeed() {
let step = 500;
if (level <= 6) // 200-500ms
step = step - 50*level;
else if (level <= 13) { // 25-175ms
step = 200;
step = step - 25*(level - 6);
}
else {
step = 20; // usually limited by the hardware
// levels 15+ are programmed to go faster by skipping lines
}
print(`level ${level}: drop interval ${step}ms`)
if (control == 3)
step = step*2;
dropInterval = step;
}
function redrawPF(ly) { function redrawPF(ly) {
for (y=0; y<=ly; ++y) for (y=0; y<=ly; ++y)
@ -112,10 +131,23 @@ function redrawPF(ly) {
} }
function gameOver() { function gameOver() {
state = 0;
g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22) g.setColor(1, 1, 1).setFontAlign(0, 1, 0).setFont("Vector",22)
.drawString("Game Over", 176/2, 76); .drawString("Game Over", 176/2, 76);
state = 0;
E.showAlert("Game Over").then(selectGame, print); E.showAlert("Game Over").then(selectGame, print);
lines = 0;
score = 0;
}
function redrawStats(onlyScore) {
g.setColor(0).fillRect(5, 30, 41, 60)
.setColor(1, 1, 1).drawString(score.toString(), 22, 50);
if (!onlyScore) {
g.setColor(0).fillRect(5, 80, 41, 110)
.setColor(1, 1, 1).drawString(level.toString(), 22, 100)
.setColor(0).fillRect(5, 130, 41, 160)
.setColor(1, 1, 1).drawString(lines.toString(), 22, 150);
}
} }
function insertAndCheck() { function insertAndCheck() {
@ -123,18 +155,41 @@ function insertAndCheck() {
for (x=0; x<ct[y].length; ++x) for (x=0; x<ct[y].length; ++x)
if (ct[y][x]>0) pf[py+y][px+x+1] = ctn+1; if (ct[y][x]>0) pf[py+y][px+x+1] = ctn+1;
// check for full lines // check for full lines
let clearCount = 0;
for (y=19; y>0; y--) { for (y=19; y>0; y--) {
var qFull = true; var qFull = true;
for (x=1; x<11; ++x) qFull &= pf[y][x]>0; for (x=1; x<11; ++x) qFull &= pf[y][x]>0;
if (qFull) { if (qFull) {
nlines++; clearCount++;
dropInterval -= 5;
Bangle.buzz(30);
for (ny=y; ny>0; ny--) pf[ny] = JSON.parse(JSON.stringify(pf[ny-1])); for (ny=y; ny>0; ny--) pf[ny] = JSON.parse(JSON.stringify(pf[ny-1]));
redrawPF(y); 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 // spawn new tile
px = 4; py = 0; px = 4; py = 0;
ctn = ntn; ctn = ntn;
@ -155,12 +210,27 @@ function moveOk(t, dx, dy) {
return ok; return ok;
} }
function pauseGame() {
print("Paused");
state = 3;
}
function resumeGame() {
print("Resumed");
state = 1;
}
function gameStep() { function gameStep() {
if (state != 1) if (state != 1)
return; return;
if (Date.now()-time > dropInterval) { // drop one step if (Date.now()-time > dropInterval) { // drop one step
time = Date.now(); 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); drawTile(ct, ctn, ox+px*8, oy+py*8, true);
py++; py++;
} }
@ -181,16 +251,18 @@ function rotate() {
} }
function move(x, y) { 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); drawTile(ct, ctn, ox+px*8, oy+py*8, true);
px += x; px += x;
py += y; py += y;
drawTile(ct, ctn, ox+px*8, oy+py*8, false); drawTile(ct, ctn, ox+px*8, oy+py*8, false);
} }
return r;
} }
function linear(x) { function linear(x) {
print("Linear: ", x); //print("Linear: ", x);
let now = px / 10; let now = px / 10;
if (x < now-0.06) if (x < now-0.06)
move(-1, 0); move(-1, 0);
@ -200,36 +272,16 @@ function linear(x) {
function newGame() { function newGame() {
E.showMenu(); E.showMenu();
Bangle.setUI({mode : "custom", btn: () => load()}); Bangle.setUI();
if (control == 4) { // Swipe if (control == 2) {
Bangle.on("touch", (e) => { Bangle.on("accel", (e) => {
t = rotateTile(ct, 3); if (state != 1) return;
if (moveOk(t, 0, 0)) { if (control != 2) return;
drawTile(ct, ctn, ox+px*8, oy+py*8, true); print(e.x);
ct = t; linear((0.2-e.x) * 2.5);
drawTile(ct, ctn, ox+px*8, oy+py*8, false);
}
}); });
}
Bangle.on("swipe", (x,y) => { if (control == 3) {
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
Bangle.setBarometerPower(true); Bangle.setBarometerPower(true);
Bangle.on("pressure", (e) => { Bangle.on("pressure", (e) => {
if (state != 1) return; if (state != 1) return;
@ -238,86 +290,83 @@ function newGame() {
if (alt_start == -9999) if (alt_start == -9999)
alt_start = a; alt_start = a;
a = a - alt_start; a = a - alt_start;
print(e.altitude, a); //print(e.altitude, a);
linear(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(); initGame();
drawGame(); drawGame();
state = 1; state = 1;
var step = 450 - 50*level; calculateSpeed();
if (control == 3) var gi = setInterval(gameStep, 20);
step = step*2;
dropInterval = step;
var gi = setInterval(gameStep, 50);
} }
function drawGame() { function drawGame() {
drawBoundingBox(); drawBoundingBox();
g.setColor(1, 1, 1).setFontAlign(0, 1, 0) 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); .drawString("Next", 176-22, 30);
showNext(ntn, ntr); showNext(ntn, ntr);
g.setColor(0).fillRect(5, 30, 41, 80) redrawStats();
.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);
} }
function selectGame() { function selectGame() {
state = 0; state = 0;
print("Game selection menu"); print("Game selection menu");
//for (let i = 0; i < 100000; i++) ;
var menu = {}; var menu = {};
menu[/*LANG*/"Normal"] = () => { control = 0; newGame(); }; menu["Normal"] = () => { control = 0; newGame(); };
menu[/*LANG*/"Drag"] = () => { control = 1; newGame(); }; menu["Drag"] = () => { control = 1; newGame(); };
menu[/*LANG*/"Tilt"] = () => { control = 2; newGame(); }; menu["Tilt"] = () => { control = 2; newGame(); };
menu[/*LANG*/"Move"] = () => { control = 3; newGame(); }; menu["Pressure"] = () => { control = 3; newGame(); };
menu[/*LANG*/"Swipe"] = () => { control = 4; newGame(); }; level = 1;
menu[/*LANG*/"Level"] = () => { selectLevel(); }; menu["Level"] = {
value : 1,
min : 0,
max : 10,
wrap : true,
onchange : (l) => { level = l; }
};
E.showMenu(menu); E.showMenu(menu);
} }