Initial Version
This commit is contained in:
parent
57963ca706
commit
e29a23cc02
3 changed files with 363 additions and 0 deletions
46
VSCode/README
Normal file
46
VSCode/README
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
302
VSCode/main.cpp
Normal file
302
VSCode/main.cpp
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player 1: x = 0
|
||||||
|
* Player 2: x = X_MAX-1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIN_LED_MATRIX 2
|
||||||
|
#define PIN_JOYSTICK_1_BUTTON 6
|
||||||
|
#define PIN_JOYSTICK_2_BUTTON 7
|
||||||
|
#define PIN_PIEZO 11
|
||||||
|
#define PIN_JOYSTICK_1_Y A0
|
||||||
|
#define PIN_JOYSTICK_2_Y A1
|
||||||
|
|
||||||
|
#define JOYSTICK_OFFSET_MIN 200
|
||||||
|
#define JOYSTICK_OFFSET_MAX 700
|
||||||
|
|
||||||
|
#define DEBOUNCE_TIME 300 // in ms
|
||||||
|
|
||||||
|
#define X_MAX 10
|
||||||
|
#define Y_MAX 20
|
||||||
|
|
||||||
|
#define GAME_DELAY 80 // in ms
|
||||||
|
#define BALL_DELAY_MAX 350 // in ms
|
||||||
|
#define BALL_DELAY_MIN 50 // in ms
|
||||||
|
#define BALL_DELAY_STEP 5 // in ms
|
||||||
|
|
||||||
|
#define PLAYER_AMOUNT 2
|
||||||
|
#define PLAYER_1 0
|
||||||
|
#define PLAYER_2 1
|
||||||
|
|
||||||
|
#define PADDLE_WIDTH 3
|
||||||
|
|
||||||
|
#define PADDLE_MOVE_NONE 0
|
||||||
|
#define PADDLE_MOVE_UP 1
|
||||||
|
#define PADDLE_MOVE_DOWN 2
|
||||||
|
|
||||||
|
#define LED_TYPE_OFF 1
|
||||||
|
#define LED_TYPE_PADDLE 2
|
||||||
|
#define LED_TYPE_BALL 3
|
||||||
|
#define LED_TYPE_BALL_RED 4
|
||||||
|
|
||||||
|
#define TONE_PLAYER 1
|
||||||
|
#define TONE_WALL 2
|
||||||
|
#define TONE_BUZZ 3
|
||||||
|
|
||||||
|
#define GAME_STATE_RUNNING 1
|
||||||
|
#define GAME_STATE_END 2
|
||||||
|
#define GAME_STATE_INIT 3
|
||||||
|
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
|
||||||
|
struct Coords {
|
||||||
|
byte x;
|
||||||
|
byte y;
|
||||||
|
};
|
||||||
|
|
||||||
|
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(X_MAX * Y_MAX, PIN_LED_MATRIX, NEO_GRB + NEO_KHZ800);
|
||||||
|
bool buttonPressed = false;
|
||||||
|
byte gameState;
|
||||||
|
byte joystickPins[PLAYER_AMOUNT] = {PIN_JOYSTICK_1_Y, PIN_JOYSTICK_2_Y};
|
||||||
|
Coords paddles[PLAYER_AMOUNT][PADDLE_WIDTH];
|
||||||
|
Coords ball;
|
||||||
|
int ballMovement[2];
|
||||||
|
unsigned int ballDelay;
|
||||||
|
unsigned long lastDrawUpdate = 0;
|
||||||
|
unsigned long lastBallUpdate = 0;
|
||||||
|
unsigned long lastButtonClick = 0;
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
pinMode(PIN_JOYSTICK_1_Y, INPUT);
|
||||||
|
pinMode(PIN_JOYSTICK_1_BUTTON, INPUT_PULLUP);
|
||||||
|
pinMode(PIN_JOYSTICK_2_Y, INPUT);
|
||||||
|
pinMode(PIN_JOYSTICK_2_BUTTON, INPUT_PULLUP);
|
||||||
|
pixels.begin();
|
||||||
|
resetLEDs();
|
||||||
|
gameState = GAME_STATE_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
switch(gameState) {
|
||||||
|
case GAME_STATE_INIT:
|
||||||
|
initGame();
|
||||||
|
break;
|
||||||
|
case GAME_STATE_RUNNING:
|
||||||
|
updateBall();
|
||||||
|
updateGame();
|
||||||
|
break;
|
||||||
|
case GAME_STATE_END:
|
||||||
|
if (isButtonPressed()) {
|
||||||
|
gameState = GAME_STATE_INIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initGame()
|
||||||
|
{
|
||||||
|
resetLEDs();
|
||||||
|
lastButtonClick = millis();
|
||||||
|
|
||||||
|
ball.x = 1;
|
||||||
|
ball.y = (Y_MAX/2) - (PADDLE_WIDTH/2) + 1;
|
||||||
|
ballMovement[0] = 1;
|
||||||
|
ballMovement[1] = -1;
|
||||||
|
ballDelay = BALL_DELAY_MAX;
|
||||||
|
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
paddles[PLAYER_1][i].x = 0;
|
||||||
|
paddles[PLAYER_1][i].y = (Y_MAX/2) - (PADDLE_WIDTH/2) + i;
|
||||||
|
paddles[PLAYER_2][i].x = X_MAX - 1;
|
||||||
|
paddles[PLAYER_2][i].y = paddles[PLAYER_1][i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameState = GAME_STATE_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBall()
|
||||||
|
{
|
||||||
|
bool hitBall = false;
|
||||||
|
if ((millis() - lastBallUpdate) < ballDelay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastBallUpdate = millis();
|
||||||
|
toggleLed(ball.x, ball.y, LED_TYPE_OFF);
|
||||||
|
|
||||||
|
// collision detection for player 1
|
||||||
|
if (ballMovement[0] == -1 && ball.x == 1) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
if (paddles[PLAYER_1][i].y == ball.y) {
|
||||||
|
hitBall = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collision detection for player 2
|
||||||
|
if (ballMovement[0] == 1 && ball.x == X_MAX-2) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
if (paddles[PLAYER_2][i].y == ball.y) {
|
||||||
|
hitBall = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hitBall == true) {
|
||||||
|
ballMovement[0] *= -1;
|
||||||
|
playTone(TONE_PLAYER);
|
||||||
|
if (ballDelay > BALL_DELAY_MIN) {
|
||||||
|
ballDelay -= BALL_DELAY_STEP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ball.x += ballMovement[0];
|
||||||
|
ball.y += ballMovement[1];
|
||||||
|
|
||||||
|
if (ball.x <=0 || ball.x >= X_MAX-1) {
|
||||||
|
endGame();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ball.y <= 0 || ball.y >= Y_MAX-1) {
|
||||||
|
ballMovement[1] *= -1;
|
||||||
|
playTone(TONE_WALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLed(ball.x, ball.y, LED_TYPE_BALL);
|
||||||
|
pixels.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void endGame()
|
||||||
|
{
|
||||||
|
gameState = GAME_STATE_END;
|
||||||
|
toggleLed(ball.x, ball.y, LED_TYPE_BALL_RED);
|
||||||
|
pixels.show();
|
||||||
|
playTone(TONE_BUZZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateGame()
|
||||||
|
{
|
||||||
|
if ((millis() - lastDrawUpdate) < GAME_DELAY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastDrawUpdate = millis();
|
||||||
|
|
||||||
|
// turn off paddle LEDs
|
||||||
|
for(byte p=0; p<PLAYER_AMOUNT; p++) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
toggleLed(paddles[p][i].x, paddles[p][i].y, LED_TYPE_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move paddles
|
||||||
|
for(byte p=0; p<PLAYER_AMOUNT; p++) {
|
||||||
|
byte movement = getPlayerMovement(p);
|
||||||
|
if (movement == PADDLE_MOVE_UP && paddles[p][PADDLE_WIDTH-1].y < (Y_MAX-1)) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
paddles[p][i].y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (movement == PADDLE_MOVE_DOWN && paddles[p][0].y > 0) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
paddles[p][i].y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// show paddle LEDs
|
||||||
|
for(byte p=0; p<PLAYER_AMOUNT; p++) {
|
||||||
|
for(byte i=0; i<PADDLE_WIDTH; i++) {
|
||||||
|
toggleLed(paddles[p][i].x, paddles[p][i].y, LED_TYPE_PADDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pixels.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte getPlayerMovement(byte playerId)
|
||||||
|
{
|
||||||
|
int value = analogRead(joystickPins[playerId]);
|
||||||
|
if (value < JOYSTICK_OFFSET_MIN) {
|
||||||
|
if (playerId == PLAYER_2) {
|
||||||
|
return PADDLE_MOVE_DOWN;
|
||||||
|
} else {
|
||||||
|
return PADDLE_MOVE_UP;
|
||||||
|
}
|
||||||
|
} else if (value > JOYSTICK_OFFSET_MAX) {
|
||||||
|
if (playerId == PLAYER_2) {
|
||||||
|
return PADDLE_MOVE_UP;
|
||||||
|
} else {
|
||||||
|
return PADDLE_MOVE_DOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PADDLE_MOVE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isButtonPressed()
|
||||||
|
{
|
||||||
|
if ((millis() - lastButtonClick) < DEBOUNCE_TIME) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (digitalRead(PIN_JOYSTICK_1_BUTTON) == LOW) {
|
||||||
|
lastButtonClick = millis();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (digitalRead(PIN_JOYSTICK_2_BUTTON) == LOW) {
|
||||||
|
lastButtonClick = millis();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetLEDs()
|
||||||
|
{
|
||||||
|
for(byte i=0; i<X_MAX*Y_MAX; i++) {
|
||||||
|
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
|
||||||
|
}
|
||||||
|
pixels.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleLed(byte x, byte y, byte type)
|
||||||
|
{
|
||||||
|
byte ledIndex = y * X_MAX + x;
|
||||||
|
uint32_t color;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case LED_TYPE_PADDLE:
|
||||||
|
color = pixels.Color(0, 8, 8);
|
||||||
|
break;
|
||||||
|
case LED_TYPE_BALL_RED:
|
||||||
|
color = pixels.Color(12, 0, 0);
|
||||||
|
break;
|
||||||
|
case LED_TYPE_BALL:
|
||||||
|
color = pixels.Color(0, 10, 0);
|
||||||
|
break;
|
||||||
|
case LED_TYPE_OFF:
|
||||||
|
color = pixels.Color(0, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels.setPixelColor(ledIndex, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void playTone(byte type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case TONE_PLAYER:
|
||||||
|
tone(PIN_PIEZO, 440, 50);
|
||||||
|
break;
|
||||||
|
case TONE_WALL:
|
||||||
|
tone(PIN_PIEZO, 550, 50);
|
||||||
|
break;
|
||||||
|
case TONE_BUZZ:
|
||||||
|
for(byte i=0; i<20; i++) {
|
||||||
|
tone(PIN_PIEZO, 220-i*10, 50);
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
15
VSCode/platformio.ini
Normal file
15
VSCode/platformio.ini
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:uno]
|
||||||
|
platform = atmelavr
|
||||||
|
board = uno
|
||||||
|
framework = arduino
|
||||||
|
lib_deps = adafruit/Adafruit NeoPixel@^1.10.4
|
Loading…
Reference in a new issue