1 / 2
Health Bar for Magic: The Gathering — zdjęcie 1
1 / 2

Health Bar for Magic: The Gathering

Zamów wydruk tego modelu

Obliczymy ostateczną cenę na podstawie wybranego pliku. Sprawdzisz ją i zaakceptujesz przed płatnością.

Zapisane na tym urządzeniu.

It's an electronic health-bar life point counter that I use for playing Magic, definitely cooler than ur average D20

Ocena
0 / 5
Polubienia
13
Pobrania
15
Wydruki
0
Wyświetlenia
1229
Oceny
0

Aktualizacja u źródła:

Informacje o modelu

Źródło
Printables
Licencja
Creative Commons — Attribution — Noncommercial

See here for a video on how it looks like when it's working:
https://www.instagram.com/p/DC7ZvZqqY5L/?igsh=ZG85azRucWNyZ2Ry 

Also, DM me there for questions.

 

Description: 
I made a health bar style life counter for MtG using an Adafruit Trinket M0 (any controller would do tho, I just don't think any other would fit inside my case).

Parts and assembly:

I've used 2x20 Adafruit NeoPixel LED strips (144/m because it's a pretty tight design).

You will also need a rotary encoder (I've used a 318-ENC130175F-12PS, the data sheet says REF. TW-700198 as well, image attached). 
Just solder the data pin of the two strips to pins 3 and 4 of the Trinket M0.
The CLK and DT pins (the left and right of the 3 upfront) of the rotary encoder need to go to pins 0 and 2 respectively, while the SW pin (the left one of the two on the back for the button click) should go to pin 1.
The other two pins would need to go to ground, since I've coded pull-up resistors on all of them. 
I've used a 5V usb cable (any power bank or usb to power socket on the other end will do) and soldered it directly to the breadboard of the Trinket M0.
I'd recommend soldering the trinket on one side and the rotary encoder on the other.

I've used a small Adafruit half breadboard, it pretty much exactly fits inside the dimensions of the body.

To close the thing, I've used 3 M3 countersunk screws (16mm long) and 3 M3 nuts, which you can push inside the case on each side.

The .stls labelled “small” are optional, I've used these to fill in the marks on top of the case, but you can also just color these in if you like. 

 

I've printed everything at 0.2mm on a Prusa MK4 with Prusament PETG. 

How does it work:

You just spin the rotary encoder to increase / decrease each players life total.
If you click the rotary button, you switch the player (i.e. which LED strip is affected).

Here you can find my code: 
 

#include <Adafruit_NeoPixel.h>

// Rotary Encoder Inputs #define CLK 0 #define DT 2 #define SW 1 #define LED_PIN_1 3 #define LED_PIN_2 4

bool whichPlayer = false; int lifeTotalOne = 20; int lifeTotalTwo = 20; int counter = 0; int currentStateCLK; int lastStateCLK; uint32_t curColors[20]; String currentDir ="";

Adafruit_NeoPixel strip1(20, LED_PIN_1, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel strip2(20, LED_PIN_2, NEO_GRB + NEO_KHZ800);

unsigned long lastButtonPress = 0;

//base color array #include <cstdint>

uint32_t base_colors[20] = { 0xB20000, // Strong Red 0xB21300, 0xB22600, 0xB24700, 0xB25900, 0xB26B00, 0xB27E00, 0xB29000, 0xB2A300, // Yellowish Red 0xB2B300, // Yellow 0x99B300, // Greenish Yellow 0x8FB300, 0x7AB300, 0x6EB300, 0x59B300, 0x4CB300, 0x3FB300, 0x33B300, 0x26B300, 0x00B200 // Strong Green };

uint32_t green_to_blue[20] = { 0x00B200, // Strong Green 0x00B213, 0x00B226, 0x00A313, // Midpoint: Blue-Green 0x00B23F, 0x00B259, 0x00A326, 0x008F3F, 0x007359, 0x00B26B, 0x00B27E, 0x00B290, 0x00B2A3, 0x00B2B5, // Light Green 0x005959, // Transition to blue-green 0x004C66, 0x003373, 0x002680, 0x001399, 0x0000B2 // Strong Blue };

uint32_t blue_to_purple[20] = { 0x0000B2, 0x0500B2, 0x0A00B2, 0x1000B2, 0x1400B2, 0x1900B2, 0x1E00B2, 0x2300B2, 0x2800B2, 0x2D00B2, 0x3200B2, 0x3800B2, 0x3C00B2, 0x4100B2, 0x4600B2, 0x4B00B2, 0x5000B2, 0x5500B2, 0x5A00B2, 0x6100B2 // Light Violet };

uint32_t purple_to_orange[20] = { 0x6100B2, // Deep Violet 0x6C00A9, // Violet 0x76009F, // Violet-Purple 0x860096, // Purple 0x93008C, // Purple-Pink 0x9E0083, // Pinkish Purple 0xA60078, // Pink-Magenta 0xB2006B, // Magenta 0xB21366, // Magenta-Red 0xB23359, // Red-Orange 0xB24C4D, // Bright Red-Orange 0xB25940, // Rich Orange-Red 0xB26B33, // Deep Orange 0xB26B33, // Vibrant Orange 0xB27E33, // Bright Orange 0xB2A33F, // Yellowish Orange 0xB2B23F, // Orange-Yellow 0xB2B539, // Warm Yellow-Orange 0xB2B239, // Bright Warm Yellow 0xB26F38 // Strong Orange };

void setup() {

// Set encoder pins as inputs pinMode(CLK,INPUT_PULLUP); pinMode(DT,INPUT_PULLUP); pinMode(SW, INPUT_PULLUP);

// Setup Serial Monitor Serial.begin(9600);

// Read the initial state of CLK lastStateCLK = digitalRead(CLK); strip1.begin(); strip1.show(); // Initialize all pixels to 'off' strip2.begin(); strip2.show(); // Initialize all pixels to 'off' //strip1.setBrightness(200); //strip2.setBrightness(200);

updateStrips(); }

void loop() {

// Read the current state of CLK currentStateCLK = digitalRead(CLK);

// If last and current state of CLK are different, then pulse occurred // React to only 1 state change to avoid double count if (currentStateCLK != lastStateCLK && currentStateCLK == 1){

// If the DT state is different than the CLK state then // the encoder is rotating CCW so decrement if (digitalRead(DT) != currentStateCLK) { counter --; currentDir ="CCW"; if(!whichPlayer){ lifeTotalOne--; }else{ lifeTotalTwo--; }

} else { // Encoder is rotating CW so increment counter ++; currentDir ="CW"; if(!whichPlayer){ lifeTotalOne++; }else{ lifeTotalTwo++; } } updateStrips(); //Serial.print("Direction: "); //Serial.print(currentDir); //Serial.print(" | Counter: "); //Serial.println(counter); }

// Remember last CLK state lastStateCLK = currentStateCLK;

// Read the button state int btnState = digitalRead(SW);

//If we detect LOW signal, button is pressed if (btnState == LOW) { //if 50ms have passed since last LOW pulse, it means that the //button has been pressed, released and pressed again if (millis() - lastButtonPress > 50) { //Serial.println("Button pressed!");

  if(whichPlayer){
      whichPlayer = false;
  }else{
    whichPlayer = true;
  }
  indicatePlayer();

}

// Remember last button press event lastButtonPress = millis(); }

// Put in a slight delay to help debounce the reading delay(1); }

void indicatePlayer(){ if(whichPlayer){ for(int i = 0; i < 20; i++){ curColors[i] = strip2.getPixelColor(i); } for(int i = 0; i < 10; i++){ strip2.setPixelColor(19-i, 0x00DDAA); strip2.setPixelColor(i, 0x00DDAA); strip2.show(); delay(20); } for(int i = 0; i < 10; i++){ strip2.setPixelColor(19-i, curColors[19-i]); strip2.setPixelColor(i, curColors[i]); strip2.show(); delay(20); } }else{ for(int i = 0; i < 20; i++){ curColors[i] = strip1.getPixelColor(i); } for(int i = 0; i < 10; i++){ strip1.setPixelColor(19-i, 0x00DDAA); strip1.setPixelColor(i, 0x00DDAA); strip1.show(); delay(20); } for(int i = 0; i < 10; i++){ strip1.setPixelColor(19-i, curColors[19-i]); strip1.setPixelColor(i, curColors[i]); strip1.show(); delay(20); } } }

void updateStrips(){

// below 20 if(lifeTotalOne <=20){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, 0x000000); } for(int i = 0; i < lifeTotalOne; i++){ strip1.setPixelColor(i, base_colors[i]); } Serial.print("<=20 | LifeTotalOne: "); Serial.println(lifeTotalOne); } strip1.show();

if(lifeTotalTwo <=20){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, 0x000000); } for(int i = 0; i < lifeTotalTwo; i++){ strip2.setPixelColor(i, base_colors[i]); } } strip2.show();

//between 20 and 40 if(lifeTotalOne >20 && lifeTotalOne <=40 ){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, 0x000000); }

if((lifeTotalOne%20)==0){
  for(int i = 0; i &lt; 20; i++){
    strip1.setPixelColor(i, green_to_blue[i]);
  }
}else{
  for(int i = 0; i &lt; (lifeTotalOne%20); i++){
    strip1.setPixelColor(i, green_to_blue[i]);
  }
}

} strip1.show();

if(lifeTotalTwo >20 && lifeTotalTwo <=40 ){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, 0x000000); } if((lifeTotalTwo%20)==0){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, green_to_blue[i]); } }else{ for(int i = 0; i < (lifeTotalTwo%20); i++){ strip2.setPixelColor(i, green_to_blue[i]); } }

} strip2.show();

