mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-04-08 06:44:43 +00:00
Tetris: Combined cpp files. Helper files into hpp. Dark mode. Encoder on. (#2587)
This commit is contained in:
parent
20c64c98bd
commit
4b000c8da6
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Mark Thompson
|
|
||||||
*
|
|
||||||
* This file is part of PortaPack.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// dummy include file to avoid changing original source
|
|
||||||
|
|
||||||
#ifndef __UI_Arial12x12_H__
|
|
||||||
#define __UI_Arial12x12_H__
|
|
||||||
|
|
||||||
#define Arial12x12 (0)
|
|
||||||
|
|
||||||
#endif /*__UI_Arial12x12_H__*/
|
|
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Mark Thompson
|
|
||||||
*
|
|
||||||
* This file is part of PortaPack.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// "HAL" display layer for Tetris code to run on PortaPack without its original ILI9341 functions
|
|
||||||
|
|
||||||
#ifndef __UI_SPI_TFT_ILI9341_H__
|
|
||||||
#define __UI_SPI_TFT_ILI9341_H__
|
|
||||||
|
|
||||||
ui::Painter painter;
|
|
||||||
|
|
||||||
static int x_pos{0};
|
|
||||||
static int y_pos{0};
|
|
||||||
static int fg_color;
|
|
||||||
static int bg_color;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
White,
|
|
||||||
Blue,
|
|
||||||
Yellow,
|
|
||||||
Purple,
|
|
||||||
Green,
|
|
||||||
Red,
|
|
||||||
Maroon,
|
|
||||||
Orange,
|
|
||||||
Black,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pp_colors must be in same order as enums above
|
|
||||||
static const Color pp_colors[] = {
|
|
||||||
Color::white(),
|
|
||||||
Color::blue(),
|
|
||||||
Color::yellow(),
|
|
||||||
Color::purple(),
|
|
||||||
Color::green(),
|
|
||||||
Color::red(),
|
|
||||||
Color::magenta(),
|
|
||||||
Color::orange(),
|
|
||||||
Color::black(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// NB: ELIMINATED SPI_TFT_ILI9341 DISPLAY CLASS DUE TO GLOBAL OBJECT INITIALIZATION ISSUE WITH EXTERNAL APPS
|
|
||||||
|
|
||||||
static void claim(__FILE* x) {
|
|
||||||
(void)x;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void cls() {
|
|
||||||
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
|
||||||
};
|
|
||||||
|
|
||||||
static void background(int color) {
|
|
||||||
bg_color = color;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void foreground(int color) {
|
|
||||||
fg_color = color;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void locate(int x, int y) {
|
|
||||||
x_pos = x;
|
|
||||||
y_pos = y;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void set_orientation(int x) {
|
|
||||||
(void)x;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void set_font(unsigned char* x) {
|
|
||||||
(void)x;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void fillrect(int x1, int y1, int x2, int y2, int color) {
|
|
||||||
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void rect(int x1, int y1, int x2, int y2, int color) {
|
|
||||||
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void printf(std::string str) {
|
|
||||||
auto style = (fg_color == White) ? *ui::Theme::getInstance()->bg_darkest : *ui::Theme::getInstance()->bg_lightest;
|
|
||||||
painter.draw_string({x_pos, y_pos - 1}, style, str);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void printf(std::string str, int v) {
|
|
||||||
if (str.find_first_of("%") != std::string::npos) {
|
|
||||||
str.resize(str.find_first_of("%")); // remove %d from end of string
|
|
||||||
}
|
|
||||||
printf(str + to_string_dec_uint(v));
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*__UI_SPI_TFT_ILI9341_H__*/
|
|
220
firmware/application/external/tetris/mbed.h
vendored
220
firmware/application/external/tetris/mbed.h
vendored
@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Mark Thompson
|
|
||||||
*
|
|
||||||
* This file is part of PortaPack.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// "HAL" layer for Tetris code to run on PortaPack without its original mbed OS
|
|
||||||
// (the dream here was to avoid modifying the original code)
|
|
||||||
|
|
||||||
#ifndef __UI_mbed_H__
|
|
||||||
#define __UI_mbed_H__
|
|
||||||
|
|
||||||
using Callback = void (*)(void);
|
|
||||||
|
|
||||||
#define wait_us(x) (void)0
|
|
||||||
#define wait(x) chThdSleepMilliseconds(x * 1000)
|
|
||||||
#define PullUp 1
|
|
||||||
|
|
||||||
enum {
|
|
||||||
dp0,
|
|
||||||
dp1,
|
|
||||||
dp2,
|
|
||||||
dp3,
|
|
||||||
dp4,
|
|
||||||
dp5,
|
|
||||||
dp6,
|
|
||||||
dp7,
|
|
||||||
dp8,
|
|
||||||
dp9,
|
|
||||||
dp10,
|
|
||||||
dp11,
|
|
||||||
dp12,
|
|
||||||
dp13,
|
|
||||||
dp14,
|
|
||||||
dp15,
|
|
||||||
dp16,
|
|
||||||
dp17,
|
|
||||||
dp18,
|
|
||||||
dp19,
|
|
||||||
dp20,
|
|
||||||
dp21,
|
|
||||||
dp22,
|
|
||||||
dp23,
|
|
||||||
dp24,
|
|
||||||
dp25,
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool but_RIGHT;
|
|
||||||
static bool but_LEFT;
|
|
||||||
static bool but_UP;
|
|
||||||
static bool but_DOWN;
|
|
||||||
static bool but_SELECT;
|
|
||||||
|
|
||||||
//
|
|
||||||
// AnalogIn Class -- DID NOT WORK DUE TO GLOBAL OBJECT INITIALIZER ISSUE WITH EXTERNAL APPS -- hacked original code module instead
|
|
||||||
//
|
|
||||||
// dp9 = joystick rotate button --> select button
|
|
||||||
// dp10 = joystick y --> up & down buttons
|
|
||||||
// dp11 = joystick x --> left & right buttons
|
|
||||||
// dp13 = random number generator
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// class AnalogIn {
|
|
||||||
// public:
|
|
||||||
// AnalogIn(uint32_t analog_input) {
|
|
||||||
// // FIXME - THIS CODE NEVER GETS EXECUTED!
|
|
||||||
// analog_input_ = analog_input;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// // Tetris code only uses this function for dp13 - supposed to be a random number
|
|
||||||
// uint16_t read_u16() {
|
|
||||||
// return std::rand();
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// // Tetris code uses read() function for direction buttons only
|
|
||||||
// float read() {
|
|
||||||
// float retval = 0.5;
|
|
||||||
// switch (analog_input_) {
|
|
||||||
// case dp11:
|
|
||||||
// if (but_LEFT)
|
|
||||||
// retval = 0.0;
|
|
||||||
// else if (but_RIGHT)
|
|
||||||
// retval = 1.0;
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case dp10:
|
|
||||||
// if (but_UP)
|
|
||||||
// retval = 0.0;
|
|
||||||
// else if (but_DOWN)
|
|
||||||
// retval = 1.0;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// return retval;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// operator float() {
|
|
||||||
// return read();
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// private:
|
|
||||||
// uint32_t analog_input_{INT_MAX};
|
|
||||||
// };
|
|
||||||
|
|
||||||
//
|
|
||||||
// Timer Class
|
|
||||||
// (Timer object was used for unneeded button debouncing, so just returning 1000ms to indicate we've waited long enough)
|
|
||||||
//
|
|
||||||
class Timer {
|
|
||||||
public:
|
|
||||||
// NOTE: INITIALIZER CODE WON'T RUN
|
|
||||||
Timer() { (void)0; };
|
|
||||||
void reset() { (void)0; };
|
|
||||||
void start() { (void)0; }
|
|
||||||
uint32_t read_ms() { return 1000; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Ticker Class
|
|
||||||
// (Ticker is timed callback, used for checking "joystick" directional switches and when time to move piece down a row)
|
|
||||||
//
|
|
||||||
// NB: Only one callback is supported per Ticker class instantiation
|
|
||||||
static Callback fall_timer_callback;
|
|
||||||
static uint32_t fall_timer_timeout;
|
|
||||||
static uint32_t fall_timer_counter;
|
|
||||||
|
|
||||||
static Callback dir_button_callback;
|
|
||||||
|
|
||||||
static void check_fall_timer() {
|
|
||||||
if (fall_timer_callback) {
|
|
||||||
if (++fall_timer_counter >= fall_timer_timeout) {
|
|
||||||
fall_timer_counter = 0;
|
|
||||||
fall_timer_callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Ticker {
|
|
||||||
public:
|
|
||||||
// NOTE: INITIALIZER CODE WON'T RUN
|
|
||||||
Ticker() { (void)0; };
|
|
||||||
|
|
||||||
void attach(Callback func, double delay_sec) {
|
|
||||||
// 0.3 sec is requested only for button check -- kludge to use on_key callback for this one instead of timer
|
|
||||||
if (delay_sec == 0.3) {
|
|
||||||
dir_button_callback = func;
|
|
||||||
} else {
|
|
||||||
fall_timer_callback = func;
|
|
||||||
fall_timer_timeout = delay_sec * 60; // timer interrupts at 60 Hz
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void detach() {
|
|
||||||
// shouldn't detach both, but don't know how to tell which object is which
|
|
||||||
dir_button_callback = nullptr;
|
|
||||||
fall_timer_callback = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// InterruptIn Class
|
|
||||||
// (just used for the Select button)
|
|
||||||
//
|
|
||||||
static Callback sel_button_callback;
|
|
||||||
|
|
||||||
static bool check_encoder(const EncoderEvent delta) {
|
|
||||||
(void)delta;
|
|
||||||
// TODO: consider adding ability to rotate Tetronimo via encoder too
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_key(const KeyEvent key) {
|
|
||||||
auto switches_debounced = get_switches_state().to_ulong();
|
|
||||||
but_RIGHT = (switches_debounced & 0x01) != 0;
|
|
||||||
but_LEFT = (switches_debounced & 0x02) != 0;
|
|
||||||
but_DOWN = (switches_debounced & 0x04) != 0;
|
|
||||||
but_UP = (switches_debounced & 0x08) != 0;
|
|
||||||
but_SELECT = (switches_debounced & 0x10) != 0;
|
|
||||||
|
|
||||||
if (key == KeyEvent::Select) {
|
|
||||||
if (sel_button_callback)
|
|
||||||
sel_button_callback();
|
|
||||||
} else {
|
|
||||||
if (dir_button_callback)
|
|
||||||
dir_button_callback();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
class InterruptIn {
|
|
||||||
public:
|
|
||||||
InterruptIn(int reg) {
|
|
||||||
// NOTE: INITIALIZER CODE WON'T RUN
|
|
||||||
(void)reg;
|
|
||||||
};
|
|
||||||
void fall(Callback func) { sel_button_callback = func; };
|
|
||||||
void mode(int v) { (void)v; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*__UI_mbed_H__*/
|
|
548
firmware/application/external/tetris/tetris.cpp
vendored
548
firmware/application/external/tetris/tetris.cpp
vendored
@ -1,548 +0,0 @@
|
|||||||
// Projekat Tetris
|
|
||||||
// by Vrnjak Lamija & Selimović Denis
|
|
||||||
// Elektrotehnički fakultet Sarajevo
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
//////// HACKED FOR PORTAPACK -- CHANGES HIGHLIGHTED
|
|
||||||
int main();
|
|
||||||
void pause_game();
|
|
||||||
void Initialize(unsigned char c);
|
|
||||||
void DeleteFigure();
|
|
||||||
void DrawFigure();
|
|
||||||
bool InCollisionDown(char delta);
|
|
||||||
bool InCollisionLeft();
|
|
||||||
bool InCollisionRight();
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
#include "mbed.h"
|
|
||||||
#include "SPI_TFT_ILI9341.h"
|
|
||||||
#include "Arial12x12.h"
|
|
||||||
|
|
||||||
#define dp23 P0_0
|
|
||||||
|
|
||||||
//////// PORTAPACK - DISABLED MOST CLASSES DUE TO GLOBAL OBJECT INITIALIZER ISSUE WITH EXTERNAL APPS:
|
|
||||||
//deklaracija display-a
|
|
||||||
//SPI_TFT_ILI9341 display(dp2, dp1, dp6, dp24, dp23, dp25, "TFT");
|
|
||||||
//
|
|
||||||
//analogni ulazi za joystick
|
|
||||||
// AnalogIn VRx(dp11);
|
|
||||||
// AnalogIn VRy(dp10);
|
|
||||||
//
|
|
||||||
// AnalogIn random(dp13); //analogni ulaz za generisanje random vrijednosti
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
//taster na joysticku za rotaciju
|
|
||||||
InterruptIn taster(dp9);
|
|
||||||
|
|
||||||
//ticker za spustanje figure
|
|
||||||
//timer za debouncing tastera na joysticku
|
|
||||||
Ticker game, joystick;
|
|
||||||
Timer debounceTaster;
|
|
||||||
|
|
||||||
unsigned char level = 0; //mora biti tipa usigned char jer inače se može desiti da level bude manji od 0, a i da ne trošimo memoriju
|
|
||||||
const float delays[4] = {1.2, 0.7, 0.4, 0.25}; //svakih koliko se spusti jedan red, ovo provjeriti da li je presporo ili prebrzo, ovisi o levelu
|
|
||||||
|
|
||||||
//////// PORTAPACK - DELETED UNNEEDED JOYSTICK HYSTERESIS VARIABLES
|
|
||||||
//char leftBoundary = 1, rightBoundary = 5, downBoundary = 1, upBoundary = 5;// sada je ovo tipa char
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
unsigned int score = 0; //stavio sam ovo unsigned int za veći opseg, mada je jako teško da se i int premaši, ali nmvz
|
|
||||||
bool firstTime = true; //ako je prvi put, figura se crta u Tickeru
|
|
||||||
bool gameStarted = false;
|
|
||||||
unsigned char nextFigure = 1; //ovo je sad globalna varijabla, da bi mogli unaprijed generisati sljedeću figuru radi prikaza
|
|
||||||
|
|
||||||
//white - no figure
|
|
||||||
//I - BLUE
|
|
||||||
//O - YELLOW
|
|
||||||
//T - PURPLE
|
|
||||||
//S - GREEN
|
|
||||||
//Z - RED
|
|
||||||
//J - MAROON
|
|
||||||
//L - ORANGE
|
|
||||||
const int colors[8] = {White, Blue, Yellow, Purple, Green, Red, Maroon, Orange};
|
|
||||||
const short DIMENSION = 16;
|
|
||||||
const short DIMENSION_NEXT = 12;
|
|
||||||
short board[20][10] = {0}; //matrica boja, 0 - 7 indeksi boja
|
|
||||||
|
|
||||||
short figuresX[7][4] = {{0,0,0,0}, {0,0,1,1}, {0,1,1,1}, {1,1,0,0}, {0,1,0,1}, {1,1,1,0}, {1,1,1,0}};
|
|
||||||
short figuresY[7][4] = {{0,1,2,3}, {1,0,0,1}, {1,1,2,0}, {0,1,1,2}, {0,1,1,2}, {2,1,0,0}, {0,1,2,2}};
|
|
||||||
|
|
||||||
unsigned int GenerateRandomSeed() {
|
|
||||||
//////// PORTAPACK - USE RTC FOR SEED
|
|
||||||
return LPC_RTC->CTIME0;
|
|
||||||
//////// PORTAPACK
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init() {
|
|
||||||
//ovo su zajedničke osobine za sve prikaze na display-u
|
|
||||||
//nikad se ne mijenjaju i pozvat ćemo je jednom prije petlje
|
|
||||||
claim(stdout);
|
|
||||||
set_orientation(2); // 2 ili 0, zavisi kako okrenemo display, provjerit ćemo na labu kako nam je najlakše povezat
|
|
||||||
set_font((unsigned char*) Arial12x12);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ShowScore() {
|
|
||||||
//pomocna funkcija za prikazivanje score-a
|
|
||||||
fillrect(165, 20, 235, 50, White); //popunimo pravugaonik da obrišemo stari score
|
|
||||||
locate(200, 35); //valjda je na sredini pravougaonika
|
|
||||||
printf("%d", score);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowNextFigure() {
|
|
||||||
//prikaz sljedeće figure koristeći pomoćnu varijablu nextFigure
|
|
||||||
fillrect(165, 70, 235, 120, White);
|
|
||||||
int upperLeftX = 176, upperLeftY = 83;
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
int x = upperLeftX + DIMENSION_NEXT * figuresY[nextFigure - 1][i], y = upperLeftY + DIMENSION_NEXT * figuresX[nextFigure - 1][i];
|
|
||||||
fillrect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, colors[nextFigure]);
|
|
||||||
rect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, Black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//funkcija za crtanje cursora za odabir levela
|
|
||||||
void DrawCursor(int color, unsigned char lev) {
|
|
||||||
fillrect(60, lev * 70 + 50, 72, lev * 70 + 50 + 12, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PORTAPACK - ADDED EXTRA LEVEL:
|
|
||||||
void ShowLevelMenu() {
|
|
||||||
//ovdje inicijalizujemo display
|
|
||||||
cls(); // brišemo prethodno
|
|
||||||
background(Black);
|
|
||||||
foreground(White);
|
|
||||||
locate(80, 50);
|
|
||||||
printf("LEVEL 1");
|
|
||||||
locate(80, 120);
|
|
||||||
printf("LEVEL 2");
|
|
||||||
locate(80, 190);
|
|
||||||
printf("LEVEL 3");
|
|
||||||
locate(80, 260);
|
|
||||||
printf("LEVEL 4");
|
|
||||||
DrawCursor(White, level);
|
|
||||||
}
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
//////// PORTAPACK - USE BUTTONS VS JOYSTICK:
|
|
||||||
void ReadJoystickForLevel(){
|
|
||||||
unsigned char old = level;
|
|
||||||
if(but_UP){
|
|
||||||
(level == 0) ? level = 3 : level--;
|
|
||||||
}
|
|
||||||
else if(but_DOWN){
|
|
||||||
//ne radi ona prethodna varijanta jer % vraća i negastivni rezultat
|
|
||||||
//to što ne koristimo unsigned tip ne pomaže jer će doći do overflow-a
|
|
||||||
level = (level + 1) % 4;
|
|
||||||
}
|
|
||||||
DrawCursor(Black, old); //na prethodni level popunimo bojom pozadine
|
|
||||||
DrawCursor(White, level); //na novi level popunimo bijelom bojom - pozadina je crna
|
|
||||||
//koristio sam fillrect, jer njega svakako moramo koristiti, jer možda budemo morali da brišemo fillcircle iz biblioteke
|
|
||||||
}
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
void EndPlay() {
|
|
||||||
joystick.detach();
|
|
||||||
score = 0;
|
|
||||||
firstTime = true;
|
|
||||||
gameStarted = false;
|
|
||||||
for(int i = 0; i < 20; i++) {
|
|
||||||
for(int j = 0; j < 10; j++) {
|
|
||||||
board[i][j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//////// PORTAPACK - FIX TO REINITIALIZE SCREEN
|
|
||||||
// ShowLevelMenu();
|
|
||||||
// joystick.attach(&ReadJoystickForLevel, 0.3);
|
|
||||||
main();
|
|
||||||
//////// PORTAPACK
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartGame()
|
|
||||||
{
|
|
||||||
cls(); // brišemo ShowLevelMenu
|
|
||||||
background(White);
|
|
||||||
foreground(Black);
|
|
||||||
fillrect(0, 0, 160, 320, White);
|
|
||||||
fillrect(160, 0, 240, 320, Black); //dio za prikazivanje rezultata će biti crni pravougaonik, a tabla je bijeli
|
|
||||||
ShowScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void copyCoordinates(short X[], short Y[], unsigned char index)
|
|
||||||
{
|
|
||||||
//umjesto one prošle metode za kopiranje, ova prima index, čisto da nam olakša život
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
X[i] = figuresX[index][i];
|
|
||||||
Y[i] = figuresY[index][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BottomEdge(int x){
|
|
||||||
return x > 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LeftEdge(int y){
|
|
||||||
return y < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RightEdge(int y){
|
|
||||||
return y > 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OutOfBounds(int y, int x){
|
|
||||||
return y < 0 || y > 9 || x > 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PutBorders(short x, short y) {
|
|
||||||
for(int i = x - 1; i <= x + 1; i++) {
|
|
||||||
for(int j = y - 1; j <= y + 1; j++) {
|
|
||||||
if(i < 0 || i > 9 || j < 0 || j > 19 || board[j][i] == 0) continue;
|
|
||||||
rect(i * DIMENSION, j * DIMENSION, (i + 1) * DIMENSION, (j + 1) * DIMENSION, Black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////// PORTAPACK - ELIMINATED CLASSES DUE TO GLOBAL OBJECT INITIALIZATION ISSUE WITH EXTERNAL APPS:
|
|
||||||
//class Tetromino{
|
|
||||||
//private:
|
|
||||||
short X[4];
|
|
||||||
short Y[4];
|
|
||||||
short boardX, boardY;
|
|
||||||
unsigned char colorIndex;//dodao sam colorIndex zasad, jer nema drugog načina da popunimo matricu sa indeksima boja
|
|
||||||
//ovo je najbezbolnija varijanta što se memorije tiče
|
|
||||||
//public:
|
|
||||||
// Tetromino(){
|
|
||||||
// unsigned char r = rand() % 7 + 1;
|
|
||||||
// Initialize(r);
|
|
||||||
// }
|
|
||||||
|
|
||||||
void Tetromino(unsigned char c) {
|
|
||||||
Initialize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Initialize(unsigned char c) {
|
|
||||||
colorIndex = c;
|
|
||||||
boardX = 0;
|
|
||||||
boardY = 4; //3,4 ili 5 najbolje da vidimo kad imamo display
|
|
||||||
copyCoordinates(X, Y, c - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rotate(){
|
|
||||||
short pivotX = X[1], pivotY = Y[1];
|
|
||||||
//prvi elemnti u matrici su pivoti oko koje rotiramo
|
|
||||||
|
|
||||||
short newX[4]; //pozicije blokova nakon rotiranja ako sve bude ok
|
|
||||||
short newY[4];
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
short tmp = X[i], tmp2 = Y[i];
|
|
||||||
newX[i] = pivotX + pivotY - tmp2;
|
|
||||||
newY[i] = tmp + pivotX - pivotY;
|
|
||||||
|
|
||||||
if(OutOfBounds(boardY + newY[i], boardX + newX[i]) || board[boardX + newX[i]][boardY + newY[i]] != 0) return;
|
|
||||||
}
|
|
||||||
DeleteFigure();
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
X[i] = newX[i];
|
|
||||||
Y[i] = newY[i];
|
|
||||||
}
|
|
||||||
DrawFigure();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawFigure() {
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
//display je deklarisani display logy iz biblioteke one
|
|
||||||
//računamo gornji lijevi pixel po x i y
|
|
||||||
//donji desni dobijemo kad dodamo DIMENZIJU
|
|
||||||
//stavio sam 16 za početak, možemo se opet skontati na labu
|
|
||||||
//ovo pretpostavlja da nema margina, mogu se lagano dodati uz neku konstantu kao offset
|
|
||||||
int upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
|
||||||
fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, colors[colorIndex]);
|
|
||||||
//ovo boji granice blokova u crno, možemo skloniti ako ti se ne sviđa
|
|
||||||
rect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteFigure() {
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
//ista logika kao u DrawFigure, samo popunjavamo sve blokove sa bijelim pravougaonicima
|
|
||||||
short upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
|
||||||
fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, White);
|
|
||||||
PutBorders(upperLeftY, upperLeftX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnAttached() {
|
|
||||||
//metoda se poziva kad figura prestanje da se krece
|
|
||||||
//popunimo matricu indeksom boje
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
board[boardX + X[i]][boardY + Y[i]] = colorIndex;
|
|
||||||
//btw board bi mogao biti niz tipa unsigned char, ali to ćemo vidjet kasnije
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MoveDown(char delta = 1){
|
|
||||||
if(!InCollisionDown(delta)){
|
|
||||||
DeleteFigure();
|
|
||||||
boardX+=delta;
|
|
||||||
DrawFigure();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveLeft(){
|
|
||||||
if(!InCollisionLeft()){
|
|
||||||
DeleteFigure();
|
|
||||||
boardY--;
|
|
||||||
DrawFigure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveRight(){
|
|
||||||
if(!InCollisionRight()){
|
|
||||||
DeleteFigure();
|
|
||||||
boardY++;
|
|
||||||
DrawFigure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftDrop() {
|
|
||||||
//ovo je funkcija za soft drop
|
|
||||||
//obrisemo figuru, postavimo novu poziciju dva reda ispod, nacrtamo figuru
|
|
||||||
DeleteFigure();
|
|
||||||
MoveDown(2);
|
|
||||||
DrawFigure();
|
|
||||||
//treba još vidjeti koje izmjene u tickeru trebaju
|
|
||||||
score += 2 * (level +1); //prema igrici koju smo igrali, dobije se 14 poena kad se uradi hard drop
|
|
||||||
ShowScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool InCollisionDown(char delta = 1){
|
|
||||||
int newX, newY; //da bi bilo citljivije
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
newX = boardX + X[i] + delta;
|
|
||||||
newY = boardY + Y[i];
|
|
||||||
|
|
||||||
if(BottomEdge(newX) || board[newX][newY] != 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//jedna figura je u koliziji ako
|
|
||||||
//pozicija na koju zelimo da pomjerimo bilo koji blok dotakne dno ili lijevu ili desnu ivicu ekrana
|
|
||||||
//ili ako je pozicija na koju zelimo da pomjerimo bilo koji od blokova vec zauzeta a da nije dio figure prije pomijeranja
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InCollisionLeft(){
|
|
||||||
int newX, newY;
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
newX = boardX + X[i];
|
|
||||||
newY = boardY + Y[i] - 1;
|
|
||||||
|
|
||||||
if(LeftEdge(newY) || board[newX][newY] != 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool InCollisionRight(){
|
|
||||||
int newX, newY;
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
newX = boardX + X[i];
|
|
||||||
newY = boardY + Y[i] + 1;
|
|
||||||
|
|
||||||
if(RightEdge(newY) || board[newX][newY] != 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Tetromino currentTetromino;
|
|
||||||
|
|
||||||
//////// PORTAPACK - USE BUTTONS VS JOYSTICK, AND ADDED PAUSE FEATURE:
|
|
||||||
void ReadJoystickForFigure() {
|
|
||||||
if(but_LEFT) {
|
|
||||||
MoveLeft();
|
|
||||||
}
|
|
||||||
else if(but_RIGHT) {
|
|
||||||
MoveRight();
|
|
||||||
}
|
|
||||||
else if(but_UP) {
|
|
||||||
pause_game();
|
|
||||||
}
|
|
||||||
else if(but_DOWN) {
|
|
||||||
SoftDrop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//////// PORTAPACK
|
|
||||||
|
|
||||||
void CheckLines(short &firstLine, short &numberOfLines)
|
|
||||||
{
|
|
||||||
//vraća preko reference prvu liniju koja je popunjena do kraja, kao i takvih linija
|
|
||||||
firstLine = -1; //postavljen na -1 jer ako nema linija koje treba brisati ispod u UpdateBoard neće se ući u petlju
|
|
||||||
numberOfLines = 0;
|
|
||||||
for(int i = 19; i >= 0; i--) {
|
|
||||||
short temp = 0;
|
|
||||||
for(int j = 0; j < 10; j++) {
|
|
||||||
if(board[i][j] == 0) {
|
|
||||||
if(numberOfLines > 0) return;
|
|
||||||
break;
|
|
||||||
}//ako je makar jedna bijela, prekida se brojanje
|
|
||||||
temp++;
|
|
||||||
}
|
|
||||||
if(temp == 10) { //ako je temo došao do 10, niti jedna bijela - puna linija
|
|
||||||
numberOfLines++;
|
|
||||||
if(firstLine == -1) firstLine = i; //ovo mijenjamo samo prvi put
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int UpdateScore (short numOfLines){
|
|
||||||
unsigned int newIncrement = 0;
|
|
||||||
switch(numOfLines) {
|
|
||||||
case 1 : newIncrement = 40; break;
|
|
||||||
case 2 : newIncrement = 100; break;
|
|
||||||
case 3 : newIncrement = 300; break;
|
|
||||||
case 4 : newIncrement = 1200; break;
|
|
||||||
default : newIncrement = 0; break; //update funkcije za score, još sam vratio ovo na 0
|
|
||||||
}
|
|
||||||
return newIncrement * (level + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateBoard()
|
|
||||||
{
|
|
||||||
short firstLine, numberOfLines;
|
|
||||||
//pozivamo funkciju
|
|
||||||
do {
|
|
||||||
CheckLines(firstLine, numberOfLines);
|
|
||||||
for(int i = firstLine; i >= numberOfLines; i--) {
|
|
||||||
for(int j = 0; j < 10; j++) {
|
|
||||||
board[i][j] = board[i - numberOfLines][j];
|
|
||||||
board[i - numberOfLines][j] = 0;
|
|
||||||
short tmp = i - numberOfLines;
|
|
||||||
fillrect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , colors[board[i][j]]); // bojimo novi blok
|
|
||||||
fillrect( j * DIMENSION, tmp * DIMENSION,(j + 1) * DIMENSION, (tmp + 1) * DIMENSION , White);
|
|
||||||
if(board[i][j] != 0)
|
|
||||||
rect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , Black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
score += UpdateScore(numberOfLines);
|
|
||||||
}
|
|
||||||
while(numberOfLines != 0); //ovdje se mijenja globalna varijabla score
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsOver() {
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
if(board[0][i] != 0) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowGameOverScreen() {
|
|
||||||
//////// PORTAPACK - SKIP CLS
|
|
||||||
// cls();
|
|
||||||
// background(Black);
|
|
||||||
// foreground(White);
|
|
||||||
background(White);
|
|
||||||
foreground(Black);
|
|
||||||
//////// PORTAPACK
|
|
||||||
locate(60, 120);
|
|
||||||
printf("GAME OVER");
|
|
||||||
locate(40, 150);
|
|
||||||
printf("YOUR SCORE IS %d", score);
|
|
||||||
wait(5); //ovaj prikaz traje 3s (možemo mijenjati) a nakon toga se ponovo prikazuje meni sa levelima
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitGame() {
|
|
||||||
if(firstTime) {
|
|
||||||
Tetromino(rand() % 7 + 1);
|
|
||||||
DrawFigure();
|
|
||||||
nextFigure = rand() % 7 + 1;
|
|
||||||
ShowNextFigure();
|
|
||||||
firstTime = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayGame(){
|
|
||||||
InitGame();
|
|
||||||
if(!MoveDown()){
|
|
||||||
OnAttached();
|
|
||||||
UpdateBoard();
|
|
||||||
ShowScore();
|
|
||||||
|
|
||||||
Tetromino(nextFigure);
|
|
||||||
DrawFigure();
|
|
||||||
nextFigure = rand() % 7 + 1;
|
|
||||||
ShowNextFigure();
|
|
||||||
if(IsOver()) {
|
|
||||||
//ako je igra završena brišemo sve sa displey-a, prikazujemo poruku i score
|
|
||||||
//takođe moramo dettach-at ticker
|
|
||||||
game.detach();
|
|
||||||
ShowGameOverScreen(); //prikaz da je kraj igre, ima wait od 3s
|
|
||||||
EndPlay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnTasterPressed(){
|
|
||||||
if(debounceTaster.read_ms() > 200) {
|
|
||||||
if(gameStarted){
|
|
||||||
Rotate();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
joystick.detach();
|
|
||||||
gameStarted = true;
|
|
||||||
StartGame(); //pocinje igra, prikazuje se tabla
|
|
||||||
joystick.attach(&ReadJoystickForFigure, 0.3);
|
|
||||||
game.attach(&PlayGame, delays[level]); //svakih nekoliko spusta figuru jedan red nize
|
|
||||||
}
|
|
||||||
debounceTaster.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTaster() {
|
|
||||||
taster.mode(PullUp); //mora se aktivirati pull up otpornik na tasteru joystick-a
|
|
||||||
taster.fall(&OnTasterPressed);
|
|
||||||
debounceTaster.reset();
|
|
||||||
debounceTaster.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
srand(GenerateRandomSeed());
|
|
||||||
Init();
|
|
||||||
ShowLevelMenu();
|
|
||||||
joystick.attach(&ReadJoystickForLevel, 0.3);
|
|
||||||
SetTaster();
|
|
||||||
|
|
||||||
//////// PORTAPACK: CAN'T HANG HERE IN MAYHEM OR WE WON'T GET ANY CALLBACKS
|
|
||||||
// while(1);
|
|
||||||
return 0;
|
|
||||||
//////// PORTAPACK
|
|
||||||
}
|
|
||||||
|
|
||||||
//////// PORTAPACK - ADDED PAUSE FEATURE:
|
|
||||||
void pause_game() {
|
|
||||||
game.detach();
|
|
||||||
joystick.detach();
|
|
||||||
locate(180, 200);
|
|
||||||
printf("PAUSED");
|
|
||||||
while ((get_switches_state().to_ulong() & 0x10) == 0); // wait for SELECT button to resume
|
|
||||||
printf(" ");
|
|
||||||
joystick.attach(&ReadJoystickForFigure, 0.3);
|
|
||||||
game.attach(&PlayGame, delays[level]); //svakih nekoliko spusta figuru jedan red nize
|
|
||||||
};
|
|
||||||
//////// PORTAPACK
|
|
560
firmware/application/external/tetris/ui_tetris.cpp
vendored
560
firmware/application/external/tetris/ui_tetris.cpp
vendored
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Mark Thompson
|
* Copyright (C) 2024 Mark Thompson
|
||||||
|
* 2025 updates by RocketGod (https://betaskynet.com/)
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
@ -23,23 +24,528 @@
|
|||||||
|
|
||||||
namespace ui::external_app::tetris {
|
namespace ui::external_app::tetris {
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
Ticker game;
|
||||||
// external code, so ignore warnings
|
Ticker joystick;
|
||||||
#pragma GCC diagnostic ignored "-Weffc++"
|
|
||||||
#include "tetris.cpp"
|
unsigned char level = 0;
|
||||||
#pragma GCC diagnostic pop
|
const float delays[4] = {1.2, 0.7, 0.4, 0.25};
|
||||||
|
unsigned int score = 0;
|
||||||
|
bool firstTime = true;
|
||||||
|
bool gameStarted = false;
|
||||||
|
unsigned char nextFigure = 1;
|
||||||
|
short board[20][10] = {0};
|
||||||
|
const int colors[8] = {White, Blue, Yellow, Purple, Green, Red, Maroon, Orange};
|
||||||
|
const short DIMENSION = 16;
|
||||||
|
const short DIMENSION_NEXT = 12;
|
||||||
|
short figuresX[7][4] = {{0, 0, 0, 0}, {0, 0, 1, 1}, {0, 1, 1, 1}, {1, 1, 0, 0}, {0, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 0}};
|
||||||
|
short figuresY[7][4] = {{0, 1, 2, 3}, {1, 0, 0, 1}, {1, 1, 2, 0}, {0, 1, 1, 2}, {0, 1, 1, 2}, {2, 1, 0, 0}, {0, 1, 2, 2}};
|
||||||
|
|
||||||
|
const Color pp_colors[] = {
|
||||||
|
Color::white(),
|
||||||
|
Color::blue(),
|
||||||
|
Color::yellow(),
|
||||||
|
Color::purple(),
|
||||||
|
Color::green(),
|
||||||
|
Color::red(),
|
||||||
|
Color::magenta(),
|
||||||
|
Color::orange(),
|
||||||
|
Color::black(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Painter painter;
|
||||||
|
|
||||||
|
bool but_RIGHT = false;
|
||||||
|
bool but_LEFT = false;
|
||||||
|
bool but_UP = false;
|
||||||
|
bool but_DOWN = false;
|
||||||
|
bool but_SELECT = false;
|
||||||
|
|
||||||
|
static int x_pos{0};
|
||||||
|
static int y_pos{0};
|
||||||
|
static int fg_color;
|
||||||
|
static int bg_color;
|
||||||
|
|
||||||
|
static Callback fall_timer_callback = nullptr;
|
||||||
|
static uint32_t fall_timer_timeout = 0;
|
||||||
|
static uint32_t fall_timer_counter = 0;
|
||||||
|
static Callback dir_button_callback = nullptr;
|
||||||
|
|
||||||
|
void cls() {
|
||||||
|
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
||||||
|
}
|
||||||
|
|
||||||
|
void background(int color) {
|
||||||
|
bg_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foreground(int color) {
|
||||||
|
fg_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void locate(int x, int y) {
|
||||||
|
x_pos = x;
|
||||||
|
y_pos = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||||
|
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rect(int x1, int y1, int x2, int y2, int color) {
|
||||||
|
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf(std::string str) {
|
||||||
|
auto style = (fg_color == White) ? *ui::Theme::getInstance()->bg_darkest : *ui::Theme::getInstance()->fg_light;
|
||||||
|
painter.draw_string({x_pos, y_pos - 1}, style, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf(std::string str, int v) {
|
||||||
|
if (str.find_first_of("%") != std::string::npos) {
|
||||||
|
str.resize(str.find_first_of("%"));
|
||||||
|
}
|
||||||
|
printf(str + to_string_dec_uint(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_fall_timer() {
|
||||||
|
if (fall_timer_callback) {
|
||||||
|
if (++fall_timer_counter >= fall_timer_timeout) {
|
||||||
|
fall_timer_counter = 0;
|
||||||
|
fall_timer_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ticker::attach(Callback func, double delay_sec) {
|
||||||
|
if (delay_sec == 0.3) {
|
||||||
|
dir_button_callback = func;
|
||||||
|
} else {
|
||||||
|
fall_timer_callback = func;
|
||||||
|
fall_timer_timeout = delay_sec * 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ticker::detach() {
|
||||||
|
dir_button_callback = nullptr;
|
||||||
|
fall_timer_callback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GenerateRandomSeed() {
|
||||||
|
return LPC_RTC->CTIME0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowScore() {
|
||||||
|
fillrect(165, 10, 235, 60, Black);
|
||||||
|
rect(165, 10, 235, 60, White);
|
||||||
|
locate(200, 35);
|
||||||
|
printf("%d", score);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowNextFigure() {
|
||||||
|
fillrect(165, 70, 235, 130, Black);
|
||||||
|
rect(165, 70, 235, 130, White);
|
||||||
|
int upperLeftX = 176, upperLeftY = 83;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int x = upperLeftX + DIMENSION_NEXT * figuresY[nextFigure - 1][i], y = upperLeftY + DIMENSION_NEXT * figuresX[nextFigure - 1][i];
|
||||||
|
fillrect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, colors[nextFigure]);
|
||||||
|
rect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, Black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCursor(int color, unsigned char lev) {
|
||||||
|
fillrect(60, lev * 70 + 50, 72, lev * 70 + 50 + 12, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLevelMenu() {
|
||||||
|
cls();
|
||||||
|
background(Black);
|
||||||
|
foreground(White);
|
||||||
|
locate(80, 50);
|
||||||
|
printf("LEVEL 1");
|
||||||
|
locate(80, 120);
|
||||||
|
printf("LEVEL 2");
|
||||||
|
locate(80, 190);
|
||||||
|
printf("LEVEL 3");
|
||||||
|
locate(80, 260);
|
||||||
|
printf("LEVEL 4");
|
||||||
|
DrawCursor(White, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadJoystickForLevel() {
|
||||||
|
unsigned char old = level;
|
||||||
|
if (but_UP) {
|
||||||
|
(level == 0) ? level = 3 : level--;
|
||||||
|
} else if (but_DOWN) {
|
||||||
|
level = (level + 1) % 4;
|
||||||
|
}
|
||||||
|
if (old != level) {
|
||||||
|
DrawCursor(Black, old);
|
||||||
|
DrawCursor(White, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndPlay() {
|
||||||
|
joystick.detach();
|
||||||
|
game.detach();
|
||||||
|
score = 0;
|
||||||
|
firstTime = true;
|
||||||
|
gameStarted = false;
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
board[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShowLevelMenu();
|
||||||
|
joystick.attach(&ReadJoystickForLevel, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartGame() {
|
||||||
|
cls();
|
||||||
|
background(Black);
|
||||||
|
foreground(White);
|
||||||
|
fillrect(0, 0, 162, 320, Black);
|
||||||
|
rect(162, 0, 164, 320, White);
|
||||||
|
fillrect(164, 0, 240, 320, Black);
|
||||||
|
ShowScore();
|
||||||
|
ShowNextFigure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyCoordinates(short X[], short Y[], unsigned char index) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
X[i] = figuresX[index][i];
|
||||||
|
Y[i] = figuresY[index][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BottomEdge(int x) {
|
||||||
|
return x > 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LeftEdge(int y) {
|
||||||
|
return y < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RightEdge(int y) {
|
||||||
|
return y > 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutOfBounds(int y, int x) {
|
||||||
|
return y < 0 || y > 9 || x > 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutBorders(short x, short y) {
|
||||||
|
for (int i = x - 1; i <= x + 1; i++) {
|
||||||
|
for (int j = y - 1; j <= y + 1; j++) {
|
||||||
|
if (i < 0 || i > 9 || j < 0 || j > 19 || board[j][i] == 0) continue;
|
||||||
|
rect(i * DIMENSION, j * DIMENSION, (i + 1) * DIMENSION, (j + 1) * DIMENSION, Black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short X[4];
|
||||||
|
short Y[4];
|
||||||
|
short boardX, boardY;
|
||||||
|
unsigned char colorIndex;
|
||||||
|
|
||||||
|
void Tetromino(unsigned char c) {
|
||||||
|
Initialize(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(unsigned char c) {
|
||||||
|
colorIndex = c;
|
||||||
|
boardX = 0;
|
||||||
|
boardY = 4;
|
||||||
|
copyCoordinates(X, Y, c - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rotate() {
|
||||||
|
short pivotX = X[1];
|
||||||
|
short pivotY = Y[1];
|
||||||
|
short newX[4];
|
||||||
|
short newY[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
short tmp = X[i], tmp2 = Y[i];
|
||||||
|
newX[i] = pivotX + pivotY - tmp2;
|
||||||
|
newY[i] = tmp + pivotX - pivotY;
|
||||||
|
if (OutOfBounds(boardY + newY[i], boardX + newX[i]) || board[boardX + newX[i]][boardY + newY[i]] != 0) return;
|
||||||
|
}
|
||||||
|
DeleteFigure();
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
X[i] = newX[i];
|
||||||
|
Y[i] = newY[i];
|
||||||
|
}
|
||||||
|
DrawFigure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFigure() {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
||||||
|
fillrect(upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, colors[colorIndex]);
|
||||||
|
rect(upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteFigure() {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
short upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
|
||||||
|
fillrect(upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
|
||||||
|
PutBorders(upperLeftY, upperLeftX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAttached() {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
board[boardX + X[i]][boardY + Y[i]] = colorIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MoveDown(char delta) {
|
||||||
|
if (!InCollisionDown(delta)) {
|
||||||
|
DeleteFigure();
|
||||||
|
boardX += delta;
|
||||||
|
DrawFigure();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveLeft() {
|
||||||
|
if (!InCollisionLeft()) {
|
||||||
|
DeleteFigure();
|
||||||
|
boardY--;
|
||||||
|
DrawFigure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveRight() {
|
||||||
|
if (!InCollisionRight()) {
|
||||||
|
DeleteFigure();
|
||||||
|
boardY++;
|
||||||
|
DrawFigure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftDrop() {
|
||||||
|
DeleteFigure();
|
||||||
|
MoveDown(2);
|
||||||
|
DrawFigure();
|
||||||
|
score += 2 * (level + 1);
|
||||||
|
ShowScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InCollisionDown(char delta) {
|
||||||
|
int newX, newY;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
newX = boardX + X[i] + delta;
|
||||||
|
newY = boardY + Y[i];
|
||||||
|
if (BottomEdge(newX) || board[newX][newY] != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InCollisionLeft() {
|
||||||
|
int newX, newY;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
newX = boardX + X[i];
|
||||||
|
newY = boardY + Y[i] - 1;
|
||||||
|
if (LeftEdge(newY) || board[newX][newY] != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InCollisionRight() {
|
||||||
|
int newX, newY;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
newX = boardX + X[i];
|
||||||
|
newY = boardY + Y[i] + 1;
|
||||||
|
if (RightEdge(newY) || board[newX][newY] != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadJoystickForFigure() {
|
||||||
|
if (but_LEFT) {
|
||||||
|
MoveLeft();
|
||||||
|
} else if (but_RIGHT) {
|
||||||
|
MoveRight();
|
||||||
|
} else if (but_UP) {
|
||||||
|
pause_game();
|
||||||
|
} else if (but_DOWN) {
|
||||||
|
SoftDrop();
|
||||||
|
} else if (but_SELECT) {
|
||||||
|
Rotate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckLines(short& firstLine, short& numberOfLines) {
|
||||||
|
firstLine = -1;
|
||||||
|
numberOfLines = 0;
|
||||||
|
for (int i = 19; i >= 0; i--) {
|
||||||
|
short temp = 0;
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
if (board[i][j] == 0) {
|
||||||
|
if (numberOfLines > 0) return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
temp++;
|
||||||
|
}
|
||||||
|
if (temp == 10) {
|
||||||
|
numberOfLines++;
|
||||||
|
if (firstLine == -1) firstLine = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int UpdateScore(short numOfLines) {
|
||||||
|
unsigned int newIncrement = 0;
|
||||||
|
switch (numOfLines) {
|
||||||
|
case 1:
|
||||||
|
newIncrement = 40;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
newIncrement = 100;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
newIncrement = 300;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
newIncrement = 1200;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newIncrement = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return newIncrement * (level + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateBoard() {
|
||||||
|
short firstLine, numberOfLines;
|
||||||
|
do {
|
||||||
|
CheckLines(firstLine, numberOfLines);
|
||||||
|
for (int i = firstLine; i >= numberOfLines; i--) {
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
board[i][j] = board[i - numberOfLines][j];
|
||||||
|
board[i - numberOfLines][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fillrect(0, 0, 162, 320, Black);
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
if (board[i][j] != 0) {
|
||||||
|
fillrect(j * DIMENSION, i * DIMENSION, (j + 1) * DIMENSION, (i + 1) * DIMENSION, colors[board[i][j]]);
|
||||||
|
rect(j * DIMENSION, i * DIMENSION, (j + 1) * DIMENSION, (i + 1) * DIMENSION, Black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
score += UpdateScore(numberOfLines);
|
||||||
|
DrawFigure();
|
||||||
|
} while (numberOfLines != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOver() {
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
if (board[0][i] != 0) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowGameOverScreen() {
|
||||||
|
background(Black);
|
||||||
|
foreground(White);
|
||||||
|
locate(60, 120);
|
||||||
|
printf("GAME OVER");
|
||||||
|
locate(40, 150);
|
||||||
|
printf("YOUR SCORE IS %d", score);
|
||||||
|
wait(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitGame() {
|
||||||
|
if (firstTime) {
|
||||||
|
Tetromino(rand() % 7 + 1);
|
||||||
|
DrawFigure();
|
||||||
|
nextFigure = rand() % 7 + 1;
|
||||||
|
ShowNextFigure();
|
||||||
|
firstTime = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayGame() {
|
||||||
|
InitGame();
|
||||||
|
if (!MoveDown(1)) {
|
||||||
|
OnAttached();
|
||||||
|
UpdateBoard();
|
||||||
|
ShowScore();
|
||||||
|
Tetromino(nextFigure);
|
||||||
|
DrawFigure();
|
||||||
|
nextFigure = rand() % 7 + 1;
|
||||||
|
ShowNextFigure();
|
||||||
|
if (IsOver()) {
|
||||||
|
game.detach();
|
||||||
|
ShowGameOverScreen();
|
||||||
|
EndPlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTasterPressed() {
|
||||||
|
static uint32_t debounce_counter = 0;
|
||||||
|
const uint32_t debounce_threshold = 12;
|
||||||
|
|
||||||
|
if (debounce_counter == 0) {
|
||||||
|
if (!gameStarted) {
|
||||||
|
joystick.detach();
|
||||||
|
gameStarted = true;
|
||||||
|
StartGame();
|
||||||
|
joystick.attach(&ReadJoystickForFigure, 0.3);
|
||||||
|
game.attach(&PlayGame, delays[level]);
|
||||||
|
}
|
||||||
|
debounce_counter = debounce_threshold;
|
||||||
|
} else if (debounce_counter > 0) {
|
||||||
|
debounce_counter--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause_game() {
|
||||||
|
game.detach();
|
||||||
|
joystick.detach();
|
||||||
|
locate(180, 200);
|
||||||
|
printf("PAUSED");
|
||||||
|
while ((get_switches_state().to_ulong() & 0x10) == 0)
|
||||||
|
;
|
||||||
|
printf(" ");
|
||||||
|
joystick.attach(&ReadJoystickForFigure, 0.3);
|
||||||
|
game.attach(&PlayGame, delays[level]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::srand(GenerateRandomSeed());
|
||||||
|
Init();
|
||||||
|
ShowLevelMenu();
|
||||||
|
joystick.attach(&ReadJoystickForLevel, 0.3);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
TetrisView::TetrisView(NavigationView& nav)
|
TetrisView::TetrisView(NavigationView& nav)
|
||||||
: nav_(nav) {
|
: nav_{nav} {
|
||||||
add_children({&dummy});
|
add_children({&dummy});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TetrisView::on_show() {
|
||||||
|
}
|
||||||
|
|
||||||
void TetrisView::paint(Painter& painter) {
|
void TetrisView::paint(Painter& painter) {
|
||||||
(void)painter;
|
(void)painter;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
std::srand(LPC_RTC->CTIME0);
|
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,11 +556,45 @@ void TetrisView::frame_sync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TetrisView::on_encoder(const EncoderEvent delta) {
|
bool TetrisView::on_encoder(const EncoderEvent delta) {
|
||||||
return check_encoder(delta);
|
if (!gameStarted) {
|
||||||
|
unsigned char old = level;
|
||||||
|
if (delta > 0) {
|
||||||
|
level = (level + 1) % 4;
|
||||||
|
} else if (delta < 0) {
|
||||||
|
(level == 0) ? level = 3 : level--;
|
||||||
|
}
|
||||||
|
if (old != level) {
|
||||||
|
DrawCursor(Black, old);
|
||||||
|
DrawCursor(White, level);
|
||||||
|
}
|
||||||
|
} else if (gameStarted && delta != 0) {
|
||||||
|
Rotate();
|
||||||
|
}
|
||||||
|
set_dirty();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TetrisView::on_key(const KeyEvent key) {
|
bool TetrisView::on_key(const KeyEvent key) {
|
||||||
return check_key(key);
|
auto switches_debounced = get_switches_state().to_ulong();
|
||||||
|
but_RIGHT = (switches_debounced & 0x01) != 0;
|
||||||
|
but_LEFT = (switches_debounced & 0x02) != 0;
|
||||||
|
but_DOWN = (switches_debounced & 0x04) != 0;
|
||||||
|
but_UP = (switches_debounced & 0x08) != 0;
|
||||||
|
but_SELECT = (switches_debounced & 0x10) != 0;
|
||||||
|
|
||||||
|
if (key == KeyEvent::Select) {
|
||||||
|
if (!gameStarted) {
|
||||||
|
OnTasterPressed();
|
||||||
|
} else {
|
||||||
|
Rotate();
|
||||||
|
}
|
||||||
|
} else if (gameStarted) {
|
||||||
|
ReadJoystickForFigure();
|
||||||
|
} else {
|
||||||
|
ReadJoystickForLevel();
|
||||||
|
}
|
||||||
|
set_dirty();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ui::external_app::tetris
|
} // namespace ui::external_app::tetris
|
105
firmware/application/external/tetris/ui_tetris.hpp
vendored
105
firmware/application/external/tetris/ui_tetris.hpp
vendored
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Mark Thompson
|
* Copyright (C) 2024 Mark Thompson
|
||||||
|
* 2025 updates by RocketGod (https://betaskynet.com/)
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
@ -22,6 +23,7 @@
|
|||||||
#ifndef __UI_TETRIS_H__
|
#ifndef __UI_TETRIS_H__
|
||||||
#define __UI_TETRIS_H__
|
#define __UI_TETRIS_H__
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "event_m0.hpp"
|
#include "event_m0.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
@ -29,16 +31,113 @@
|
|||||||
#include "random.hpp"
|
#include "random.hpp"
|
||||||
#include "lpc43xx_cpp.hpp"
|
#include "lpc43xx_cpp.hpp"
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
|
#include "ui_widget.hpp"
|
||||||
|
|
||||||
namespace ui::external_app::tetris {
|
namespace ui::external_app::tetris {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
White,
|
||||||
|
Blue,
|
||||||
|
Yellow,
|
||||||
|
Purple,
|
||||||
|
Green,
|
||||||
|
Red,
|
||||||
|
Maroon,
|
||||||
|
Orange,
|
||||||
|
Black,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const Color pp_colors[];
|
||||||
|
extern Painter painter;
|
||||||
|
extern bool but_RIGHT;
|
||||||
|
extern bool but_LEFT;
|
||||||
|
extern bool but_UP;
|
||||||
|
extern bool but_DOWN;
|
||||||
|
extern bool but_SELECT;
|
||||||
|
|
||||||
|
void cls();
|
||||||
|
void background(int color);
|
||||||
|
void foreground(int color);
|
||||||
|
void locate(int x, int y);
|
||||||
|
void fillrect(int x1, int y1, int x2, int y2, int color);
|
||||||
|
void rect(int x1, int y1, int x2, int y2, int color);
|
||||||
|
void printf(std::string str);
|
||||||
|
void printf(std::string str, int v);
|
||||||
|
|
||||||
|
#define wait(x) chThdSleepMilliseconds(x * 1000)
|
||||||
|
|
||||||
|
using Callback = void (*)(void);
|
||||||
|
|
||||||
|
class Ticker {
|
||||||
|
public:
|
||||||
|
Ticker() = default;
|
||||||
|
void attach(Callback func, double delay_sec);
|
||||||
|
void detach();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Ticker game;
|
||||||
|
extern Ticker joystick;
|
||||||
|
|
||||||
|
extern unsigned char level;
|
||||||
|
extern const float delays[4];
|
||||||
|
extern unsigned int score;
|
||||||
|
extern bool firstTime;
|
||||||
|
extern bool gameStarted;
|
||||||
|
extern unsigned char nextFigure;
|
||||||
|
extern short board[20][10];
|
||||||
|
extern const int colors[8];
|
||||||
|
extern const short DIMENSION;
|
||||||
|
extern const short DIMENSION_NEXT;
|
||||||
|
extern short figuresX[7][4];
|
||||||
|
extern short figuresY[7][4];
|
||||||
|
|
||||||
|
unsigned int GenerateRandomSeed();
|
||||||
|
void Init();
|
||||||
|
void ShowScore();
|
||||||
|
void ShowNextFigure();
|
||||||
|
void DrawCursor(int color, unsigned char lev);
|
||||||
|
void ShowLevelMenu();
|
||||||
|
void ReadJoystickForLevel();
|
||||||
|
void EndPlay();
|
||||||
|
void StartGame();
|
||||||
|
void copyCoordinates(short X[], short Y[], unsigned char index);
|
||||||
|
bool BottomEdge(int x);
|
||||||
|
bool LeftEdge(int y);
|
||||||
|
bool RightEdge(int y);
|
||||||
|
bool OutOfBounds(int y, int x);
|
||||||
|
void PutBorders(short x, short y);
|
||||||
|
void Tetromino(unsigned char c);
|
||||||
|
void Initialize(unsigned char c);
|
||||||
|
void Rotate();
|
||||||
|
void DrawFigure();
|
||||||
|
void DeleteFigure();
|
||||||
|
void OnAttached();
|
||||||
|
bool MoveDown(char delta);
|
||||||
|
void MoveLeft();
|
||||||
|
void MoveRight();
|
||||||
|
void SoftDrop();
|
||||||
|
bool InCollisionDown(char delta);
|
||||||
|
bool InCollisionLeft();
|
||||||
|
bool InCollisionRight();
|
||||||
|
void ReadJoystickForFigure();
|
||||||
|
void CheckLines(short& firstLine, short& numberOfLines);
|
||||||
|
unsigned int UpdateScore(short numOfLines);
|
||||||
|
void UpdateBoard();
|
||||||
|
bool IsOver();
|
||||||
|
void ShowGameOverScreen();
|
||||||
|
void InitGame();
|
||||||
|
void PlayGame();
|
||||||
|
void OnTasterPressed();
|
||||||
|
void pause_game();
|
||||||
|
|
||||||
class TetrisView : public View {
|
class TetrisView : public View {
|
||||||
public:
|
public:
|
||||||
TetrisView(NavigationView& nav);
|
TetrisView(NavigationView& nav);
|
||||||
|
void on_show() override;
|
||||||
|
|
||||||
std::string title() const override { return "Tetris"; };
|
std::string title() const override { return "Tetris"; }
|
||||||
|
|
||||||
void focus() override { dummy.focus(); };
|
void focus() override { dummy.focus(); }
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
void frame_sync();
|
void frame_sync();
|
||||||
bool on_encoder(const EncoderEvent event) override;
|
bool on_encoder(const EncoderEvent event) override;
|
||||||
@ -61,4 +160,4 @@ class TetrisView : public View {
|
|||||||
|
|
||||||
} // namespace ui::external_app::tetris
|
} // namespace ui::external_app::tetris
|
||||||
|
|
||||||
#endif /*__UI_TETRIS_H__*/
|
#endif /* __UI_TETRIS_H__ */
|
Loading…
x
Reference in New Issue
Block a user