/* * study20251125_tetris * written by cleemy desu wayo / Licensed under CC0 1.0 * 2025-11-25 * ---- * this is just a study in Processing * * the following preparations are required: * 1. create a new folder (directory) named "study20251125_tetris" * 2. in the new folder, save this Processing sketch as "study20251125_tetris.pde" * 3. in the new folder, save image as "cassidy-james-blaede-UBcXr0DcTAY-unsplash.jpg" * (download from https://unsplash.com/photos/UBcXr0DcTAY ) * 4. install "Game Control Plus" library * (in IDE, Sketch -> Import Library -> Manage Libraries...) * 5. edit the lines marked with "change this line as needed" if necessary * * the author, cleemy desu wayo, has tested this sketch only on Processing 4.4.10 running on Linux. * * ---- * possibly the updated version is here: * * https://gist.github.com/search?q=cleemy+desu+wayo+tetris * * old version is here: * * - study20251026_tetris * https://gist.github.com/cleemy-desu-wayo/ec1d6ce69b4a7e61efdcee71413ef07f * * ---- * how to play * LEFT key: move left * RIGHT key: move right * UP key: ratate R * DOWN key: move down * Z key: ratate R * X key: ratate L * P key: pause * * (and gamepads are also available) * * ---- * see also (technical matters around gamepad) * https://note.com/ozora_electric/n/n17c0bafae69e * https://note.com/ozora_electric/n/n82481de7e00e * https://zawaworks.hatenablog.com/entry/2020/12/04/210613 * https://qiita.com/hextomino/items/8f6e0a08b15148a5d718 * */ import org.gamecontrolplus.*; Boolean isGamePadEnabled = true; // change this line as needed // (if you are seeing gamepad-related errors // and don't need a gamepads, set this to false) int padNum = 0; // change this line as needed String hatName = ""; // change this line as needed String sliderXName = "x"; // change this line as needed String sliderYName = "y"; // change this line as needed int btnANum = 1; // change this line as needed int btnBNum = 2; // change this line as needed int btnSNum = 9; // change this line as needed char KeyPChar = 'p'; // change this line as needed char KeyZChar = 'z'; // change this line as needed char KeyXChar = 'x'; // change this line as needed String fontName = "Noto Sans Mono"; // change this line as needed int debugBarricadeMode = 0; // change this line as needed // (for debug, 0: normal (no barricade) 1-: barricade is enable) // change these values if you adjust the difficulty int initialLevel = 1; float levelInterval = 3000.0; int[] addScore = {100, 300, 800, 2000}; float[] speedByLevel = {0.0 , // level 0 (ignored) 2000.0 , 1500.0 , 1100.0 , 950.0 , 700.0 , // level 1-5 600.0 , 500.0 , 400.0 , 320.0 , 240.0 , // level 6-10 170.0 , 100.0 , 60.0 , 20.0 , 0.0 // level 10-15 }; PGraphics pg; int gameMode = 102; // 0: title (not implemented) // 101: normal 102: fixing & stand by 103: deleting (line clear) // 104: pause // 200: game over int lastGameMode; int drawCnt = 0; int lastRedraw = -1; int screenWidth = 1280; int screenHeight = 720; int leftMargin = 360; int topMargin = 118; int blockSize = 20; int blockMargin = 3; int minoRotate; int minoX; // X position int minoY; // Y position float downInterval = 0.0; // millisec float asobiInterval = 500.0; // millisec float lastAsobiResetTime = -1.0; // millisec (result of millis()) float standbyInterval = 300.0; // millisec float lastStandbyStartTime = -1.0; // millisec (result of millis()) float lastDeleteStartTime = -1.0; // millisec (result of millis()) float gameOverStartTime = -1.0; // millisec (result of millis()) int lastMinoRotate = -1; int lastMinoX = -1; int lastMinoY = -1; Boolean newMinoDrawDone = true; int matrixSizeX = 14; int matrixSizeY = 22; int[][] blockMatrix = new int[matrixSizeX][matrixSizeY]; int[][] fixingBlock = new int[matrixSizeX][matrixSizeY]; int mino; int nextMino; int[][][][] minoBlock = { // 0: T {{{0, 0}, {-1, 0}, {0, -1}, {1, 0}}, {{0, 0}, {0, -1}, {1, 0}, {0, 1}}, {{0, 0}, {-1, 0}, {0, 1}, {1, 0}}, {{0, 0}, {-1, 0}, {0, -1}, {0, 1}}}, // 1: I {{{0, 0}, {-1, 0}, {1, 0}, {2, 0}}, {{0, 0}, {0, -1}, {0, 1}, {0, 2}}, {{0, 0}, {-1, 0}, {1, 0}, {2, 0}}, {{0, 0}, {0, -1}, {0, 1}, {0, 2}}}, // 2: O {{{0, 0}, {1, 0}, {0, -1}, {1, -1}}, {{0, 0}, {1, 0}, {0, -1}, {1, -1}}, {{0, 0}, {1, 0}, {0, -1}, {1, -1}}, {{0, 0}, {1, 0}, {0, -1}, {1, -1}}}, // 3: S {{{0, 0}, {-1, 0}, {0, -1}, {1, -1}}, {{0, 0}, {0, -1}, {1, 0}, {1, 1}}, {{0, 0}, {-1, 0}, {0, -1}, {1, -1}}, {{0, 0}, {0, -1}, {1, 0}, {1, 1}}}, // 4: Z {{{0, 0}, {-1, -1}, {0, -1}, {1, 0}}, {{0, 0}, {1, -1}, {1, 0}, {0, 1}}, {{0, 0}, {-1, -1}, {0, -1}, {1, 0}}, {{0, 0}, {1, -1}, {1, 0}, {0, 1}}}, // 5: J {{{0, 0}, {-1, -1}, {-1, 0}, {1, 0}}, {{0, 0}, {1, -1}, {0, -1}, {0, 1}}, {{0, 0}, {-1, 0}, {1, 0}, {1, 1}}, {{0, 0}, {0, -1}, {0, 1}, {-1, 1}}}, // 6: L {{{0, 0}, {-1, 0}, {1, 0}, {1, -1}}, {{0, 0}, {0, -1}, {0, 1}, {1, 1}}, {{0, 0}, {-1, 1}, {-1, 0}, {1, 0}}, {{0, 0}, {-1, -1}, {0, -1}, {0, 1}}} }; int deletingLineNum = 0; int[] deletingLines = {-1, -1, -1, -1}; Boolean deleteDone = false; int intentFixingCnt = 0; Boolean pauseTextDrawDone = false; ControlDevice pad; ControlHat hat; ControlSlider sliderX, sliderY; ControlButton btnA, btnB, btnS; Boolean isHatFound = false; Boolean isSliderXFound = false; Boolean isSliderYFound = false; Boolean isBtnAFound = false; Boolean isBtnBFound = false; Boolean isBtnSFound = false; Boolean isKeyLeftPressed = false; Boolean isKeyLeftJustReleased = true; Boolean isPadLeftJustReleased = false; Boolean isKeyRightPressed = false; Boolean isKeyRightJustReleased = true; Boolean isPadRightJustReleased = false; Boolean isKeyUpPressed = false; Boolean isKeyDownPressed = false; Boolean isKeyUpJustReleased = true; Boolean isPadUpJustReleased = false; Boolean isKeyPPressed = false; Boolean isKeyPJustReleased = true; Boolean isKeyZPressed = false; Boolean isKeyZJustReleased = true; Boolean isKeyXPressed = false; Boolean isKeyXJustReleased = true; float moveLeftStartTime = -1.0; // millisec (result of millis()) float moveRightStartTime = -1.0; // millisec (result of millis()) float moveLeftRightHoldCharge = 160.0; // millisec float lastMoveDownTime = -1.0; // millisec (result of millis()) float lastMoveLeftRightTime = -1.0; // millisec (result of millis()) Boolean isMoveDownEnabled = true; Boolean isBtnAJustReleased = true; Boolean isBtnBJustReleased = true; Boolean isBtnSJustReleased = true; int level = initialLevel; int score = 0; int highScore = 0; void setup() { if (isGamePadEnabled) { setupGamePad(); } size(1280, 720); noStroke(); PImage bg = loadImage("cassidy-james-blaede-UBcXr0DcTAY-unsplash.jpg"); pg = createGraphics(1280, 720); pg.beginDraw(); pg.image(bg, 0, 0, 1280, 720); pg.endDraw(); frameRate(60); gameReset(); } void setupGamePad () { ControlIO control; int foundGamePadNum = 0; int btnNum = 0; String tmpHatName = ""; control = ControlIO.getInstance(this); foundGamePadNum = control.getNumberOfDevices(); if (foundGamePadNum == 0) { println("[gamepad info] number of gamepad: " + foundGamePadNum + " (not found)"); isGamePadEnabled = false; return; } else { println("[gamepad info] number of gamepad: " + foundGamePadNum); } println("[gamepad info] found gamepad: " + control.getDevices()); pad = control.getDevice(padNum); println("[gamepad info] pad: " + pad.getName()); btnNum = pad.getNumberOfButtons(); println("[gamepad info] number of button: " + btnNum); int i = 0; for (ControlInput input : pad.getInputs()) { if (input instanceof ControlHat) { if (tmpHatName == "") { tmpHatName = input.getName(); } println("[gamepad info] inputs-" + i + " -- hat : " + tmpHatName); } else if (input instanceof ControlSlider) { println("[gamepad info] inputs-" + i + " -- slider : " + input.getName()); } else if (input instanceof ControlButton) { println("[gamepad info] inputs-" + i + " -- button : " + input.getName()); } i++; } if (hatName == "") { hat = pad.getHat(tmpHatName); } else { hat = pad.getHat(hatName); } if (hat instanceof ControlHat) { isHatFound = true; println("[gamepad info] hat : " + hat.getName() + " -- " + hat); } else { println("[gamepad info] hat : (not found)"); } sliderX = pad.getSlider(sliderXName); if (sliderX instanceof ControlSlider) { isSliderXFound = true; println("[gamepad info] sliderX : " + sliderX.getName() + " -- " + sliderX); } else { println("[gamepad info] sliderX : (not found)"); } sliderY = pad.getSlider(sliderYName); if (sliderY instanceof ControlSlider) { isSliderYFound = true; println("[gamepad info] sliderY : " + sliderY.getName() + " -- " + sliderY); } else { println("[gamepad info] sliderY : (not found)"); } if (btnANum < btnNum) { btnA = pad.getButton(btnANum); } if (btnA instanceof ControlButton) { isBtnAFound = true; println("[gamepad info] btnA : " + btnA.getName() + " -- " + btnA); } else { println("[gamepad info] btnA : (not found)"); } if (btnBNum < btnNum) { btnB = pad.getButton(btnBNum); } if (btnB instanceof ControlButton) { isBtnBFound = true; println("[gamepad info] btnB : " + btnB.getName() + " -- " + btnB); } else { println("[gamepad info] btnB : (not found)"); } if (btnSNum < btnNum) { btnS = pad.getButton(btnSNum); } if (btnS instanceof ControlButton) { isBtnSFound = true; println("[gamepad info] btnS : " + btnS.getName() + " -- " + btnS); } else { println("[gamepad info] btnS : (not found)"); } } void draw() { Boolean isBlackout = false; drawCnt++; if (drawCnt % 100000 == 0) { println("[" + getTimeString() + "] drawCnt: " + drawCnt); } if (drawCnt % 60 == 0) { //println("level: " + level + " -- downInterval: " + downInterval); // for debug // sliderX and sliderY info (for debug) if (isSliderXFound && isSliderYFound) { if (abs(sliderX.getValue()) > 0.1 || abs(sliderY.getValue()) > 0.1) { //println("sliderX:" + sliderX.getValue() + " ---- sliderY: " + sliderY.getValue()); } } } // pause if (isBtnSFound && !btnS.pressed() && !isBtnSJustReleased) { isBtnSJustReleased = true; } if (!isKeyPPressed && !isKeyPJustReleased) { isKeyPJustReleased = true; } if ((isBtnSFound && btnS.pressed() && isBtnSJustReleased) || (isKeyPPressed && isKeyPJustReleased)) { if (gameMode >= 101 && gameMode <= 103) { lastGameMode = gameMode; gameMode = 104; pauseTextDrawDone = false; } else if (gameMode == 104) { gameMode = lastGameMode; } isBtnSJustReleased = false; isKeyPJustReleased = false; } // title or something if (gameMode < 100) { // fixing & stand by } else if (gameMode == 102) { if (millis() > lastStandbyStartTime + standbyInterval) { gameMode = 101; newMinoDrawDone = false; //clearCurrentMino(); // game over if (checkBlock(mino, minoX, minoY, minoRotate) == 0) { startGameOver(); } putCurrentMino(); } // deleting } else if (gameMode == 103) { float deleteTime = 0.0; float fixingTime = 300.0; if (deletingLineNum == 1) { deleteTime = 140.0; fixingTime = 190.0; if (!deleteDone) { if (millis() <= lastDeleteStartTime + 95) { int deleteBlockNum = floor(10.0 / 95 * (millis() - lastDeleteStartTime)); if (deleteBlockNum > 10) { deleteBlockNum = 10; } for (int i = 2; i <= 1 + deleteBlockNum; i++) { blockMatrix[i][deletingLines[0]] = 0; } } else { blockMatrix[11][deletingLines[0]] = 0; } } } else if (deletingLineNum == 2) { deleteTime = 270.0; fixingTime = 340.0; if (!deleteDone) { if (millis() <= lastDeleteStartTime + 230) { int deleteBlockNum = floor(10.0 / 230 * (millis() - lastDeleteStartTime)); if (deleteBlockNum > 10) { deleteBlockNum = 10; } for (int i = 2; i <= 1 + deleteBlockNum; i++) { blockMatrix[i][deletingLines[0]] = 0; blockMatrix[13 -i][deletingLines[1]] = 0; } } else { blockMatrix[11][deletingLines[0]] = 0; blockMatrix[2][deletingLines[1]] = 0; } } } else if (deletingLineNum == 3) { deleteTime = 950.0; fixingTime = 1300.0; } else if (deletingLineNum == 4) { deleteTime = 1900.0; fixingTime = 2650.0; } if (!deleteDone) { if (millis() > lastDeleteStartTime + deleteTime) { for(int i = 0; i < 4; i++) { deleteLine(deletingLines[i]); } deleteDone = true; score += addScore[deletingLineNum - 1]; } } if (millis() > lastDeleteStartTime + fixingTime) { gameMode = 101; putCurrentMino(); newMinoDrawDone = false; deletingLineNum = 0; deleteDone = false; } // pause } else if (gameMode == 104) { if (!pauseTextDrawDone) { fill(255, 255, 255, 223); rect(280, 200, 480, 300); textFont(createFont(fontName, 50, true)); textAlign(CENTER, CENTER); fill(63, 63, 63, 127); text("P A U S E", 280, 200, 480, 300); pauseTextDrawDone = true; } return; // normal game mode } else if (gameMode == 101) { Boolean isSliderXLeft = false; Boolean isSliderXRight = false; Boolean isSliderYUp = false; Boolean isSliderYDown = false; if (isSliderXFound) { if (sliderX.getValue() < -0.6) { isSliderXLeft = true; } else if (sliderX.getValue() > 0.6) { isSliderXRight = true; } } if (isSliderYFound) { if (sliderY.getValue() < -0.9) { isSliderYUp = true; } else if (sliderY.getValue() > 0.6) { isSliderYDown = true; } } // move down (by intention) if (millis() > lastMoveLeftRightTime + 150) { if (((isHatFound && !hat.down()) || !isHatFound) && !isSliderYDown && !isKeyDownPressed) { isMoveDownEnabled = true; intentFixingCnt = 0; } if (isMoveDownEnabled) { if ((isHatFound && hat.down()) || isSliderYDown || isKeyDownPressed) { moveMinoDown(); } } } // move left if (millis() > lastMoveDownTime + 90) { if (((isHatFound && !hat.left()) || !isHatFound) && !isSliderXLeft && !isPadLeftJustReleased) { isPadLeftJustReleased = true; } if (isKeyLeftPressed && (isKeyLeftJustReleased || (millis() - moveLeftStartTime > moveLeftRightHoldCharge))) { if (isKeyLeftJustReleased) { moveLeftStartTime = millis(); isKeyLeftJustReleased = false; } moveMinoLeft(); } if (((isHatFound && hat.left()) || isSliderXLeft) && (isPadLeftJustReleased || (millis() - moveLeftStartTime > moveLeftRightHoldCharge))) { if (isPadLeftJustReleased) { moveLeftStartTime = millis(); isPadLeftJustReleased = false; } moveMinoLeft(); } } // move right if (millis() > lastMoveDownTime + 90) { if (((isHatFound && !hat.right()) || !isHatFound) && !isSliderXRight && !isPadRightJustReleased) { isPadRightJustReleased = true; } if (isKeyRightPressed && (isKeyRightJustReleased || (millis() - moveRightStartTime > moveLeftRightHoldCharge))) { if (isKeyRightJustReleased) { moveRightStartTime = millis(); isKeyRightJustReleased = false; } moveMinoRight(); } if (((isHatFound && hat.right()) || isSliderXRight) && (isPadRightJustReleased || (millis() - moveRightStartTime > moveLeftRightHoldCharge))) { if (isPadRightJustReleased) { moveRightStartTime = millis(); isPadRightJustReleased = false; } moveMinoRight(); } } // rotate if (((isHatFound && !hat.up()) || !isHatFound) && !isSliderYUp && !isPadUpJustReleased) { isPadUpJustReleased = true; } if (isKeyUpPressed && isKeyUpJustReleased) { rotateMino(0); isKeyUpJustReleased = false; } if (((isHatFound && hat.up()) || isSliderYUp) && isPadUpJustReleased) { rotateMino(0); isPadUpJustReleased = false; } // rotate (by button A) if (isBtnAFound) { if (!btnA.pressed() && !isBtnAJustReleased) { isBtnAJustReleased = true; } if (btnA.pressed() && isBtnAJustReleased) { rotateMino(0); isBtnAJustReleased = false; } } // rotate (by button B) if (isBtnBFound) { if (!btnB.pressed() && !isBtnBJustReleased) { isBtnBJustReleased = true; } if (btnB.pressed() && isBtnBJustReleased) { rotateMino(1); isBtnBJustReleased = false; } } // rotate (by Z key) if (isKeyZPressed && isKeyZJustReleased) { rotateMino(0); isKeyZJustReleased = false; } // rotate (by X key) if (isKeyXPressed && isKeyXJustReleased) { rotateMino(1); isKeyXJustReleased = false; } // move down naturally and set next mino if (isMoveDownEnabled && ((isHatFound && hat.down()) || isSliderYDown || isKeyDownPressed)) { clearCurrentMino(); if (checkBlock(mino, minoX, minoY + 1, minoRotate) == 0) { intentFixingCnt++; if (intentFixingCnt > 6) { setNextMino(); } else { putCurrentMino(); } } else { putCurrentMino(); } } else if (millis() > lastAsobiResetTime + downInterval) { clearCurrentMino(); // move down naturally if (checkBlock(mino, minoX, minoY + 1, minoRotate) == 1) { minoY++; putCurrentMino(); lastAsobiResetTime = millis(); } else if (millis() > lastAsobiResetTime + asobiInterval) { setNextMino(); } else { putCurrentMino(); } } // game over } else if (gameMode == 200) { int floodState = 0; if (millis() < gameOverStartTime + 2000) { } else if (millis() < gameOverStartTime + 3900) { floodState = floor((millis() - 2000 - gameOverStartTime) / 40); if (floodState < 0 ) { floodState = 0; } else if (floodState > 41) { floodState = 41; } if (floodState <= 20) { for (int i = 2; i < matrixSizeX - 2; i++) { blockMatrix[i][20 - floodState] = 1; } } else { for (int i = 2; i < matrixSizeX - 2; i++) { blockMatrix[i][floodState - 21] = 0; } } } else if (millis() > gameOverStartTime + 5100) { gameReset(); gameMode = 101; } } // draw if ((gameMode == 101 && (!newMinoDrawDone || lastMinoRotate != minoRotate || lastMinoX != minoX || lastMinoY != minoY)) || gameMode == 102 || gameMode == 103 || gameMode == 200) { float tmpTime = millis() - lastDeleteStartTime; float tmpAlpha = 0.0; // draw bg if (gameMode == 103) { if (deletingLineNum == 3) { if (tmpTime < 310) { if (drawCnt % 6 < 3) { image(pg, 0, 0); } else { background(0); } } else { image(pg, 0, 0); } } else if (deletingLineNum == 4) { if (tmpTime < 512) { tmpAlpha = tmpTime / 2.0; if (tmpAlpha > 255.0) { tmpAlpha = 255.0; } image(pg, 0, 0); fill(0, 0, 0, tmpAlpha); rect(0, 0, screenWidth, screenHeight); } else if (tmpTime < 1100) { isBlackout = true; if (drawCnt % 6 < 3) { background(255); } else { background(0); } } else if (tmpTime < 2500 ) { background(0); } else if (tmpTime < 2627 ) { tmpAlpha = 255 - (tmpTime - 2500) * 2; if (tmpAlpha < 0.0) { tmpAlpha = 0.0; } image(pg, 0, 0); fill(0, 0, 0, tmpAlpha); rect(0, 0, screenWidth, screenHeight); } else { image(pg, 0, 0); } } else { image(pg, 0, 0); } } else if (gameMode == 200) { if (millis() < gameOverStartTime + 2000) { tmpAlpha = 127.0 / 2000 * (millis() - gameOverStartTime); if (tmpAlpha > 127.0) { tmpAlpha = 127.0; } } else if (millis() > gameOverStartTime + 4500) { tmpAlpha = 127.0 - 127.0 / 300 * (millis() - 4500 - gameOverStartTime); if (tmpAlpha < 0.0) { tmpAlpha = 0.0; } } else { tmpAlpha = 127.0; } image(pg, 0, 0); fill(0, 0, 0, tmpAlpha); rect(0, 0, screenWidth, screenHeight); } else { image(pg, 0, 0); } // draw all blocks of main area if (!isBlackout) { fill(0, 0, 0, 127); rect(320, 70, 400, 600); } fill(255, 255, 255, 255); for (int i = 0; i < matrixSizeX; i++) { for (int j = 0; j < matrixSizeY; j++) { if (blockMatrix[i][j] == 1) { if (!(gameMode == 103 && !deleteDone && ((deletingLineNum == 4 && tmpTime > 1090) || (deletingLineNum == 3 && tmpTime > 390)) && i > 1 && i < matrixSizeX - 2 && (deletingLines[0] == j || deletingLines[1] == j || deletingLines[2] == j || deletingLines[3] == j))) { square(leftMargin + (blockSize + blockMargin) * i, topMargin + (blockSize + blockMargin) * j, blockSize); } } } } newMinoDrawDone = true; // draw next mino int nextMinoMarginX = 875; int nextMinoMarginY = 168; if (nextMino == 1) { nextMinoMarginX -= 12; nextMinoMarginY -= 10; } else if (nextMino == 2) { nextMinoMarginX -= 12; } if (!isBlackout) { fill(0, 0, 0, 127); rect(805, 90, 160, 160); } if (gameMode == 101 || (gameMode == 102 && millis() > lastStandbyStartTime + standbyInterval - 100)) { fill(255, 255, 255, 255); for (int i = 0; i < 4; i++) { square(nextMinoMarginX + (blockSize + blockMargin) * minoBlock[nextMino][0][i][0], nextMinoMarginY + (blockSize + blockMargin) * minoBlock[nextMino][0][i][1], blockSize); } } // draw score levelReset(); if (!isBlackout) { fill(0, 0, 0, 127); rect(790, 330, 190, 292); } if (!(gameMode == 103 && deletingLineNum == 4 && tmpTime >= 512)) { fill(255, 255, 255, 191); if (gameMode == 103 && deletingLineNum == 4 && tmpTime < 512) { fill(255, 255, 255, (191.0 / 512 * (512 - tmpTime))); } textFont(createFont(fontName, 17, true)); textAlign(LEFT, CENTER); text("LEVEL", 820, 365, 165, 45); textAlign(RIGHT, CENTER); text(str(level), 785, 392, 165, 45); textAlign(LEFT, CENTER); text("SCORE", 820, 440, 165, 45); textAlign(RIGHT, CENTER); text(str(score), 785, 467, 165, 45); textAlign(LEFT, CENTER); text("HIGH SCORE", 820, 515, 165, 45); if (score > highScore) { highScore = score; } textAlign(RIGHT, CENTER); text(str(highScore), 785, 542, 165, 45); } lastMinoRotate = minoRotate; lastMinoY = minoY; lastMinoX = minoX; lastRedraw = drawCnt; } if (gameMode == 102) { drawEffectFixingBlock(); } } void gameReset() { mino = int(random(7)); nextMino = int(random(7)); minoX = 6; minoY = 1; minoRotate = 0; score = 0; levelReset(); println("[" + getTimeString() + "] game reset"); for (int i = 0; i < matrixSizeX; i++) { for (int j = 0; j < matrixSizeY; j++) { if (j == matrixSizeY - 1) { if (i >= 1 && i < matrixSizeX - 1) { blockMatrix[i][j] = 1; } else { blockMatrix[i][j] = 0; } } else { if (i == 1 || i == matrixSizeX - 2) { blockMatrix[i][j] = 1; } else { blockMatrix[i][j] = 0; } } } } if (debugBarricadeMode != 0) { putBarricade(); } } void levelReset() { level = floor(score / levelInterval) + initialLevel; if (level > speedByLevel.length -1) { level = speedByLevel.length -1; } downInterval = speedByLevel[level]; } void clearCurrentMino() { int x, y; for (int i = 0; i < 4; i++) { x = minoX + minoBlock[mino][minoRotate][i][0]; y = minoY + minoBlock[mino][minoRotate][i][1]; blockMatrix[x][y] = 0; } } void putCurrentMino() { int x, y; for (int i = 0; i < 4; i++) { x = minoX + minoBlock[mino][minoRotate][i][0]; y = minoY + minoBlock[mino][minoRotate][i][1]; blockMatrix[x][y] = 1; } } void setNextMino() { putCurrentMino(); setFixingBlock(); gameMode = 102; // check aligned lines checkAlignedLines(); // next mino mino = nextMino; nextMino = int(random(7)); minoX = 6; minoY = 1; minoRotate = 0; isMoveDownEnabled = false; intentFixingCnt = 0; if (mino == 1) { minoY = 0; } lastAsobiResetTime = millis(); lastStandbyStartTime = millis(); newMinoDrawDone = false; } // return value: 0 -> ng 1 -> ok int checkBlock(int mino, int pos, int step, int rotate) { int result = 1; int x, y; for (int i = 0; i < 4; i++) { x = pos + minoBlock[mino][rotate][i][0]; y = step + minoBlock[mino][rotate][i][1]; if (x >= 0 && x < matrixSizeX && y >= 0 && y < matrixSizeY) { if (blockMatrix[x][y] == 1) { result = 0; } } else { result = 0; } } return result; } void checkAlignedLines() { Boolean isAlignedLine; deletingLineNum = 0; for (int i = 0; i < 4; i++) { deletingLines[i] = -1; } for (int i = 0; i < matrixSizeY - 1; i++) { isAlignedLine = true; for (int j = 2; j <= matrixSizeX - 2; j++) { if (blockMatrix[j][i] == 0) { isAlignedLine = false; } } if (isAlignedLine) { deletingLines[deletingLineNum] = i; gameMode = 103; deletingLineNum++; } } if (deletingLineNum > 0) { // for debug //println("deletingLines: " + // deletingLines[0] + ", " + deletingLines[1] + ", " + // deletingLines[2] + ", " + deletingLines[3]); lastDeleteStartTime = millis(); } } void deleteLine(int line) { for (int i = 2; i < matrixSizeX - 2; i++) { for (int j = line; j >= 1; j--) { blockMatrix[i][j] = blockMatrix[i][j - 1]; } blockMatrix[i][0] = 0; } } void setFixingBlock() { int x, y; for (int i = 0; i < matrixSizeX; i++) { for (int j = 0; j < matrixSizeY; j++) { fixingBlock[i][j] = 0; } } for (int i = 0; i < 4; i++) { x = minoX + minoBlock[mino][minoRotate][i][0]; y = minoY + minoBlock[mino][minoRotate][i][1]; fixingBlock[x][y] = 1; } } void drawEffectFixingBlock() { for (int i = 0; i < matrixSizeX; i++) { for (int j = 0; j < matrixSizeY; j++) { if (fixingBlock[i][j] == 1) { if (millis() < lastStandbyStartTime + 240) { if (drawCnt % 6 < 3) { fill(91, 63, 63); } else { fill(255, 255, 255); } } if (millis() < lastStandbyStartTime + 255) { fill(63 + 192 / 255.0 * (millis() - lastStandbyStartTime), 79 + 176 / 255.0 * (millis() - lastStandbyStartTime), 127 + 127 / 255.0 * (millis() - lastStandbyStartTime)); } square(leftMargin + (blockSize + blockMargin) * i, topMargin + (blockSize + blockMargin) * j, blockSize); } } } } void startGameOver() { gameOverStartTime = millis(); gameMode = 200; } void keyPressed() { if (keyCode == LEFT) { isKeyLeftPressed = true; } else if (keyCode == RIGHT) { isKeyRightPressed = true; } else if (keyCode == DOWN) { isKeyDownPressed = true; } else if (keyCode == UP) { isKeyUpPressed = true; } else if (key == KeyPChar) { isKeyPPressed = true;; } else if (key == KeyZChar) { isKeyZPressed = true; } else if (key == KeyXChar) { isKeyXPressed = true; } } void keyReleased() { if (keyCode == LEFT) { isKeyLeftPressed = false; isKeyLeftJustReleased = true; } else if (keyCode == RIGHT) { isKeyRightPressed = false; isKeyRightJustReleased = true; } else if (keyCode == DOWN) { isKeyDownPressed = false; } else if (keyCode == UP) { isKeyUpPressed = false; isKeyUpJustReleased = true; } else if (key == KeyPChar) { isKeyPPressed = false; isKeyPJustReleased = true; } else if (key == KeyZChar) { isKeyZPressed = false; isKeyZJustReleased = true; } else if (key == KeyXChar) { isKeyXPressed = false; isKeyXJustReleased = true; } } // move left void moveMinoLeft() { clearCurrentMino(); if (checkBlock(mino, minoX - 1, minoY, minoRotate) == 1) { minoX--; lastAsobiResetTime = millis(); } putCurrentMino(); lastMoveLeftRightTime = millis(); } // move right void moveMinoRight() { clearCurrentMino(); if (checkBlock(mino, minoX + 1, minoY, minoRotate) == 1) { minoX++; lastAsobiResetTime = millis(); } putCurrentMino(); lastMoveLeftRightTime = millis(); } // move down (by intention) void moveMinoDown() { clearCurrentMino(); if (checkBlock(mino, minoX, minoY + 1, minoRotate) == 1) { minoY++; score += 1; lastAsobiResetTime = millis(); } putCurrentMino(); lastMoveDownTime = millis(); } // rotate mino // mode == 0 -> rotate R // mode == 1 -> rotate L void rotateMino(int mode) { int rotateCandidate = 0; int[][] candidate = {{-1, minoX, minoY}, {-1, minoX - 1, minoY}, {-1, minoX + 1, minoY}, {1, minoX - 2, minoY}, {1, minoX + 2, minoY}, {-1, minoX, minoY - 1}, {-1, minoX - 1, minoY - 1}, {-1, minoX + 1, minoY - 1}, {1, minoX - 2, minoY - 1}, {1, minoX + 2, minoY - 1}, {1, minoX, minoY + 1}}; Boolean isSliderXRight = false; Boolean isSliderXLeft = false; if (isSliderXFound) { if (sliderX.getValue() > 0.6) { isSliderXRight = true; } else if (sliderX.getValue() < -0.6) { isSliderXLeft = true; } } // if the left is pressed, the left takes priority if ((isHatFound && hat.left()) || isSliderXLeft || isKeyLeftPressed) { if (mino == 1) { candidate[0][1] = minoX - 1; candidate[1][1] = minoX - 2; candidate[2][1] = minoX; candidate[3][1] = minoX + 1; candidate[4][1] = minoX + 1; candidate[5][1] = minoX - 1; candidate[6][1] = minoX - 2; candidate[7][1] = minoX; candidate[8][1] = minoX + 1; candidate[9][1] = minoX + 1; } // if the right is pressed, the right takes priority } else if ((isHatFound && hat.right()) || isSliderXRight || isKeyRightPressed) { candidate[1][1] = minoX + 1; candidate[2][1] = minoX - 1; candidate[3][1] = minoX + 2; candidate[4][1] = minoX - 2; candidate[6][1] = minoX + 1; candidate[7][1] = minoX - 1; candidate[8][1] = minoX + 2; candidate[9][1] = minoX - 2; if (mino == 1) { candidate[0][1] = minoX + 1; candidate[1][1] = minoX + 2; candidate[2][1] = minoX; candidate[3][1] = minoX - 1; candidate[4][1] = minoX - 1; candidate[5][1] = minoX + 1; candidate[6][1] = minoX + 2; candidate[7][1] = minoX; candidate[8][1] = minoX - 1; candidate[9][1] = minoX - 1; } } clearCurrentMino(); if (mode == 0) { rotateCandidate = minoRotate + 1; } else if (mode == 1) { rotateCandidate = minoRotate - 1; } if (rotateCandidate > 3) { rotateCandidate = 0; } if (rotateCandidate < 0) { rotateCandidate = 3; } //println(" -- candidate check start --"); // for debug for (int i = 0; i < candidate.length; i++) { if (candidate[i][0] == -1 || candidate[i][0] == mino) { // for debug //println("candidate[" + i + "] -- minoX: " + candidate[i][1] + " minoY: " +candidate[i][2]); if (checkBlock(mino, candidate[i][1], candidate[i][2], rotateCandidate) == 1) { minoRotate = rotateCandidate; minoX = candidate[i][1]; minoY = candidate[i][2]; lastAsobiResetTime = millis(); break; } } } putCurrentMino(); } String getTimeString() { String result = ""; result += nf(hour(), 2) + ":"; result += nf(minute(), 2) + ":"; result += nf(second(), 2); return result; } // for debug void putBarricade() { // barricade at the top if (debugBarricadeMode == 1) { for (int i = 3; i <= 10; i++) { if (i % 2 == 1) { blockMatrix[i][8] = 1; } else { blockMatrix[i][10] = 1; } } // barricade at the top } else if (debugBarricadeMode == 2) { for (int i = 2; i <= 11; i++) { if (i != 7) { blockMatrix[i][11] = 1; } } blockMatrix[2][8] = 1; blockMatrix[3][8] = 1; blockMatrix[10][8] = 1; blockMatrix[11][8] = 1; // tetris or triple chance } else if (debugBarricadeMode == 101) { for (int i = 2; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[10][17] = 0; // tetris chance (tense situation) } else if (debugBarricadeMode == 102) { for (int i = 2; i <= 10; i++) { for (int j = 4; j <= 20; j++) { blockMatrix[i][j] = 1; } } // tetris chance (tense situation) } else if (debugBarricadeMode == 103) { for (int i = 3; i <= 11; i++) { for (int j = 4; j <= 20; j++) { blockMatrix[i][j] = 1; } } // split triple chance } else if (debugBarricadeMode == 201) { for (int i = 2; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[5][18] = 0; // split triple chance } else if (debugBarricadeMode == 202) { for (int i = 2; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[10][18] = 0; // split double chance } else if (debugBarricadeMode == 301) { for (int i = 2; i <= 10; i++) { blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[10][19] = 0; // spin chance (T) } else if (debugBarricadeMode == 401 || debugBarricadeMode == 402) { for (int i = 2; i <= 11; i++) { blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } if (debugBarricadeMode == 401) { blockMatrix[6][18] = 0; } else { blockMatrix[8][18] = 0; } blockMatrix[7][18] = 0; blockMatrix[6][19] = 0; blockMatrix[7][19] = 0; blockMatrix[8][19] = 0; blockMatrix[2][20] = 0; // spin chance (T) } else if (debugBarricadeMode == 403 || debugBarricadeMode == 404) { for (int i = 2; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } if (debugBarricadeMode == 403) { blockMatrix[5][17] = 0; } else { blockMatrix[7][17] = 0; } blockMatrix[6][17] = 0; blockMatrix[5][18] = 0; blockMatrix[6][18] = 0; blockMatrix[7][18] = 0; blockMatrix[6][19] = 0; // spin chance (T) } else if (debugBarricadeMode == 405) { for (int i = 2; i <= 11; i++) { blockMatrix[i][16] = 1; blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[8][16] = 0; blockMatrix[9][16] = 0; blockMatrix[6][17] = 0; blockMatrix[7][17] = 0; blockMatrix[8][17] = 0; blockMatrix[9][17] = 0; blockMatrix[6][18] = 0; blockMatrix[7][18] = 0; blockMatrix[8][18] = 0; blockMatrix[6][19] = 0; blockMatrix[7][19] = 0; blockMatrix[7][20] = 0; // spin chance (S or Z) } else if (debugBarricadeMode == 411) { for (int i = 2; i <= 11; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[3][17] = 0; blockMatrix[4][17] = 0; blockMatrix[3][18] = 0; blockMatrix[4][18] = 0; blockMatrix[2][19] = 0; blockMatrix[3][19] = 0; blockMatrix[4][19] = 0; blockMatrix[9][17] = 0; blockMatrix[10][17] = 0; blockMatrix[9][18] = 0; blockMatrix[10][18] = 0; blockMatrix[9][19] = 0; blockMatrix[10][19] = 0; blockMatrix[11][19] = 0; blockMatrix[6][20] = 0; // korogashi test (J or L) } else if (debugBarricadeMode == 501) { for (int i = 3; i <= 10; i++) { blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[3][17] = 1; blockMatrix[10][17] = 1; // flexible rotation test (I) } else if (debugBarricadeMode == 601) { for (int i = 3; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[2][10] = 1; blockMatrix[3][10] = 1; blockMatrix[10][10] = 1; blockMatrix[11][10] = 1; blockMatrix[3][15] = 1; blockMatrix[3][16] = 1; blockMatrix[4][16] = 1; blockMatrix[5][16] = 1; blockMatrix[7][17] = 0; blockMatrix[8][15] = 1; blockMatrix[8][16] = 1; blockMatrix[9][16] = 1; blockMatrix[10][16] = 1; blockMatrix[7][17] = 0; // flexible rotation test (I or J or L) } else if (debugBarricadeMode >= 602 && debugBarricadeMode <= 603) { for (int i = 3; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[2][10] = 1; blockMatrix[3][10] = 1; blockMatrix[10][10] = 1; blockMatrix[11][10] = 1; blockMatrix[10][16] = 1; blockMatrix[9][17] = 0; blockMatrix[3][16] = 1; blockMatrix[4][17] = 0; if (debugBarricadeMode == 603) { blockMatrix[2][13] = 1; blockMatrix[3][13] = 1; blockMatrix[4][13] = 1; blockMatrix[9][13] = 1; blockMatrix[10][13] = 1; blockMatrix[11][13] = 1; } // flexible rotation test (I or J or L) } else if (debugBarricadeMode >= 611 && debugBarricadeMode <= 613) { for (int i = 3; i <= 10; i++) { blockMatrix[i][17] = 1; blockMatrix[i][18] = 1; blockMatrix[i][19] = 1; blockMatrix[i][20] = 1; } blockMatrix[2][10] = 1; blockMatrix[3][10] = 1; blockMatrix[10][10] = 1; blockMatrix[11][10] = 1; blockMatrix[9][16] = 1; blockMatrix[10][16] = 1; blockMatrix[8][17] = 0; blockMatrix[3][16] = 1; blockMatrix[4][16] = 1; blockMatrix[5][17] = 0; if (debugBarricadeMode == 612) { blockMatrix[6][14] = 1; blockMatrix[6][15] = 1; blockMatrix[7][14] = 1; blockMatrix[7][15] = 1; } else if (debugBarricadeMode == 613) { blockMatrix[3][14] = 1; blockMatrix[4][14] = 1; blockMatrix[9][14] = 1; blockMatrix[10][14] = 1; } } }