//between 40 and 60 if(lifeTotalOne >40 && lifeTotalOne <=60 ){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, 0x000000); } if((lifeTotalOne%20)==0){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, blue_to_purple[i]); } }else{ for(int i = 0; i < (lifeTotalOne%20); i++){ strip1.setPixelColor(i, blue_to_purple[i]); } }

Serial.print("&gt;20 | LifeTotalOne: ");

Serial.println(lifeTotalOne); } strip1.show();

if(lifeTotalTwo >40 && lifeTotalTwo <=60 ){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, 0x000000); } if((lifeTotalTwo%20)==0){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, blue_to_purple[i]); } }else{ for(int i = 0; i < (lifeTotalTwo%20); i++){ strip2.setPixelColor(i, blue_to_purple[i]); } } } strip2.show();

// between 60 and 80 if(lifeTotalOne >60 && lifeTotalOne <=80 ){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, 0x000000); } if((lifeTotalOne%20)==0){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, purple_to_orange[i]); } }else{ for(int i = 0; i < (lifeTotalOne%20); i++){ strip1.setPixelColor(i, purple_to_orange[i]); } }

Serial.print("&gt;20 | LifeTotalOne: ");

Serial.println(lifeTotalOne); } strip1.show();

if(lifeTotalTwo >60 && lifeTotalTwo <=80 ){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, 0x000000); } if((lifeTotalTwo%20)==0){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, purple_to_orange[i]); } }else{ for(int i = 0; i < (lifeTotalTwo%20); i++){ strip2.setPixelColor(i, purple_to_orange[i]); } } } strip2.show();

// above 80 if(lifeTotalOne >80){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, 0x000000); } if((lifeTotalOne%20)==0){ for(int i = 0; i < 20; i++){ strip1.setPixelColor(i, purple_to_orange[19]); } }else{ for(int i = 0; i < (lifeTotalOne%20); i++){ strip1.setPixelColor(i, purple_to_orange[19]); } }

Serial.print("&gt;20 | LifeTotalOne: ");

Serial.println(lifeTotalOne); } strip1.show();

if(lifeTotalTwo >80){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, 0x000000); } if((lifeTotalTwo%20)==0){ for(int i = 0; i < 20; i++){ strip2.setPixelColor(i, purple_to_orange[19]); } }else{ for(int i = 0; i < (lifeTotalTwo%20); i++){ strip2.setPixelColor(i, purple_to_orange[19]); } } } strip2.show();

}

Tagi