Skip to content

Commit a7be4f4

Browse files
authored
Merge pull request #1 from m5stack/master
update
2 parents f3f246a + 3942a67 commit a7be4f4

31 files changed

+78358
-156576
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ https://docs.m5stack.com/#/en/api
7979

8080
* [GUIslice](https://github.com/ImpulseAdventure/GUIslice) - A lightweight GUI framework suitable for embedded displays
8181

82-
* [M5ez](https://github.com/ropg/M5ez) - The easy way to program on the M5Stack
82+
* [M5ez](https://github.com/M5ez/M5ez) - The easy way to program on the M5Stack
8383

8484

8585
* [M5Stack MultiApp Advanced](https://github.com/botofancalin/M5Stack-MultiApp-Advanced) - A M5Stack firmware made on PlatformIO

examples/Advanced/Display_Unicode/CUF_24px.h

Lines changed: 76676 additions & 156295 deletions
Large diffs are not rendered by default.

examples/Advanced/Display_Unicode/Display_Unicode.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void setup()
2626
M5.begin();
2727

2828
M5.Lcd.setTextColor(TFT_WHITE);
29-
M5.Lcd.setFreeFont(&CUF_24px);
29+
M5.Lcd.setFreeFont(&unicode_24px);
3030

3131

3232
M5.Lcd.setTextDatum(TC_DATUM);

examples/Basics/Button/Button.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ void loop() {
3434
M5.update();
3535

3636
// if you want to use Releasefor("was released for"), use .wasReleasefor(int time) below
37-
if (M5.BtnA.wasReleased()) {
37+
if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
3838
M5.Lcd.print('A');
39-
} else if (M5.BtnB.wasReleased()) {
39+
} else if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000, 200)) {
4040
M5.Lcd.print('B');
41-
} else if (M5.BtnC.wasReleased()) {
41+
} else if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000, 200)) {
4242
M5.Lcd.print('C');
4343
} else if (M5.BtnB.wasReleasefor(700)) {
4444
M5.Lcd.clear(BLACK);

examples/Basics/PowerOFF/PowerOFF.ino

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ void setup(){
1414
M5.Power.begin();
1515

1616
// Lcd display
17-
M5.Lcd.println("This is software power off demo");
18-
M5.Lcd.println("Press the button A to power off.");
17+
M5.Lcd.setTextSize(2);
18+
M5.Lcd.println("Software Power-OFF Demo");
19+
M5.Lcd.println("Press Button A ...");
1920
}
2021

2122
// the loop routine runs over and over again forever
2223
void loop() {
2324

2425
if(M5.BtnA.wasPressed()) {
25-
M5.powerOFF();
26+
M5.Power.powerOFF();
2627
}
2728

2829
M5.update();
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/******************************************************************************
2+
* M5Snake : Game board management *
3+
* ------------------------------- *
4+
* Manage the game board (storage in memory and display *
5+
* Author: Olivier Staquet *
6+
* Last version available on https://github.com/ostaquet/M5Snake *
7+
*****************************************************************************/
8+
#include "GameBoard.h"
9+
10+
/**
11+
* Initialize
12+
*/
13+
void GameBoardClass::begin(uint8_t _max_game_cycles) {
14+
// Keep the number of game cycles
15+
max_game_cycles = _max_game_cycles;
16+
current_game_cycle = 0;
17+
18+
// Init the board at blank
19+
for(uint8_t x = 0; x < board_width; x++) {
20+
for(uint8_t y = 0; y < board_height; y++) {
21+
board_data[x][y] = BLOCK_STATUS_EMPTY;
22+
board_changes[x][y] = 0;
23+
}
24+
}
25+
26+
// Set screen to blank
27+
M5.Lcd.fillScreen(BLACK);
28+
}
29+
30+
/**
31+
* Refresh display
32+
*/
33+
void GameBoardClass::refresh() {
34+
// Check where there are some changes
35+
for(uint8_t x = 0; x < board_width; x++) {
36+
for(uint8_t y = 0; y < board_height; y++) {
37+
// Check the cell
38+
if(board_changes[x][y] > 0) {
39+
// There is a change...
40+
drawChange(x, y);
41+
// Reset the change tracking
42+
board_changes[x][y] = 0;
43+
}
44+
}
45+
}
46+
}
47+
48+
/**
49+
* Put the head of the snake on the board and go on right
50+
*/
51+
void GameBoardClass::startSnake() {
52+
// Define the middle of the screen
53+
setCell(board_width / 2, board_height / 2, BLOCK_STATUS_HEAD);
54+
55+
// Define the direction
56+
setDirection(DIRECTION_RIGHT);
57+
}
58+
59+
/**
60+
* Make the snake move on the board
61+
* Return boolean true if OK, false if game over
62+
*/
63+
bool GameBoardClass::moveSnake() {
64+
// Check if it is a cycle to move
65+
if(current_game_cycle < max_game_cycles) {
66+
// Wait for the next cycle
67+
current_game_cycle++;
68+
return true;
69+
} else {
70+
// Reset the game cycle
71+
current_game_cycle = 0;
72+
}
73+
74+
// Add 1 to all current block with between 1 and 512
75+
// to keep count of the movement of the snake (1 = head, 2 = 2nd block after head...)
76+
for(uint8_t x = 0; x < board_width; x++) {
77+
for(uint8_t y = 0; y < board_height; y++) {
78+
if(board_data[x][y] < BLOCK_STATUS_CHERRY && board_data[x][y] != BLOCK_STATUS_EMPTY) {
79+
board_data[x][y] = board_data[x][y] + 1;
80+
}
81+
}
82+
}
83+
84+
// Next move to be defined
85+
int8_t next_block_x = current_head_x;
86+
int8_t next_block_y = current_head_y;
87+
88+
// Define the next move of the head
89+
switch(current_direction) {
90+
case DIRECTION_UP :
91+
next_block_y = current_head_y - 1;
92+
break;
93+
case DIRECTION_RIGHT :
94+
next_block_x = current_head_x + 1;
95+
break;
96+
case DIRECTION_DOWN :
97+
next_block_y = current_head_y + 1;
98+
break;
99+
case DIRECTION_LEFT :
100+
next_block_x = current_head_x - 1;
101+
break;
102+
}
103+
104+
// Check if the move is valid...
105+
// Check the limit of the board for X
106+
if(next_block_x < 0 || next_block_x >= board_width) {
107+
return false;
108+
}
109+
// Check the limit of the board for Y
110+
if(next_block_y < 0 || next_block_y >= board_height) {
111+
return false;
112+
}
113+
114+
// Check if there is a cherry on the cell (if not a cherry, remove the last block of the tail
115+
if(board_data[next_block_x][next_block_y] != BLOCK_STATUS_CHERRY) {
116+
removeTail();
117+
}
118+
119+
// Check if there is another part of the snake
120+
if(board_data[next_block_x][next_block_y] > BLOCK_STATUS_EMPTY && board_data[next_block_x][next_block_y] < BLOCK_STATUS_CHERRY) {
121+
return false;
122+
}
123+
124+
// OK, move the head of the snake
125+
setCell(next_block_x, next_block_y, BLOCK_STATUS_HEAD);
126+
127+
return true;
128+
}
129+
130+
/**
131+
* Identify and remove the tail (last block of the snake)
132+
*/
133+
void GameBoardClass::removeTail() {
134+
uint16_t greatest_value = 0;
135+
uint8_t tail_x = 0;
136+
uint8_t tail_y = 0;
137+
138+
// Find the cell with the biggest value (it is the tail)
139+
for(uint8_t x = 0; x < board_width; x++) {
140+
for(uint8_t y = 0; y < board_height; y++) {
141+
if(board_data[x][y] < BLOCK_STATUS_CHERRY) {
142+
if(board_data[x][y] > greatest_value) {
143+
tail_x = x;
144+
tail_y = y;
145+
greatest_value = board_data[x][y];
146+
}
147+
}
148+
}
149+
}
150+
151+
// Remove the tail
152+
setCell(tail_x, tail_y, BLOCK_STATUS_EMPTY);
153+
}
154+
155+
/**
156+
* Get the max score
157+
*/
158+
uint16_t GameBoardClass::getMaxScore() {
159+
uint16_t greatest_value = 0;
160+
161+
// Find the cell with the biggest value (it is the tail)
162+
for(uint8_t x = 0; x < board_width; x++) {
163+
for(uint8_t y = 0; y < board_height; y++) {
164+
if(board_data[x][y] < BLOCK_STATUS_CHERRY) {
165+
if(board_data[x][y] > greatest_value) {
166+
greatest_value = board_data[x][y];
167+
}
168+
}
169+
}
170+
}
171+
172+
return greatest_value - 1;
173+
}
174+
175+
/**
176+
* Draw the change of one cell
177+
*/
178+
void GameBoardClass::drawChange(uint8_t x, uint8_t y) {
179+
// Compute box position
180+
uint16_t pos_x = x * BLOCK_SIZE;
181+
uint16_t pos_y = y * BLOCK_SIZE;
182+
183+
// Depending on the content of the cell, draw the box
184+
switch(board_data[x][y]) {
185+
case BLOCK_STATUS_EMPTY :
186+
M5.Lcd.fillRect(pos_x, pos_y, BLOCK_SIZE, BLOCK_SIZE, BLACK);
187+
break;
188+
189+
case BLOCK_STATUS_CHERRY :
190+
M5.Lcd.fillRect(pos_x, pos_y, BLOCK_SIZE, BLOCK_SIZE, BLACK);
191+
M5.Lcd.fillCircle(pos_x + BLOCK_SIZE / 2, pos_y + BLOCK_SIZE / 2, BLOCK_SIZE / 2 - 1, RED);
192+
break;
193+
194+
default :
195+
M5.Lcd.drawRect(pos_x, pos_y, BLOCK_SIZE, BLOCK_SIZE, BLACK);
196+
M5.Lcd.fillRect(pos_x + 1, pos_y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2, WHITE);
197+
break;
198+
}
199+
}
200+
201+
/**
202+
* Add a ramdom cherry on the board
203+
*/
204+
void GameBoardClass::addCherry() {
205+
uint8_t pos_x = random(0, board_width);
206+
uint8_t pos_y = random(0, board_height);
207+
208+
while(board_data[pos_x][pos_y] != BLOCK_STATUS_EMPTY) {
209+
pos_x = random(0, board_width);
210+
pos_y = random(0, board_height);
211+
}
212+
213+
setCell(pos_x, pos_y, BLOCK_STATUS_CHERRY);
214+
}
215+
216+
/**
217+
* Set direction
218+
*/
219+
void GameBoardClass::setDirection(uint8_t direction) {
220+
current_direction = direction;
221+
}
222+
223+
/**
224+
* Set a value in a cell
225+
*/
226+
void GameBoardClass::setCell(uint8_t x, uint8_t y, uint16_t status) {
227+
board_data[x][y] = status;
228+
board_changes[x][y] = 1;
229+
230+
if(status == BLOCK_STATUS_HEAD) {
231+
current_head_x = x;
232+
current_head_y = y;
233+
}
234+
}
235+
236+
GameBoardClass GameBoard;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/******************************************************************************
2+
* M5Snake : Game board management *
3+
* ------------------------------- *
4+
* Manage the game board (storage in memory and display *
5+
* Author: Olivier Staquet *
6+
* Last version available on https://github.com/ostaquet/M5Snake *
7+
*****************************************************************************/
8+
#ifndef _GAMEBOARD_H_
9+
#define _GAMEBOARD_H_
10+
11+
#include <Arduino.h>
12+
#include <M5Stack.h>
13+
14+
#define LCD_WIDTH 320
15+
#define LCD_HEIGHT 240
16+
17+
#define BLOCK_SIZE 16
18+
19+
#define BLOCK_STATUS_EMPTY 0x00 // Empty block
20+
#define BLOCK_STATUS_HEAD 0x01 // Head of the snake
21+
// All values between 2 and 511 // Body of the snake, greatest value = tail
22+
#define BLOCK_STATUS_CHERRY 0x200 // Cherry to increase the size of the snake
23+
24+
#define DIRECTION_UP 0x01
25+
#define DIRECTION_RIGHT 0x02
26+
#define DIRECTION_DOWN 0x03
27+
#define DIRECTION_LEFT 0x04
28+
29+
class GameBoardClass {
30+
public:
31+
// Initialize
32+
void begin(uint8_t game_cycles = 4);
33+
34+
// Refresh display
35+
void refresh();
36+
37+
// Start the snake
38+
void startSnake();
39+
40+
// Make the snake move on the board
41+
// Return boolean true if OK, false if game over
42+
bool moveSnake();
43+
44+
// Set direction
45+
void setDirection(uint8_t direction);
46+
47+
// Add a ramdom cherry on the board
48+
void addCherry();
49+
50+
// Get the max score
51+
uint16_t getMaxScore();
52+
53+
private:
54+
// Variables
55+
56+
// Current direction
57+
uint8_t current_direction = 0x00;
58+
uint8_t current_head_x = 0x00;
59+
uint8_t current_head_y = 0x00;
60+
61+
// Cycles
62+
uint8_t max_game_cycles = 4;
63+
uint8_t current_game_cycle = 0;
64+
65+
// Keep track of the size of the board
66+
uint8_t board_width = LCD_WIDTH / BLOCK_SIZE;
67+
uint8_t board_height = LCD_HEIGHT / BLOCK_SIZE;
68+
69+
// Game board in memory
70+
uint16_t board_data[LCD_WIDTH / BLOCK_SIZE][LCD_HEIGHT / BLOCK_SIZE];
71+
72+
// Track change of the game board to optimize refresh
73+
uint8_t board_changes[LCD_WIDTH / BLOCK_SIZE][LCD_HEIGHT / BLOCK_SIZE];
74+
75+
76+
// Internal functions
77+
// Set a value in a cell
78+
void setCell(uint8_t x, uint8_t y, uint16_t status);
79+
80+
// Draw a cell with the change indicated
81+
void drawChange(uint8_t x, uint8_t y);
82+
83+
// Remove the tail of the snake (put the biggest cell at blank)
84+
void removeTail();
85+
};
86+
87+
extern GameBoardClass GameBoard;
88+
89+
#endif // _GAMEBOARD_H_

0 commit comments

Comments
 (0)