Obrázek : https://ctrlv.cz/ulsl
Potřebuješ: rotační enkodér, a nějaké knihovny. Nebo si ten program uprav na tlačítka. Zapojení se dá okoukat z obrázku.
Víceméně jsem si jen hrál, v kódu můžou být chyby, nesmysly, bugy
Kód: Vybrat vše
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <U8glib.h>
U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);
#define bW 4
#define bH 4
#define ROW 23
#define COL 10
#define bOffX 1
#define bOffY 33
#define nextX 4
#define nextY 4
#define bP 3
#define DOWN_SCORE 1+1*lvl
int board[ROW][COL];
boolean isStarted = 0;
//long int lastTick = 0;
unsigned long int gameTime = 0;
unsigned long int score = 0;
unsigned int lines = 0;
int lvl = 0;
int gameSpeed = 1000;
boolean gameOver = 1;
//unsigned int IBlock[4] = {0x4444,0x0F00,0x2222,0x00F0};
unsigned int IBlock[4] = {0x4444,0x0F00,0x4444,0x0F00};
unsigned int JBlock[4] = {0x2260,0x4700,0x3220,0x0710};
unsigned int LBlock[4] = {0x4460,0x0E80,0xC440,0x2E00};
unsigned int OBlock[4] = {0x6600,0x6600,0x6600,0x6600};
unsigned int SBlock[4] = {0x6C00,0x4620,0x06C0,0x8C40};
unsigned int TBlock[4] = {0x0270,0x4640,0x7200,0x1310};
unsigned int ZBlock[4] = {0xC600,0x2640,0x0C60,0x4C80};
unsigned int nextBlock;
unsigned int activeBlock[4];
int nbR;
int nbID;
int abID;
int abX;
int abY;
int abR;
byte mID;
bool mActive;
ClickEncoder *encoder;
int16_t last, value;
void timerIsr() {
encoder->service();
}
void setup(void) {
u8g.setRot90();
encoder = new ClickEncoder(3, 4, 5, 4);
Timer1.initialize(1000);
Timer1.attachInterrupt(timerIsr);
encoder->setAccelerationEnabled(false);
last = 0;
abX = 0;
abY = 0;
abR = 0;
//lastTick = millis();
isStarted = 0;
gameOver = 1;
gameSpeed = 1200;
mID = 0;
mActive = 0;
randomSeed(analogRead(A0));
delay(500);
}
void loop(void) {
//if (millis()-lastTick > 15) {
value += encoder->getValue();
if (value != last) {
if(value > last) {
if(gameOver == 0){
moveRight();
}else{
if(!mActive){
mID = (mID + 1) % 3;
}else{
if(lvl < 9 && mID == 1){lvl++;}
}
}
}else{
if(gameOver == 0){
moveLeft();
}else{
if(!mActive){
if(mID == 0){mID = 2;}else{mID = (mID - 1) % 3;}
}else{
if(lvl > 0 && mID == 1){lvl--;}
}
}
}
last = value;
}
ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
switch (b) {
//VERBOSECASE(ClickEncoder::Pressed);
//VERBOSECASE(ClickEncoder::Held)
//VERBOSECASE(ClickEncoder::Released)
//VERBOSECASE(ClickEncoder::Clicked)
case ClickEncoder::Clicked:
if(gameOver == 0){
moveRotate();
}else{
menuOpen();
//isStarted = 1;
//gameOver = 0;
}
break;
case ClickEncoder::Held:
if(gameOver == 0){
moveDown();
score += DOWN_SCORE;
moveDown();
score += DOWN_SCORE;
}
break;
case ClickEncoder::DoubleClicked:
lvl++;
break;
}
}
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
//lastTick = millis();
//}
if(!gameOver){
if (millis()-gameTime > (gameSpeed-lvl*100)) {
moveDown();
gameTime = millis();
}
}
if(isStarted && gameOver == 0){
//gameOver = 0;
score = 0;
lines = 0;
isStarted = 0;
prepareNext();
createBlock();
}
}
void menuOpen(){
if(mID == 0){
isStarted = 1;
gameOver = 0;
}else{
mActive = !mActive;
}
}
void drawMenu(){
if(!mActive || mID == 1){
u8g.setFont(u8g_font_5x7);
u8g.setPrintPos(4, 42);
u8g.print(F("Start"));
u8g.setPrintPos(4, 52);
u8g.print(F("Level"));
u8g.setPrintPos(4, 62);
u8g.print(F("Score"));
u8g.drawLine(2,42+mID*10,28,42+mID*10);
if(mActive){
u8g.drawLine(2,42-8+mID*10,28,42-8+mID*10);
u8g.drawLine(2,42-7+mID*10,2,42+mID*10);
u8g.drawLine(28,42-7+mID*10,28,42+mID*10);
}
}
}
void drawGUI(void){
u8g.drawFrame(2, 2, 16, 16);
u8g.drawFrame(0, 32, COL*bP+2, ROW*bP+2);
//u8g.drawFrame(0, 0, 32, 100);
u8g.setFont(u8g_font_7x14);//lvl
u8g.setPrintPos(22, 15);
u8g.print(lvl);
drawScore();
}
void drawScore(){
u8g.setFont(u8g_font_5x7);//score
u8g.setPrintPos(1, 28);
u8g.print(score);
}
void drawBlock(int x, int y){
u8g.drawFrame(x ,y , bP, bP);
}
void drawNextBlock(void){
int b = 15;
for(int s=0;s < bW; s++){
for(int r=0;r < bH; r++){
if(!bitRead(nextBlock, b)){ b--;continue;}
drawBlock(r*bP+nextX, s*bP+nextY);
b--;
}
}
}
void drawBoard(){
for(int y=0;y < ROW; y++){
for(int x=0;x < COL; x++){
if(!board[y][x]){continue;}
drawBlock(x*bP+bOffX, y*bP+bOffY);
}
}
}
void drawActiveBlock(){
int b = 15;
for(int s=0;s < bW; s++){
for(int r=0;r < bH; r++){
if(!bitRead(activeBlock[abR], b)){ b--;continue;}
drawBlock(r*bP+bOffX+abX*bP, s*bP+bOffY+abY*bP);
b--;
}
}
}
void prepareNext(){
nbID = random(6);
nbR = random(3);
switch(nbID){
case 0:
nextBlock = IBlock[nbR];
break;
case 1:
nextBlock = JBlock[nbR];
break;
case 2:
nextBlock = LBlock[nbR];
break;
case 3:
nextBlock = OBlock[nbR];
break;
case 4:
nextBlock = SBlock[nbR];
break;
case 5:
nextBlock = TBlock[nbR];
break;
case 6:
nextBlock = ZBlock[nbR];
break;
}
}
void createBlock(){
abX = 3;
abY = 0;
abR = nbR;
abID = nbID;
switch(abID){
case 0:
for(int i=0; i < 4;i++){activeBlock[i] = IBlock[i];}
break;
case 1:
for(int i=0; i < 4;i++){activeBlock[i] = JBlock[i];}
break;
case 2:
for(int i=0; i < 4;i++){activeBlock[i] = LBlock[i];}
break;
case 3:
for(int i=0; i < 4;i++){activeBlock[i] = OBlock[i];}
break;
case 4:
for(int i=0; i < 4;i++){activeBlock[i] = SBlock[i];}
break;
case 5:
for(int i=0; i < 4;i++){activeBlock[i] = TBlock[i];}
break;
case 6:
for(int i=0; i < 4;i++){activeBlock[i] = ZBlock[i];}
break;
}
prepareNext();
}
void moveRight(){
if(notColision(abX+1,abY,abR)){
abX++;
}
}
void moveLeft(){
if(notColision(abX-1,abY,abR)){
abX--;
}
}
void moveDown(){
if(notColision(abX,abY+1,abR)){
abY++;
}else{
lockBlock();
}
}
void moveRotate(){
byte kOff = 1;
if(notColision(abX,abY,(abR + 1) % 4)){
abR = (abR + 1) % 4;
}else{
if(abX <= 0){
if(notColision(abX+1,abY,(abR + 1) % 4)){
abX++;
abR = (abR + 1) % 4;
}
}
if(abX >= 7){
if(abID == 0 && abX == 8){kOff = 2;}
if(notColision(abX-kOff,abY,(abR + 1) % 4)){
abX -= kOff;
abR = (abR + 1) % 4;
}
}
}
}
void lockBlock(){
int b = 15;
int fullRowCounter = 0;
for(int s=0;s < bW; s++){
for(int r=0;r < bH; r++){
if(!bitRead(activeBlock[abR], b)){ b--;continue;}
board[abY+s][abX+r] = 1;
b--;
if(abY == 0){
gameOver = 1;
}
}
}
if(!gameOver){
for(int y=0;y < ROW; y++){
boolean isRowFull = true;
for(int x=0;x < COL; x++){
isRowFull = isRowFull && board[y][x];
}
if(isRowFull){
for(int r = y;r > 1; r--){
for(int s = 0; s < COL; s++){
board[r][s] = board[r-1][s];
}
}
score += 10 + (10*fullRowCounter);
fullRowCounter++;
}
}
createBlock();
} else {
eraseGame();
}
}
boolean notColision(int newX, int newY, int newR){
boolean nocolide = true;
int b = 15;
for(int s=0;s < bW; s++){
for(int r=0;r < bH; r++){
if(!bitRead(activeBlock[newR], b)){b--; continue;}
if((newX+r >= COL)||(newX+r < 0)){nocolide=false;}
if(newY+s >= ROW){nocolide=false;}
if(board[newY+s][newX+r]){nocolide=false;}
b--;
}
}
return nocolide;
}
void eraseGame(){
for(int y=0;y < ROW; y++){
for(int x=0;x < COL; x++){
board[y][x] = 0;
}
}
gameOver = 1;
isStarted = 0;
}
void draw(void) {
/*if(!isStarted){
drawActiveBlock();
}*/
drawGUI();
drawScore();
if(gameOver) {
drawMenu();
}else{
drawActiveBlock();
drawNextBlock();
drawBoard();
}
}