2021-08-18 17:26:51 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
#include "pico/stdlib.h"
|
|
|
|
|
|
|
|
#include "plasma2040.hpp"
|
|
|
|
|
|
|
|
#include "common/pimoroni_common.hpp"
|
|
|
|
#include "rgbled.hpp"
|
|
|
|
#include "button.hpp"
|
|
|
|
|
|
|
|
/*
|
|
|
|
****LED STRIP STACKER GAME****
|
|
|
|
Button a Begins game
|
|
|
|
|
|
|
|
push button when the red and yellow leds cross each other.
|
|
|
|
see how far you get...
|
|
|
|
by Gee 'Rabid Inventor' Bartlett
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
using namespace pimoroni;
|
2021-08-19 14:12:56 +01:00
|
|
|
using namespace plasma;
|
2021-08-18 17:26:51 +01:00
|
|
|
|
|
|
|
// Set how many LEDs you have
|
|
|
|
const uint N_LEDS = 40;
|
|
|
|
const uint REFRESH_DELAY = 100;
|
|
|
|
|
|
|
|
// Pick *one* LED type by uncommenting the relevant line below:
|
|
|
|
|
|
|
|
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
2021-08-19 14:12:56 +01:00
|
|
|
//APA102 led_strip(N_LEDS, pio0, 0, plasma2040::DAT, plasma2040::CLK);
|
2021-08-18 17:26:51 +01:00
|
|
|
|
|
|
|
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
|
|
|
// by default the WS2812 LED strip will be 400KHz, RGB with no white element
|
2021-08-19 14:12:56 +01:00
|
|
|
//WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT);
|
2021-08-18 17:26:51 +01:00
|
|
|
|
|
|
|
//Uncomment for WS2812 with RGBW running at 800KHz
|
2021-08-19 14:12:56 +01:00
|
|
|
WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT, 800000, true);
|
2021-08-18 17:26:51 +01:00
|
|
|
|
2021-08-19 14:12:56 +01:00
|
|
|
Button button_a(plasma2040::BUTTON_A, Polarity::ACTIVE_LOW, 50);
|
|
|
|
Button button_b(plasma2040::BUTTON_B, Polarity::ACTIVE_LOW, 50);
|
|
|
|
RGBLED led(plasma2040::LED_R, plasma2040::LED_G, plasma2040::LED_B);
|
2021-08-18 17:26:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
class playfield_object{
|
|
|
|
public:
|
|
|
|
uint8_t position = 0;
|
|
|
|
uint8_t length = 0;
|
|
|
|
int move_direction = 1;
|
|
|
|
uint8_t speed = 0;
|
|
|
|
uint8_t colour_R = 0;
|
|
|
|
uint8_t colour_G = 0;
|
|
|
|
uint8_t colour_B = 0;
|
|
|
|
int is_present_at(uint8_t test_position){
|
|
|
|
int ret = 0;
|
|
|
|
if (test_position >= position){
|
|
|
|
if (test_position <= position + length){
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class levels{
|
|
|
|
public:
|
|
|
|
uint8_t player_speed = 0;
|
|
|
|
uint8_t player_speed_increase_rate = 0;
|
|
|
|
bool moving_target = false;
|
|
|
|
uint8_t target_speed = 0;
|
|
|
|
uint8_t target_speed_increase_rate = 0;
|
|
|
|
bool moving_playfield = false;
|
|
|
|
uint8_t playfield_speed = 0;
|
|
|
|
uint8_t playfield_speed_increase_rate = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class StackerGame{
|
|
|
|
public:
|
|
|
|
enum states{
|
|
|
|
ATTRACT_MODE,
|
|
|
|
GAME_STARTED
|
|
|
|
};
|
|
|
|
levels begining_level;
|
|
|
|
uint8_t playfield_width;
|
|
|
|
int current_step = 0;
|
|
|
|
states game_state = ATTRACT_MODE;
|
|
|
|
int score = 0;
|
|
|
|
uint8_t game_speed = 0;
|
|
|
|
playfield_object player;
|
|
|
|
playfield_object target;
|
|
|
|
playfield_object left_wall;
|
|
|
|
playfield_object right_wall;
|
|
|
|
|
|
|
|
void start(levels game_level);
|
|
|
|
void reset(levels game_level);
|
|
|
|
void game_step();
|
|
|
|
void advance_round();
|
|
|
|
void stop();
|
|
|
|
};
|
|
|
|
|
|
|
|
void StackerGame::start(levels game_level){
|
|
|
|
game_state = ATTRACT_MODE;
|
|
|
|
begining_level = game_level;
|
|
|
|
playfield_width = N_LEDS;
|
|
|
|
player.position = 5;
|
|
|
|
player.length = 10;
|
|
|
|
target.position = 15;
|
|
|
|
target.length = 10;
|
|
|
|
left_wall.position = 0;
|
|
|
|
left_wall.length = 3;
|
|
|
|
right_wall.position = playfield_width - left_wall.length;
|
|
|
|
right_wall.length = left_wall.length;
|
|
|
|
player.speed = begining_level.player_speed;
|
|
|
|
target.speed = begining_level.target_speed;
|
|
|
|
|
|
|
|
//object colours
|
|
|
|
player.colour_R = 0;
|
|
|
|
player.colour_B = 0;
|
|
|
|
player.colour_G = 50;
|
|
|
|
|
|
|
|
target.colour_R = 50;
|
|
|
|
target.colour_G = 50;
|
|
|
|
target.colour_B = 0;
|
|
|
|
|
|
|
|
left_wall.colour_R = 0;
|
|
|
|
left_wall.colour_G = 0;
|
|
|
|
left_wall.colour_B = 50;
|
|
|
|
|
|
|
|
right_wall.colour_R = 0;
|
|
|
|
right_wall.colour_G = 0;
|
|
|
|
right_wall.colour_B = 50;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void StackerGame::reset(levels game_level){
|
|
|
|
begining_level = game_level;
|
|
|
|
playfield_width = N_LEDS;
|
|
|
|
player.position = 5;
|
|
|
|
player.length = 10;
|
|
|
|
target.position = 15;
|
|
|
|
target.length = 10;
|
|
|
|
left_wall.position = 0;
|
|
|
|
left_wall.length = 3;
|
|
|
|
right_wall.position = playfield_width - left_wall.length;
|
|
|
|
right_wall.length = left_wall.length;
|
|
|
|
player.speed = begining_level.player_speed;
|
|
|
|
target.speed = begining_level.target_speed;
|
|
|
|
begining_level.moving_target = false;
|
|
|
|
|
|
|
|
//object colours
|
|
|
|
player.colour_R = 0;
|
|
|
|
player.colour_B = 0;
|
|
|
|
player.colour_G = 50;
|
|
|
|
|
|
|
|
target.colour_R = 50;
|
|
|
|
target.colour_G = 50;
|
|
|
|
target.colour_B = 0;
|
|
|
|
|
|
|
|
left_wall.colour_R = 0;
|
|
|
|
left_wall.colour_G = 0;
|
|
|
|
left_wall.colour_B = 50;
|
|
|
|
|
|
|
|
right_wall.colour_R = 0;
|
|
|
|
right_wall.colour_G = 0;
|
|
|
|
right_wall.colour_B = 50;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void StackerGame::stop(){
|
|
|
|
sleep_ms(500);
|
|
|
|
game_state = ATTRACT_MODE;
|
|
|
|
reset(begining_level);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void StackerGame::advance_round(){
|
|
|
|
|
|
|
|
player.speed = player.speed + begining_level.player_speed_increase_rate;
|
|
|
|
|
|
|
|
if (player.speed > 240){ //higher level stuff
|
|
|
|
begining_level.moving_target = true;
|
|
|
|
player.speed = begining_level.player_speed;
|
|
|
|
target.speed = target.speed + begining_level.target_speed_increase_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void StackerGame::game_step(){
|
|
|
|
current_step++;
|
|
|
|
|
|
|
|
bool a = button_a.read();
|
|
|
|
|
|
|
|
if (game_state == GAME_STARTED){
|
|
|
|
if (a){
|
|
|
|
if (player.position == target.position)
|
|
|
|
{
|
|
|
|
advance_round();
|
|
|
|
}
|
|
|
|
else if (player.position < target.position ){
|
|
|
|
if (player.position + player.length >= target.position){
|
|
|
|
target.length = target.length - (target.position - player.position);
|
|
|
|
player.length = target.length;
|
|
|
|
sleep_ms(200);
|
|
|
|
advance_round();
|
|
|
|
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (player.position > target.position){
|
|
|
|
if(player.position < target.position + target.length){
|
|
|
|
|
|
|
|
target.length = target.length - (player.position - target.position);
|
|
|
|
target.position = player.position;
|
|
|
|
player.length = target.length;
|
|
|
|
sleep_ms(200);
|
|
|
|
advance_round();
|
|
|
|
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// aminate player and target ingame
|
|
|
|
if (player.position + player.length >= right_wall.position){
|
|
|
|
player.move_direction = -1;
|
|
|
|
}
|
|
|
|
if (player.position <= left_wall.position + left_wall.length){
|
|
|
|
player.move_direction = 1;
|
|
|
|
}
|
|
|
|
if (current_step % (254 - player.speed) == 0){
|
|
|
|
player.position += player.move_direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (begining_level.moving_target){
|
|
|
|
if (target.position + target.length >= right_wall.position){
|
|
|
|
target.move_direction = -1;
|
|
|
|
}
|
|
|
|
if (target.position <= left_wall.position + left_wall.length){
|
|
|
|
target.move_direction = 1;
|
|
|
|
}
|
|
|
|
if (current_step % (254 - target.speed) == 0){
|
|
|
|
target.position += target.move_direction;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (game_state == ATTRACT_MODE){
|
|
|
|
|
|
|
|
if (a){
|
|
|
|
game_state = GAME_STARTED;
|
|
|
|
reset(begining_level);
|
|
|
|
sleep_ms(2000);
|
|
|
|
}
|
|
|
|
|
|
|
|
// aminate player and target attract mode
|
|
|
|
if (player.position + player.length >= right_wall.position){
|
|
|
|
player.move_direction = -1;
|
|
|
|
}
|
|
|
|
if (player.position <= left_wall.position + left_wall.length){
|
|
|
|
player.move_direction = 1;
|
|
|
|
}
|
|
|
|
if (current_step % (254 - 150) == 0){
|
|
|
|
player.position += player.move_direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (target.position + target.length >= right_wall.position){
|
|
|
|
target.move_direction = -1;
|
|
|
|
}
|
|
|
|
if (target.position <= left_wall.position + left_wall.length){
|
|
|
|
target.move_direction = 1;
|
|
|
|
}
|
|
|
|
if (current_step % (254 - 50) == 0){
|
|
|
|
target.position += target.move_direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
stdio_init_all();
|
|
|
|
|
|
|
|
led_strip.start(60);
|
|
|
|
|
|
|
|
|
|
|
|
StackerGame stacker; // create instance of stacker game
|
|
|
|
|
|
|
|
//create level instance this is where you can adjust beginning dificulty
|
|
|
|
levels level_1;
|
|
|
|
level_1.player_speed = 70;
|
|
|
|
level_1.player_speed_increase_rate = 10;
|
|
|
|
level_1.moving_target = false;
|
|
|
|
level_1.target_speed = 20;
|
|
|
|
level_1.target_speed_increase_rate = 10;
|
|
|
|
|
|
|
|
stacker.start(level_1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
//do game loop
|
|
|
|
stacker.game_step();
|
|
|
|
|
|
|
|
if (stacker.game_state == stacker.ATTRACT_MODE){
|
|
|
|
bool a = button_a.read();
|
|
|
|
if (a){
|
|
|
|
|
|
|
|
stacker.game_state = stacker.GAME_STARTED;
|
|
|
|
stacker.start(level_1);
|
|
|
|
sleep_ms(2000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// leds update routine
|
|
|
|
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
|
|
|
|
|
|
|
if (stacker.target.is_present_at(i)){
|
|
|
|
led_strip.set_rgb(i, stacker.target.colour_R, stacker.target.colour_G, stacker.target.colour_B);
|
|
|
|
|
|
|
|
if (stacker.player.is_present_at(i)){
|
|
|
|
led_strip.set_rgb(i, stacker.target.colour_R - stacker.player.colour_R,
|
|
|
|
stacker.target.colour_G - stacker.player.colour_G,
|
|
|
|
stacker.target.colour_B - stacker.player.colour_B);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (stacker.player.is_present_at(i)){
|
|
|
|
led_strip.set_rgb(i, stacker.player.colour_R, stacker.player.colour_G, stacker.player.colour_B);
|
|
|
|
}
|
|
|
|
else if (stacker.left_wall.is_present_at(i)){
|
|
|
|
led_strip.set_rgb(i, stacker.left_wall.colour_R, stacker.left_wall.colour_G, stacker.left_wall.colour_B);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (stacker.right_wall.is_present_at(i)){
|
|
|
|
led_strip.set_rgb(i, stacker.right_wall.colour_R, stacker.right_wall.colour_G, stacker.right_wall.colour_B);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
led_strip.set_rgb(i, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sleep time controls the rate at which the LED buffer is updated
|
|
|
|
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
|
|
|
sleep_ms(1);
|
|
|
|
}
|
|
|
|
}
|