Infrared selected switch statement using Arduino and Neopixels - c++

I'm having some problems putting the finishing touches on the latest project. The Idea is to have an Infrared receiver mounted on a single Arduino Uno, taking ques from a remote to select preprogramed patterns on a Neopixel strip (selection from the Neopixel Strand test)
Here is my code
//Always comment your code like a violent psychopath will be maintaining it and they know where you live
#include <Adafruit_NeoPixel.h> //Neopixel Library
#include <IRLibAll.h> //IR reciever Library
IRrecvLoop myReceiver(2); //IR receiver on IO pin 2
IRdecode myDecoder; //Decoder object
unsigned long oldCode = 00000000; //Comparison variable to evaluate the execution of the 'Check' function later
Adafruit_NeoPixel strip (3,3,NEO_RGBW + NEO_KHZ800); //Creates the Pixel strip as an object in the code
void setup() {
strip.begin(); //Initialise the Neopixel strip
strip.show(); //Initialise all pixels to 'off'
myReceiver.enableIRIn(); // Start the IR receiver
}
void loop() {
check(); //Run the check function
delay(20); //Delay before running the loop again by 20 milliseconds giving time to recieve signals
}
void check() { //check Function: Checks for an IR signal before nominating which of the test displays to run
if (oldCode = myDecoder.value){ //Evaluates if the IR code recieved from the remote matches 'oldCode' and if it does....
return; //Terminates the check Function returning its values
}
if (myReceiver.getResults()) {
myDecoder.decode();
if (myDecoder.protocolNum == NEC) {
switch(myDecoder.value) { //Activate this switch statement based on the value 'myDecoder' holds
case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF6897:
colorWipe(strip.Color( 0, 0, 0), 50); // Black/off "0"
Serial.println("0 - Black/off");
break;
case 0xFF30CF:
colorWipe(strip.Color(255, 0, 0), 50); // Red "1"
Serial.println("1 - All red");
break;
case 0xFF18E7:
colorWipe(strip.Color( 0, 255, 0), 50); // Green "2"
Serial.println("2 - All green");
break;
case 0xFF7A85:
colorWipe(strip.Color( 0, 0, 255), 50); // Blue "3"
Serial.println("3 - All blue");
break;
case 0xFF10EF:
theaterChase(strip.Color(127, 127, 127), 50); // White "4"
Serial.println("4 - All white");
break;
case 0xFF38C7:
theaterChase(strip.Color(127, 0, 0), 50); // Red "5"
Serial.println("5");
break;
case 0xFF5AA5:
theaterChase(strip.Color( 0, 0, 127), 50); // Blue "6"
Serial.println("6");
break;
case 0xFF42BD:
rainbow(10); // "7"
Serial.println("7");
break;
case 0xFF4AB5:
theaterChaseRainbow(50); // "8"
Serial.println("8");
break;
case 0xFF52AD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFFFFFFF: Serial.println("Please release button and reselect"); break;
}
}
oldCode = myDecoder.value; //make the new button state equal the old buttonstate preventing the button from activating if statement
}
}
void colorWipe(uint32_t color, int wait) { //Colour wipe test
while(true) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
check();
delay(wait); // Pause for a moment
}
}
}
void theaterChase(uint32_t color, int wait) { //Theatre Chase test
while(true) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
for(int c=b; c<strip.numPixels(); c += 3) { // 'c' counts up from 'b' to end of strip in steps of 3...
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
check(); //Run the check function
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
}
void rainbow(int wait) { //Rainbow test function
while(true) { //while this function is active
for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) { //Sets differing colours for the rainbow
for(int i=0; i<strip.numPixels(); i++) { //For each pixel in strip...
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); //balances the colour pattern along the length of the strip
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); //run the colour pattern along the strip
check(); //run the check function
}
strip.show(); //Update strip with new contents
delay(wait); //Pause for a moment
}
}
}
void theaterChaseRainbow(int wait) {
while(true) {
int firstPixelHue = 0; //First pixel starts at red
for(int a=0; a<30; a++) { //Repeat 30 times...
for(int b=0; b<3; b++) { //'b' counts from 0 to 2...
strip.clear(); //Set all pixels to off
for(int c=b; c<strip.numPixels(); c += 3) { //'c' counts up from 'b' to end of strip in increments of 3, hue of pixel 'c' is offset by an amount to make one full revolution of the color wheel (range 65536) along the length of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels(); //create the hue variable and balance the rainbow colouring across the strip
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
check(); //Run the check function
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
}
The Problems
I have tried to write a loop that uses a class call to decide what is going on ("check"), I have also written another version where the switch statement is place in the loop instead. The problem from what I understand is that the IR input cannot receive whilst the loop is running (as it cannot interrupt) yet the test patterns will not play unless the loop is running. I have looked at solutions that involve using two Arduino's with either one running IR and the Neopixel respectively but unfortunately this will not match up with my brief - I need to have it running on one Arduino.
Any ideas?

For those who are interested - the final code to this project was...
//Always comment your code like it will be maintained by a violent psychopath who knows where you live.
#include <IRLibAll.h> //Infra Red Library
#include <Adafruit_NeoPixel.h> //Adafruit NeoPixel Library
//======== Constants =============
const int LEDpin = 3; //IO pin for the LED strip
const int LEDcount = 3; //Number of LED's in the strip
const int IRreceiver = 2; //IO pin for the IRreceiver
IRrecvPCI myReceiver(IRreceiver); //Instantiate the Infra Red receiver
IRdecode myDecoder; //Instatiate a Decoder object (Veriable to hold the recieved data from the button press)
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, color_WIPE, SCANNER, FADE }; //Limit the results 'pattern' will accept with an enumeration
//======== Variables =============
//=====Classes and Functions =====
class neoPatterns : public Adafruit_NeoPixel //A class to govern the operation of the Neopixel patterns outside of the Main loop
{
private:
int steps;
uint32_t color;
public:
pattern activePattern; //Tracks the pattern that is currently active on the strip
unsigned long interval; //Milliseconds between updates
unsigned long lastUpdate; //Records the millisecond of the last update
uint32_t color1, color2; //Variables for recording active colors
uint16_t totalSteps; //How many steps of the pattern have been called
uint16_t index; //What step within the pattern we are on
void (*onComplete)(); //onComplete callback function - still wondering how much i need this?
neoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()) //Class constructor to...
:Adafruit_NeoPixel(pixels, pin, type) //initialise the Neopixel strip
{
onComplete = callback;
}
void update() //Function that manages updating the pattern
{
if((millis() - lastUpdate) > interval) //Is it time to update?
{
lastUpdate = millis(); //Updates 'lastUpdate' to the current milli's value
switch(activePattern) //Switch statement to track which pattern needs its update function
{
case RAINBOW_CYCLE: //If rainbowCycle...
rainbowCycleUpdate(); //update rainbowCycle
break;
case THEATER_CHASE: //If theatreChase...
theaterChaseUpdate(); //update theatreChase
break;
case color_WIPE: //if colorWipe
colorWipeUpdate(); //update colorWipe
break;
case SCANNER: //if scanner
scannerUpdate(); //update scanner
break;
case FADE: //if fade
fadeUpdate(); //update fade
break;
default:
break;
}
}
}
void increment() //Function for incrementing values to drive strand tests
{
index++; //increment index variable
if (index >= totalSteps) //if index is greater than or equal to totalsteps...
{
index = 0; //..reset index to 0 and...
if (onComplete != NULL) //... if onComplete has no value...
{
onComplete(); //...call the onComplete callback
}
}
}
void rainbowCycle(uint8_t interval) //Rainbow Cycle strand test pattern
{
activePattern = RAINBOW_CYCLE; //Set current active pattern to Rainbow Cycle...
interval = interval; //reset interval to interval
totalSteps = 255; //set total step variable to 255
index = 0; //set index variable to 0
}
void rainbowCycleUpdate() //update for Rainbow Cycle
{
for(int i=0; i< numPixels(); i++) //create a variable called 'i' which is equal to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
setPixelColor(i, wheel(((i * 256 / numPixels()) + index) & 255)); //set the pixel color to ...
}
show(); //update the orders to the Neopixel strand
increment(); //Run the increment function
}
void colorWipe (uint32_t color, uint8_t interval) //color wipe funtion
{
activePattern = color_WIPE; //update the current active pattern to color Wipe
interval = interval; //reset the interval variable
totalSteps = 255; //set the total steps variable to 255
color1 = color; //set color to color 1
index = 0; //reset the index variable to 0
}
void colorWipeUpdate() //Color wipe update function
{
setPixelColor(index, color1); //change the pixel color to color1
show(); //update the strand
increment(); //run the increment function
}
void theaterChase(uint32_t color1, uint32_t color2, uint8_t interval) //Theatre Chase funtion
{
activePattern = THEATER_CHASE; //change the current active pattern to Theatre Chase
interval = interval; //reset the interval variable
totalSteps = numPixels(); //update the total steps variable to be equivilent to the number of pixels
color1 = color1; //Reset color1
color2 = color2; //Reset color2
index = 0; //Set index variable to 0
}
void theaterChaseUpdate() //Theatre Chase update function
{
for(int i=0; i< numPixels(); i++) //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
if ((i + index) % 3 == 0) //if the total of I and index divide equally by 3...
{
setPixelColor(i, color1); //...set the pixelcolor to color 1...
}
else //...otherwise...
{
setPixelColor(i, color2); //set the pixel color to color 2
}
}
show(); //update the neopixel strand
increment(); //run the increment function
}
void scanner(uint32_t color1, uint8_t interval) //Scanner function
{
activePattern = SCANNER; //update the active pattern to Scanner
interval = interval; //reset the interval variable
totalSteps = (numPixels() - 1) * 2; //set the total steps variable to by equal to twice that of the number of pixels on the strand less one
color1 = color1; //reset the color1 variable
index = 0; //set the index variable to 0
}
void scannerUpdate() //Scanner update function
{
for (int i = 0; i < numPixels(); i++) //take the i variable and reset it to 0 and do loops, whilst the number of pixels in the strip is greater than i, incremeting i every loop.
{
if (i == index) //if the i variable is equivilant to the index variable...
{
setPixelColor(i, color1); //set the pixel color to color1
}
else if (i == totalSteps - index) //if the i variable is equivilant to totalsteps less the value of index...
{
setPixelColor(i, color1); //set the pixel color to color1...
}
else //otherwise...
{
setPixelColor(i, DimColor(getPixelColor(i))); //dim the current pixel value
}
}
show(); //update the strand
increment(); //run the increment function
}
void fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval) //Fade function
{
activePattern = FADE; //set the current active pattern to fade
interval = interval; //reset the interval variable
totalSteps = steps; //create a new steps variable and set it to be eqivilant to totalSteps
color1 = color1; //reset color1
color2 = color2; //reset color2
index = 0; //set index to 0
}
void fadeUpdate() //Fade update function
{
uint8_t red = ((Red(color1) * (totalSteps - index)) + (Red(color2) * index)) / totalSteps;
uint8_t green = ((Green(color1) * (totalSteps - index)) + (Green(color2) * index)) / totalSteps;
uint8_t blue = ((Blue(color1) * (totalSteps - index)) + (Blue(color2) * index)) / totalSteps;
colorSet(Color(red, green, blue));
show(); //update the strand
increment(); //run the increment function
}
uint8_t Red(uint32_t color) //Red color function
{
return (color >> 16) & 0xFF;
}
uint8_t Green(uint32_t color) //Green color function
{
return (color >> 8) & 0xFF;
}
uint8_t Blue(uint32_t color) //Blue color function
{
return color & 0xFF;
}
uint32_t DimColor(uint32_t color) //color dimming function
{
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}
uint32_t wheel(byte wheelPos) //color wheeling function for the rainbow color functions
{
wheelPos = 255 - wheelPos;
if(wheelPos < 85)
{
return Color(255 - wheelPos * 3, 0, wheelPos * 3);
}
else if(wheelPos < 170)
{
wheelPos -= 85;
return Color(0, wheelPos * 3, 255 - wheelPos * 3);
}
else
{
wheelPos -= 170;
return Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}
}
void colorSet(uint32_t color) //color set function sets all colors to the same synchronus color
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}
void IRSelector() //Infra Red selection function - takes action based on IR code received
{
if (myDecoder.protocolNum == NEC) { //ignore any code that is not recieved from a NEC remote control
switch(myDecoder.value) //Switch statement that makes a decision based upon the value recieved from the Infra Red decoder
{
case 0xFFA25D: Serial.println("Untethered button, please select from 0-8"); break; //=====================================================================
case 0xFFE21D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF629D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF22DD: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF02FD: Serial.println("Untethered button, please select from 0-8"); break; // ------------- UNASSIGNED BUTTON SELECTIONS -------------------------
case 0xFFC23D: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFE01F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFA857: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF906F: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFF9867: Serial.println("Untethered button, please select from 0-8"); break;
case 0xFFB04F: Serial.println("Untethered button, please select from 0-8"); break; //=====================================================================
case 0xFF6897: //"0 - All black (off)"
colorWipe(color, interval);
Serial.println("0 - Black/off");
break;
case 0xFF30CF: //"1 - All red"
colorWipe(color, interval);
Serial.println("1 - All red");
break;
case 0xFF18E7: //"2 - All green"
colorWipe(color, interval);
Serial.println("2 - All green");
break;
case 0xFF7A85: //"3 - All blue"
colorWipe(color, interval);
Serial.println("3 - All blue");
break;
case 0xFF10EF: //"4 - All white"
colorWipe(color, interval);
Serial.println("4 - All white");
break;
case 0xFF38C7: //"5 - Rainbow Cycle"
rainbowCycle(interval);
Serial.println("5");
break;
case 0xFF5AA5: //"6 - Theater Chase"
theaterChase(color1, color2, interval);
Serial.println("6");
break;
case 0xFF42BD: //"7 - Scanner"
scanner(color1, interval);
Serial.println("7");
break;
case 0xFF4AB5: //"8 - Fader"
fade(color1, color2, steps, interval);
Serial.println("8");
break;
case 0xFF52AD: Serial.println("Untethered button, please select from 0-8"); break; //button 9 - unassigned
case 0xFFFFFFFF: Serial.println("Please release button and reselect"); break; //consistant repeat code
default:
Serial.print(" other button ");
Serial.println(myDecoder.value);
}//End of Switch
}
}//End of IRSelector method
}; // End of neoPatterns class
void strandComplete();
neoPatterns strand(LEDcount, LEDpin, NEO_RGBW + NEO_KHZ800, &strandComplete); //Neopattern object to define the strand
void setup(){ /*----( SETUP: RUNS ONCE )----*/
Serial.begin(9600); //engage the serial monitor
Serial.println("IR Receiver Button Decode"); //print out to the monitor
myReceiver.enableIRIn(); //Start the receiver
strand.begin(); //start the Neopixel strip
}/*--(end setup )---*/
void loop(){ /*----( LOOP: RUNS CONSTANTLY )----*/
if (myReceiver.getResults()) //check to see if we have received an IR signal?
{
myDecoder.decode(); //Decode the recieved signal
strand.IRSelector(); //Run the IR selection function
myReceiver.enableIRIn(); //reset the receiver for a new code
}
strand.update(); //Run the update function on the Neopixel strand
}/* --(end main loop )-- */
void strandComplete()
{
// Random color change for next scan
strand.color1 = strand.wheel(random(255));
}`

Related

Error on PWM output while using ATMega328p-au and Atmel Studio

Hallo everyone,
I am new into AVR programming and I was asked to develop a board which could read out the values of an analog sensor and set a PWM output. The design included a potentiometer, to act as a percentage dimmer between two PWM signals.
As my programming experience is only in the Arduino IDE, when migrating to Atmel Studio 7 I used the import Arduino Code option and proceed with ISP programming using Atmel ICE.
The model itself is composed of two analog signals (sensor and potentiometer) and 4 pwm outputs (two pairs of signals). Moreover, the code is based on a basic State Machine:
1) Read Sensor and Potentiometer, which determines the PWM output value.
2) Case 1: increase the PWM output value
3) Case 2: decrese the PWM output value
4) Case 3: mantain the PWM output value
However, whenever I put the sensor under my Lamp (controlled by the PWM) it starts to flicker and I can not reach a "stable state". My posible solution would be read out the sensor's value and have an average between the highest and lower value, which will be later used to set the PWM output level and a second one would be using interrumptions but I do not know how to implement them.
Note: the frequency is set to 10 MHz because I am using 3,3 V, so the cristal was selected according to the input value
/*Begining of Auto generated code by Atmel studio */
#define F_CPU 10000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <Arduino.h>
/*End of auto generated code by Atmel studio */
//Pinout
const int C1 = 9; // Select the pin for Channel 1 PWM Dimming (Sunrise)
const int C2 = 6; // Select the pin for Channel 2 PWM Dimming (Daylight)
const int C3 = 5; // Select the pin for Channel 3 PWM Dimming (Sunrise 2)
const int C4 = 3; // Select the pin for Channel 4 PWM Dimming (Daylight 2)
const int CM = A1; // Select the pin for the color mixer (Potentiometer)
const int ALS = A0; // Select the pin for the ALS signal
//Variables
int ch = 0; // Current PWM level
int count = 0;
float ch1 = 0; // Color mixer factor of the Channel 1 and 3 PWM (0% - 100%)
float ch2 = 0; // Color mixer factor of the Channel 2 and 4 PWM (0% - 100%)
int mixer = 0; // Potentiometer value
int pwm = 0; // PWM counter
int th = 200; // Threshold value (light sensitivity)
int als = 0; // Stores the value of the ALS
int mst = 0; // Maschine state
int sum = 0; // Average ALS value
int sum2 = 0; // Average trimmer value
int wait = 100; // Delay value
int f = 0; //1 Machine State counter
int i = 0; //2 Machine State counter
//Setup
void setup() {
// I/O Pins
pinMode(C1, OUTPUT);
pinMode(C2, OUTPUT);
pinMode(C3, OUTPUT);
pinMode(C4, OUTPUT);
pinMode(ALS, INPUT);
pinMode(CM, INPUT);
// Set PWM outputs to LOW
analogWrite(C1, ch1);
analogWrite(C2, ch2);
analogWrite(C3, ch1);
analogWrite(C4, ch2);
//Serial.begin(9600);
}
void loop() {
//State machine init
switch(mst){
case 0:
// Read the value from the Ambient Light Sensor and the Mixer Pin
for(int i =0; i<wait; i++){
delay(0.00001);
als = analogRead(ALS);
sum = als + sum;
}
// Obtain an average ALS value
sum = sum/wait;
mixer = analogRead(CM);
//Serial.println(sum2);
if(sum > th) {
sum = th;
}
if(mixer >= 1000) {
mixer = 1000;
} else {
}
// Re-map average value to PWM level (0-255 == 0-100%)
pwm = map(sum, 0, th, 255, 0);
//Declare the color mixer percentage
if((mixer>=0)&&(mixer<512)){
ch1 = 100;
ch2 = (100*mixer)/512;
} else if(mixer<1022) {
ch1 = map(mixer, 512, 1000, 100, 0);
ch2 = 100;
} else {
ch1 = 0;
ch2 = 100;
}
//Serial.print(mixer);
ch1 = ch1/100;
ch2 = ch2/100;
//Increase PWM
if(ch<pwm-5){
mst = 1;
}
//Change to the second stage
if(ch>pwm+5){
mst = 2;
}
//Change to third stage
if((ch > pwm-5) && (ch < pwm+5)){
mst = 3;
}
delay(0.000001);
break;
case 1: //Current PWM level less than the actual ALS value
//Compare PWM and ch1 to make a gradual change
count = ch+3;
if (count > 255)
{
count = 255;
}
ch = count;
analogWrite(C1, (ch*ch1));
analogWrite(C2, (ch*ch2));
analogWrite(C3, (ch*ch1));
analogWrite(C4, (ch*ch2));
delay(0.0000001);
//Return to initial state
mst = 0;
break;
case 2: //Current PWM level greater than the actual ALS value
//Compare PWM and ch1 to make a gradual change
count = ch-3;
if (count < 0)
{
count = 0;
}
ch = count;
analogWrite(C1, (ch*ch1));
analogWrite(C2, (ch*ch2));
analogWrite(C3, (ch*ch1));
analogWrite(C4, (ch*ch2));
delay(0.0000001);
//Return to initial state
mst = 0;
break;
case 3: //Current PWM level equal than the actual ALS value
//Keep tha output value
analogWrite(C1, (ch*ch1));
analogWrite(C2, (ch*ch2));
analogWrite(C3, (ch*ch1));
analogWrite(C4, (ch*ch2));
//Return to initial state (Read ALS & Trimmer)
mst = 0;
delay(0.0000001);
break;
default:
//Empty
break;
}
}

else if stops at first iteration [Arduino]

My code stops at the first iteration for the phot_val "if" statement.
/////// Code loop
void loop() {
double sound = MIC(); //Declare variable for obtaining microphone data
double phot_val;
int nreadings = 100;
int song1[N]={CN4, DN4, EN4, FN4, GN4, AN4, BN4, CN5};
int song2[M]= {RT0, RT0, CN4, DN4, CN4, FN4, EN4, RT0,CN4, DN4, CN4, GN4, FN4, RT0, CN4, CN5, AN4, FN4, EN4,DN4, RT0, AS4, AN4, FN4, GN4, FN4, RT0, RT0};
phot_val = read_analogn(2,nreadings);
Serial.print("Sound: ");Serial.println(sound); //Testing purposes, Print out sound/mic value
Serial.print("Light: ");Serial.println(phot_val,5);//Testing purposes, Print out light sensor data
if(phot_val >= .5){play_song(song1,N);} //Stops after first 100???
/// Else If statements to change RBG colors depending on sound
if(MIC() >= 30){ setColor(255, 0, 0); } //Red Color
else if(MIC() >= 35){setColor(0, 255, 0);} //Green Color
else if(MIC() >= 40){setColor(0, 0 , 255);} //Blue Color
else if(MIC() >=25){setColor(255, 255, 255);} //White Color
else if(MIC() >=25){setColor(170, 0, 255);} //White Color
else {setColor(0, 0, 0);}
}
/////// Read light sensor function
float read_analogn(int p, int n){
float sum = 0;
float avg;
int i;
float voltage;
float phot_val;
for(i=0; i<n; i++)
{
phot_val = analogRead(p);
voltage = phot_val*(5.0/1023.0);
sum += voltage;
}
avg = sum/n;
return (avg);
}
/////// Color function for RBG Leds
void setColor(int redV, int greenV, int blueV) {
analogWrite(redP, redV); //Red value for RBG
analogWrite(greenP, greenV); //Green value for RBG
analogWrite(blueP, blueV); //Blue value for RBG
}
/////// Play song function
void play_song(int song[], int n){
int isong; //Define variables
for(isong=0;isong<n;isong++){ //For loop to play the songs
tone(SPKR,song[isong]);
delay(500);
}
noTone(SPKR);
}
}
I can post more code if needed, but I have no Idea why it stop
Edit: Fixed title, and added more code of the functions.
So basically it runs tru but when "if(phot_val >= .5){play_song(song1,N);}" becomes true it stops until the song it's played entirety then it continues to read data again.
You aren't checking the value of the analog pin in the for loop so it blocks everything until the entirety of the song finishes. All you need to do is update the for loop to check the value of the input.
Replace your for loop with something like:
for(isong=0;isong<n;isong++){
tone(SPKR,song[isong]);
delay(500);
phot_val = read_analogn(2, nreadings);
if(phot_val < .5){break;} //or whatever value you want it to stop at
}
This will stop the song when your sensor goes below the threshold
I do not see any for loop , perhaps read_analogn(); is a function you declared which contains a for loop?
In that case you should check the function in order to make sure the for loop does not fall into an infinite loop , perhaps place some serial outputs in different parts of the code to see if it reaches that part , print out variables to check if different parts of the code are operating and so on.
Nevertheless it is hard to say what is happening without seeing the for loop / function which is causing the trouble so I suggest you place the functions code and the for loop itself in your question.
The first else if in your code is at this questionable location:
if(MIC() >= 30){ setColor(255, 0, 0); } //Red Color
else if(MIC() >= 35) {
// comes here only if the first call of MIC() returns less than 30
// and the second one returns 35 or more.
// ???
}
This is not an answer, but hard to read as a comment.

Slow Paint() Performance

I want to display a customized item, basically a colored table with variable column number and width. I'm using c++ Builder XE2 Rad Studio for this.
So, I created a new class inherting from TGraphicControl overwriting void __fastcall Paint(void).
The Problem: it takes quite some time (between 15 and 30 ms) to draw 12 colored rectangles with text, so I expect to have done something wrong. I suspect ShadowRect to do things one could implement better, but I'm not really sure...
Does anyone see my mistake here?
Code to Draw the Paint() Event:
void __fastcall CustomTrgDrawings::Paint(void){
ResetCanvasTools();
ShadowRect(ClientRect,colBG-0x111111,coladdLight,colText,"");
Canvas->TextOutA(5,8,String().sprintf(L"Logic Box %u",fid));
Canvas->Font->Style = TFontStyles() << fsBold;
ShadowRect(nameRec,colBtnBG,coladdLight,colText,fName);
Canvas->Font->Style = TFontStyles() ;
ShadowRect(ch1Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch1Id],true,3,true);
ShadowRect(ch2Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch2Id],true,3,true);
ShadowRect(ch3Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch3Id],true,3,true);
ShadowRect(ch4Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch4Id],true,3,true);
ShadowRect(norm1Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm1],true,3,true);
ShadowRect(norm2Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm2],true,3,true);
ShadowRect(norm3Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm3],true,3,true);
ShadowRect(norm4Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm4],true,3,true);
ShadowRect(logicRec,colBtnBG-0x002222,coladdLight,colText,logics->Strings[flogicId],true,3,true);
ShadowRect(normOutRec,colBtnBG-0x002200,coladdLight,colText,norms->Strings[fnormOut],true,3,true);
}
void CustomTrgDrawings::ResetCanvasTools(){
Canvas->Brush->Color=clNone;
Canvas->Brush->Style=bsClear;
Canvas->Pen->Color=clNone;
Canvas->Pen->Mode=pmCopy;
Canvas->Pen->Style=psSolid;
Canvas->Pen->Width=1;
Canvas->Font->Color=clBlack;
Canvas->Font->Size=8;
Canvas->Font->Style=TFontStyles();
}
void CustomTrgDrawings::ShadowRect(const TRect pos,const TColor bg, const TColor add,const TColor fg, const String text,const bool shadow,const int align,const bool comboIcon){
int textLen;
int textX,textY;
int iconWidth=0;
Canvas->Brush->Style=bsSolid;
Canvas->Brush->Color=bg;
Canvas->Pen->Color=bg-4*add;
Canvas->Pen->Style=psSolid;
Canvas->Pen->Width=1;
Canvas->FillRect(pos);
if(shadow){
Canvas->Pen->Color=bg-2*add;
Canvas->MoveTo(pos.Left,pos.Bottom-1);
Canvas->LineTo(pos.Right-1,pos.Bottom-1);
Canvas->LineTo(pos.Right-1,pos.Top);
Canvas->Pen->Color=bg+2*add;
Canvas->MoveTo(pos.Right-1,pos.Top);
Canvas->LineTo(pos.Left,pos.Top);
Canvas->LineTo(pos.Left,pos.Bottom-1);
}
if(comboIcon){
iconWidth=6;
Canvas->Pen->Style=psSolid;
Canvas->Pen->Mode=pmMask;
Canvas->Pen->Width=3;
Canvas->Pen->Color=bg-2*add;
Canvas->MoveTo(pos.Right-iconWidth-5,pos.Top+6);
Canvas->LineTo(pos.Right-iconWidth/2-5,pos.Top+10);
Canvas->LineTo(pos.Right-5,pos.Top+6);
}
Canvas->Brush->Style=bsClear;
Canvas->Pen->Color=fg;
textLen=Canvas->TextWidth(text);
switch(align%3){ //horizontal position
case 0: //left
textX=3;
break;
case 1: //middle
textX=((pos.Width()-iconWidth)-textLen)/2;
break;
case 2: //right
textX=(pos.Width()-iconWidth)-textLen;
break;
}
switch(align/3){ //vertical position
case 0: //top
textY=-1;
break;
case 1: //middle
textY=(pos.Height()-Canvas->TextHeight(text))/2;
break;
case 2: //bottom
textY=pos.Height()-Canvas->TextHeight(text);
break;
}
Canvas->TextOutA(pos.Left+textX,pos.Top+textY,text);
}

SDL stiff movement

i am making a pong game, lPad is left pad and rPad is the right pad, but i have a problem when any pad is moving up and when i release the up button and press down the pad stops for a while and then goes down, the other thing is i can't move both pads when pressing both controls(only one is moving) with this setup:
if(e.type == SDL_KEYDOWN) {
switch(e.key.keysym.sym) {
case SDLK_s:
lPad.y += 8;
if(lPad.y >= s.SCREEN_HEIGHT - lPad.getHeight()) {
lPad.y = s.SCREEN_HEIGHT - lPad.getHeight();
}
break;
case SDLK_w:
lPad.y -= 8;
if(lPad.y <= 0) {
lPad.y = 0;
}
break;
case SDLK_DOWN:
rPad.y += 8;
if(rPad.y >= s.SCREEN_HEIGHT - rPad.getHeight()) {
rPad.y = s.SCREEN_HEIGHT - rPad.getHeight();
}
break;
case SDLK_UP:
rPad.y -= 8;
if(rPad.y <= 0) {
rPad.y = 0;
}
break;
default:
break;
}
}
Any idea how to fix this and make it smooth ?
It's better to use SDL_GetKeyboardState(NULL) as the function to get input. This way, you can get the entire state of the keyboard simultaneously and thus allow for parallel inputs. If you use the while loop, each event will get caught individually, and thus be choppy.
Here is some sample code on how to use it:
const auto * keys = SDL_GetKeyboardState(NULL);
while(!done) {
while(SDL_PollEvent(&e)) {
if(e.type == SDL_QUIT) {
done = true;
}
}
SDL_PumpEvents();
if (keys[SDL_SCANCODE_UP]) {
p1.set_speed(0, -60000 * delta.count());
}
if (keys[SDL_SCANCODE_DOWN]) {
p1.set_speed(0, 60000 * delta.count());
}
if (keys[SDL_SCANCODE_LEFT]) {
p1.set_speed(-60000 * delta.count(), 0);
}
if (keys[SDL_SCANCODE_RIGHT]) {
p1.set_speed(60000 * delta.count(), 0);
}
Also, might I suggest having a speed variable? Using pixels is not a good way to scale movement, as it depends on the resolution of the screen. Using something based on a time step is much more robust.

Linker Issue using Extern

So I have a 2 games running side by side.
proj2/main.cpp (main that gets run that then can call either game)
proj2/spades/display.cpp
proj2/spades/gameplay.cpp
proj2/spades/otherFiles.cpp
proj2/hearts/display.cpp (this is the same display class as in the spades game with the same functions just sightly altered.)
proj2/hearts/hearts.cpp
proj2/hearts/otherFiles.cpp
I'm getting the following linker error,
./gamePlay.o: In function `__static_initialization_and_destruction_0(int, int)':
gamePlay.cpp:(.text+0x396): undefined reference to `spades::display::display()'
./gamePlay.o: In function `__tcf_3':
gamePlay.cpp:(.text+0x480): undefined reference to `spades::display::~display()'
in my gamePlay.cpp file I define the following and I think this is where my error is,
display monitor;
if I add the extern identifier to the line such as
extern display monitor;
the error will disappear only to produce the following issue,
./gamePlay.o: In function `spades::gamePlay::storeBid(std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&)':
gamePlay.cpp:(.text+0x14ee): undefined reference to `spades::monitor'
gamePlay.cpp:(.text+0x14f3): undefined reference to `spades::display::drawBox(int, int, int, int, int)'
I think this error is this coming from these following lines, but I have no idea how to fix this error. Feeling quite lost at the moment. (I don't understand why I would need the extern as an identifier for monitor either). Also all the includes should be alright.
int key = monitor.captureInput();
monitor.drawBox(2, 5, 3, 2, 0);
Below is my display.h file
/*
* Description: Defines constants and class prototypes and variables
*/
// These are include files they are used for accessing functions and
// variables in external libraries.
#include <ncursesw/ncurses.h>
#include <iostream>
#include <cstdio>
// This is the namespace std, without this you would need to add "std::"
// infront of every variable and function from the std library.
//using namespace std;
// These Mouse Mask Definitions are for some of the common mouse buttons
// that are used in this project.
#define LEFT_UP 1
#define LEFT_DOWN 2
#define LEFT_CLICK 4
#define LEFT_DOUBLECLICK 24
#define RIGHT_UP 4096
#define RIGHT_DOWN 8192
#define RIGHT_CLICK 16384
#define RIGHT_DOUBLECLICK 32768
#define MIDDLE_ROLLUP 1048576
#define MIDDLE_ROLLDOWN 256
namespace spades {
// Some extended character definitions for showing the special symbols
// in the extended UTF-8 character map.
const char joker[] = {0xE2, 0x98, 0xBA, 0};
const char clubs[] = {0xE2, 0x99, 0xA3, 0};
const char diamonds[] = {0xE2, 0x99, 0xA6, 0};
const char hearts[] = {0xE2, 0x99, 0xA5, 0};
const char spades[] = {0xE2, 0x99, 0xA0, 0};
/*
* This is the display class definitions
*/
class display {
public:
/* "constructor"
* This function is called whenever a new object of class display is first
* created. Put initialization functions in here.
*/
display(void){};
/* "destructor"
* This function is called just before a object is deleted. Put clean up
* functions in here.
*/
~display(){}; // destructor
// captures user input
int captureInput(void);
// stores new screensize on update
void handleResize(int sig);
/*
* Drawing commands
*/
// display a card on the screen
void displayCard(int x, int y, int suit, int number, int printAtt);
// erase in the shape of a box on the screen
void eraseBox(int x, int y, int sizeX, int sizeY);
// draw a box on the screen
void drawBox(int x, int y, int sizeX, int sizeY, int printAtt);
// display banner text at the bottom of the screen
void bannerBottom(std::string bannerText);
void bannerAboveBottom(std::string bannerText);
// display banner text at the top of the screen
void bannerTop(std::string bannerText);
// get information about the display
int getCols(void) {return cols;}
int getLines(void) {return lines;}
int getMouseEventX(void) {return mouseEventX;}
int getMouseEventY(void) {return mouseEventY;}
int getMouseEventButton(void) {return mouseEventButton;}
// Updates the screen after you finish drawing
void updateScreen(void) {refresh();}
// sets an offset for when cards clip the bottom of the screen
void setBottomOffset(int offset) {lineBoundaryOffset=offset;}
private:
// These are private functions and variables used inside of display.
// You should not try to access these from outside the display class.
void printFace(int suit, int number, int line, int printAtt);
void printSuit(int suit);
void printNumber(int number);
int cols;
int lines;
int mouseEventX;
int mouseEventY;
int mouseEventButton;
int lineBoundaryOffset;
};
}
Below is my display.cpp file
/*
* Description: Defines the functionality of the user interface.
*
* NOTES:
* * Requires the terminal (Putty) to be set to UTF-8.
* * Does not function when running a screen session.
*/
#include <iostream>
#include <sys/ioctl.h>
#include <cstdio>
#include <unistd.h>
#include <locale.h>
#include <ncursesw/ncurses.h>
#include "display.h"
namespace spades {
//using namespace std;
/* Function: This is the constructor.
* Description: It is called whenever an object of class display is initialized
*/
display::display(void) {
/* Initilization of Terminal */
// required to get card suits displaying, combined with UTF-8 set in terminal
setlocale(LC_ALL,"en_US.utf-8");
// initialize ncurses screen
initscr();
// allow for color settings
start_color();
// clear the screen
clear();
// turn off the keyboard echo (reqiured while drawing)
noecho();
// Change to character mode (so individual characters are being read at a
// time rather than waiting for a carriage return).
cbreak();
// Allows for function keys to be used (also nessacary for getting the mouse
// movement working).
keypad(stdscr, TRUE);
// set which mouse events are captured
mousemask(ALL_MOUSE_EVENTS, NULL);
// Setting the timeout for the capture input values are in 1/10ths of a second.
halfdelay(5);
// setup the screen size settings.
cols = 80;
lines = 24;
// this updates the locally stored col and line variables
handleResize(0);
// set a no card draw offset of 1 so the bottom banner is not overwritten
lineBoundaryOffset = 1;
// Settings for card colors (these can be set outside of the display class)
init_pair(1, COLOR_CYAN, COLOR_BLACK); // for card outline
init_pair(2, COLOR_BLUE, COLOR_BLACK); // for spades and clubs
init_pair(3, COLOR_RED, COLOR_BLACK); // for hearts and diamonds
init_pair(4, COLOR_GREEN, COLOR_BLACK); // for turned over card
init_pair(5, COLOR_GREEN, COLOR_BLACK); // for box drawing
init_pair(6, COLOR_GREEN, COLOR_BLACK); // for banner display
}
/* Function: This is the destructor.
* Description: This is called just before an object is deleted.
*/
display::~display() {
// this is turns off all the special settings and returns the terminal to normal
endwin();
// insert deletion of dynamically created objects here too
}
/*
* Function: This captures all the userinput.
* Description: It captures mouse and keyboard events.
* Returns "Positive Number"
* - for user keypress
* - this is a character code typed
* Returns "0" - for no user input
* - this is when nothing is typed for half a second
* - allows for other timed operations to occur
* Returns "-1" - for mouse event
* - details of the mouse event must be fetched from this class
* - use getMouseEventX, getMouseEventY and getMouseEventButton
*/
int display::captureInput(void) {
// obtain one mouse event or keypress
int ch=getch();
// this is a switch statement for the result of getch
switch (ch) {
case KEY_MOUSE: // this occurs when an mouse event occurs
{
MEVENT mevent; // this is a variable declared of type MEVENT
getmouse(&mevent); // this gets the mouse event from ncurses (library)
mouseEventX = mevent.x; // get the column location of the event
mouseEventY = mevent.y; // get the row location of the event
mouseEventButton = mevent.bstate; // get the button state of the mouse
return -1; // -1 is for a mouse event
}
break;
case ERR: // this occurs when there is a timeout
{
return 0; // 0 is when nothing occurs
}
break;
default: // this occurs when a key is pressed
return ch; // a character is when the user types something
}
return 0; // this is never called, but is used to stop compiler complaints
}
/*
* Function: Updates all the information in the display class on window resize
* Description: This function just updates information, it requires the call
* from a static singal handler. Signal handlers service interrupts and require
* a static function to be called, because they are not part of the main
* program control flow. The signal handler should be declared in the main
* class, because your game should redraw the display on a resize.
*/
void display::handleResize(int sig) {
#ifdef TIOCGSIZE // operating system dependant differences
struct ttysize ts;
ioctl(STDIN_FILENO, TIOCGSIZE, &ts); // get the information of the terminal
cols = ts.ts_cols;
lines = ts.ts_lines;
#elif defined(TIOCGWINSZ)
struct winsize ts;
ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); // get the information of the terminal
cols = ts.ws_col;
lines = ts.ws_row;
#endif /* TIOCGSIZE */
resizeterm(lines, cols); // sets the ncurses window size correctly
}
/*
* Function: Displays various cards on the game screen
* Description: This function displays various playing cards on the screen.
* The first two arguments are the x and y coordinates of the top left corner
* of the card.
* The suit values are: 1=spades, 2=hearts, 3=clubs, 4=diamonds
* The numbers are: 1=Ace, 2-10=2-10, 11=Jack, 12=Queen, 13=King, 14=Joker
* Any suit and number that do not match the valid numberrs generates a face down
* card.
* The printAtt allows for one or more any of the following display settings:
* A_NORMAL Normal display (no highlight)
* A_STANDOUT Best highlighting mode of the terminal.
* A_UNDERLINE Underlining
* A_REVERSE Reverse video
* A_BLINK Blinking
* A_DIM Half bright
* A_BOLD Extra bright or bold
* A_PROTECT Protected mode
* A_INVIS Invisible or blank mode
* A_ALTCHARSET Alternate character set
* A_CHARTEXT Bit-mask to extract a character
* COLOR_PAIR(n) Color-pair number n
*/
void display::displayCard(int x, int y, int suit, int number, int printAtt) {
// Ncurses drawing settings
attron(COLOR_PAIR(1) | printAtt);
// prevent draw if it off the screen
if (x>=0 && y>=0 && x<cols-6 && y<lines-lineBoundaryOffset) {
// print the top lines of the card
mvprintw(y,x,"\u250c\u2500\u2500\u2500\u2500\u2510");
// the next 4 if statements prevent draw if it is over the bottom of the screen
if (y<lines-1-lineBoundaryOffset) {
move(y+1,x); // move command
printFace(suit,number,0, printAtt); // call function to print card face
}
if (y<lines-2-lineBoundaryOffset) {
move(y+2,x); // move command
printFace(suit,number,1, printAtt); // call function to print card face
}
if (y<lines-3-lineBoundaryOffset) {
move(y+3,x); // move command
printFace(suit,number,2, printAtt); // call function to print card face
}
if (y<lines-4-lineBoundaryOffset) {
// prints the bottom lines of the card
mvprintw(y+4,x,"\u2514\u2500\u2500\u2500\u2500\u2518");
}
}
// Ncurses turn off the drawing settings
attroff(COLOR_PAIR(1) | printAtt);
}
/*
* Function: Print a single line of what is written on the card.
* Description: This copies suit, number and printAtt from the calling function.
* Also includes what line of the card face is being drawn.
*/
void display::printFace(int suit, int number, int line, int printAtt) {
// draw left edge of the card
printw("\u2502");
if (suit==2 || suit==4) { // Red for Hearts and Diamonds
attron(COLOR_PAIR(3) | printAtt);
} else { // Black for Spades and Clover
attron(COLOR_PAIR(2) | printAtt);
}
// this the display of the joker
if (number==14) {
if (line==0)
printw("J%s ", joker);
if (line==1)
printw("oker");
if (line==2)
printw(" J%s", joker);
// this is the display for the cards with suits and numbers
} else if (suit>=1 && suit <=4 && number>=1 && number<=13) {
if (line==0) {
printSuit(suit); // function to draw suit
printNumber(number); // function to draw number
if (number!=10)
printw(" ");
printw(" ");
} else if (line==2) {
if (number!=10)
printw(" ");
printw(" ");
printNumber(number); // function to draw number
printSuit(suit); // function to draw suit
} else {
printw(" ");
}
// this is for a face down card
} else {
// the face down cards have a special color
attron(COLOR_PAIR(4) | printAtt);
if (line==0)
printw("%s %s", spades, hearts);
if (line==1)
printw("Play");
if (line==2)
printw("%s %s", diamonds, clubs);
attroff(COLOR_PAIR(1) | printAtt);
}
// turn on the card edge color settings
attron(COLOR_PAIR(1) | printAtt);
// print the right edge of the card
printw("\u2502");
}
/*
* Function: Print the suit of the card
* Description: This is just a look up table.
*/
void display::printSuit(int suit) {
switch (suit) {
case 1:
printw("%s",spades);
break;
case 2:
printw("%s",hearts);
break;
case 3:
printw("%s",clubs);
break;
case 4:
printw("%s",diamonds);
break;
default:
printw(" ");
break;
}
}
/*
* Function: Prints the number on the card
* Description: This is just a look up table.
*/
void display::printNumber(int number) {
switch (number) {
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
printw("%i",number);
break;
case 1:
printw("%c",'A');
break;
case 11:
printw("%c",'J');
break;
case 12:
printw("%c",'Q');
break;
case 13:
printw("%c",'K');
break;
default:
printw(" ");
break;
}
}
/*
* Function: Erases a rectangle on the screen
* Description: x,y is for the top left corner, sizeX and sizeY set
* how big the square is.
*/
void display::eraseBox(int x, int y, int sizeX, int sizeY) {
std::string strDraw;
int yCount;
int maxSizeX;
// this limits the column size of the draw when it is over the edge
// of the drawing area
if (sizeX+x > cols)
maxSizeX=cols-x;
else
maxSizeX=sizeX;
// for the number of rows that need to be drawn
for (yCount=0; yCount<sizeY;yCount++) {
// if the box goes over the edge of the drawable screen
// stop drawing by breaking the loop
if (yCount+y > lines-lineBoundaryOffset || y < 0)
break;
// reset the line to be drawn
strDraw = "";
// check that x is not off the screen
if (x<=cols && x >= 0) {
// make a string needed for box width
strDraw.append(maxSizeX,' ');
// print the line of the box
mvprintw(y+yCount,x,"%s",strDraw.c_str());
}
}
}
/*
* Function: Draws a box on the screen
* Description: x,y is for the top left corner, sizeX and sizeY set
* how big the square is. printAtt allows for changes in the
* display settings.
*/
void display::drawBox(int x, int y, int sizeX, int sizeY, int printAtt) {
std::string strDraw;
int ii;
int yCount;
// set the box setting colors on
attron(COLOR_PAIR(5) | printAtt);
// for the box height being drawn loop
for (yCount=0; yCount<sizeY;yCount++) {
// break loop if the drawing is offscreen
if (yCount+y > lines-lineBoundaryOffset || y < 0)
break;
// if x is on the screen
if (x<=cols) {
strDraw = "";
// for the box width loop
for (ii=0;ii<sizeX;ii++){
// stop drawing if the x is offscreen
if (ii+x > cols || x < 0)
break;
// first line
if (yCount==0) {
if (ii==0) {
strDraw.append("\u250c"); // left
} else if (ii==sizeX-1) {
strDraw.append("\u2510"); // right
} else {
strDraw.append("\u2500"); // middle
}
// last line
} else if (yCount==sizeY-1) {
if (ii==0) {
strDraw.append("\u2514"); // left
} else if (ii==sizeX-1) {
strDraw.append("\u2518"); // right
} else {
strDraw.append("\u2500"); // middle
}
// other lines
} else {
if (ii==0) {
strDraw.append("\u2502"); // left
} else if (ii==sizeX-1) {
strDraw.append("\u2502"); // right
} else {
strDraw.append(" "); // middle
}
}
}
// print the line that was created
mvprintw(y+yCount,x,"%s",strDraw.c_str());
}
}
// turn off the attribute colors
attroff(COLOR_PAIR(5) | printAtt);
}
/*
* Function: Draws a banner of text at the bottom right of the screen
* Description: Inverts the color and draws the banner at the bottom
* of the screen. Does not handle carriage returns on the string.
*/
void display::bannerBottom(std::string bannerText) {
// change to the banner draw settings
attron(COLOR_PAIR(6) | A_REVERSE | A_BOLD);
// checks if the banner string size is smaller than the width of the screen
if((unsigned)cols > bannerText.size()) {
// moves the cursor to the bottom of the screen
move(lines-1,0);
// fill in extra space to the banner text is right adjusted
hline(' ',cols - bannerText.size());
// prints out the banner text
mvprintw(lines-1,cols-bannerText.size(),"%s", bannerText.c_str());
// if banner string size is larger than width of screen
} else {
// clip the banner text so it doesn't wrap over to the next line
mvprintw(lines-1,0,"%s", (bannerText.substr(0,cols)).c_str());
}
// turn off the draw colors
attroff(COLOR_PAIR(6) | A_REVERSE | A_BOLD);
}
void display::bannerAboveBottom(std::string bannerText) {
// change to the banner draw settings
attron(COLOR_PAIR(1) | A_REVERSE | A_BOLD);
// checks if the banner string size is smaller than the width of the screen
if((unsigned)cols > bannerText.size()) {
// moves the cursor to the bottom of the screen
move(lines-2,0);
// fill in extra space to the banner text is right adjusted
hline(' ',cols - bannerText.size());
// prints out the banner text
mvprintw(lines-2,cols-bannerText.size(),"%s", bannerText.c_str());
// if banner string size is larger than width of screen
} else {
// clip the banner text so it doesn't wrap over to the next line
mvprintw(lines-2,0,"%s", (bannerText.substr(0,cols)).c_str());
}
// turn off the draw colors
attroff(COLOR_PAIR(1) | A_REVERSE | A_BOLD);
}
/*
* Function: Draws a banner of text at the top left of the screen
* Description: Inverts the color and draws the banner at the top
* of the screen. Does not handle carriage returns on the string.
*/
void display::bannerTop(std::string bannerText) {
// change to the banner draw settings
attron(COLOR_PAIR(6) | A_REVERSE | A_BOLD);
// checks if the banner string size is smaller than the width of the screen
if((unsigned)cols > bannerText.size()) {
// moves the cursor to the bottom of the screen
move(0,0);
// prints out the banner text
printw("%s", bannerText.c_str());
// fill in extra space after the banner text
hline(' ',cols - bannerText.size());
// if banner string size is larger than width of screen
} else {
// clip the banner text so it doesn't wrap over to the next line
mvprintw(0,0,"%s", (bannerText.substr(0,cols)).c_str());
}
// turn off the draw colors
attroff(COLOR_PAIR(6) | A_REVERSE | A_BOLD);
}
}
Below is my gameplay.h file
#include "player.h"
#include "display.h"
#ifndef gamePlay_H
#define gamePlay_H
namespace spades {
class gamePlay{
bool spadesBroken;
public:
vector <spades::card> getDeck();
vector <spades::player>getplayers();
bool getSpadesBroken() {return spadesBroken;}
void setSpadesBroken(bool b){spadesBroken = b;}
int compareCenter(int leadplayer);
void createDeck();
void deal(vector <spades::card> &deck, vector <spades::player> &players);
void handSort();
bool containSuit(spades::card lead, spades::player players);
bool onlySpade(spades::player play);
int handCheck(int xevent, int yevent, vector <spades::player> players, int trickStart);
void displayHand();
void displayAdd();
void humanPlay(int trickStart);
void CPUplay(int trickStart, int CPU);
void score(spades::player &play, spades::player &play2);
void storeBid(stringstream &msg);
void runGame();
};
}
#endif
Below is my gameplay.cpp file
#include <iostream>
#include <sys/ioctl.h>
#include <cstdio>
#include <unistd.h>
#include <locale.h>
#include <ncursesw/ncurses.h>
#include <fstream>
#include "gamePlay.h"
#include <cstdlib>
#include <sstream>
#include <ctime>
namespace spades {
vector <spades::player> players(4);
vector <spades::card> deck(52);
display monitor;
card center[4];
vector <spades::card> gamePlay::getDeck(){return deck;}
vector <spades::player> gamePlay::getplayers(){return players;}
//sorts the cards in the players hand into diamonds, clubs, hearts, spades
void gamePlay::handSort(){
int spades[13];
int hearts[13];
int clubs[13];
int diamonds[13];
int index;
int i;
for(i=0; i<13; i++){ //determines the card number and places them into corresponding indexes
index = (players.at(0).hand.at(i).getCardNum()+11)%13; //cause the cards to be placed based on their number with 2 being index 0 and 1(ace) being index 12
switch(players.at(0).hand.at(i).getSuit())
{
case 1: spades[index] = 1;
break;
case 2: hearts[index] = 1;
break;
case 3: clubs[index] = 1;
break;
case 4: diamonds[index] = 1;
break;
default: mvprintw(3,2,"!!!!!!!we have a problem!!!!!!!!!!");
break;
}
}
i = 0;
while(i<13){ //being placing the ordered cards back into the players hand
int j = 0;
while(j < 13){
if(diamonds[j] == 1){ //if a card has been placed in this index for the diamonds only array
if(j+2 == 14) //if the card is an ace
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2); //add 2 to each index to get the card number
players.at(0).hand.at(i).setSuit(4);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(clubs[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(3);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(hearts[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(2);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(spades[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(1);
i++;
}
j++;
}
}
}
//compares the center pile of 4 played cards to determine who wins the trick
int gamePlay::compareCenter(int leadplayer){
int highest = center[leadplayer].getCardNum();
if(center[leadplayer].getCardNum() == 1)
highest = 14;
int suit = center[leadplayer].getSuit();
int player = leadplayer;
for(int i = leadplayer+1; i < leadplayer+4; i++)
{
if(center[i%4].getSuit() == 1)
setSpadesBroken(true);
if((suit != 1) && (center[i%4].getSuit() == 1))
{
player = i%4;
suit = 1;
highest = center[i%4].getCardNum();
}
if(suit == center[i%4].getSuit()){
if(center[i%4].getCardNum() == 1){
player = i % 4;
highest = 14;
}
if(highest < center[i%4].getCardNum())
{
player = i%4;
highest = center[i%4].getCardNum();
}
}
}
players.at(player).setTricksTaken(players.at(player).getTricksTaken()+1); //increments the trick count of the winning player
return player; //return the player who won to determine who goes first next turn
}
//Create the deck of 52 cards by setting the suit and number of each card to a nonzero integer
void gamePlay::createDeck() {
for(int j = 0; j < 52; j++)
{
deck.at(j).setCardNum((j%13)+1);
deck.at(j).setSuit((j/13)+1);
}
random_shuffle(deck.begin(), deck.end());
}
//deal out 13 cards to each player by setting the
void gamePlay::deal(vector <spades::card> &newdeck, vector <spades::player> &newplayers){
for(int i = 0; i<52; i++){
newplayers.at(i/13).addCard(newdeck.at(i));
newdeck.at(i).setSuit(0);
newdeck.at(i).setCardNum(0);
}
}
//determines if the player still has a card of the same suit in their hand as the leading card played
bool gamePlay::containSuit(spades::card lead, spades::player players){
bool suit = false;
for(int i = 0; i < players.getHand().size(); i++){
if(lead.getSuit() == players.getHand().at(i).get
You have to write default constructor and destructor like this:
struct display
{
display() { }
~display() { }
// ^^^^
};
and not like this:
struct display
{
display();
~display();
};
However, if you do have the latter form in your header and want to keep it that way, you need to add definitions to the source file:
display::display() { }
display::~display() { }
The linker is complaining that it can't find object spades::monitor and function spades::display::drawBox(int, int, int, int). Are these defined anywhere? Please note that when defining a member variable/member function in a .cpp file (or anywhere outside of its class definition), you have to qualify it with the class name. Example:
In .h
namespace spades {
class display {
static display monitor;
void drawBox(int, int, int, int);
};
}
In .cpp
namespace spades {
display display::monitor;
void display::drawBox(int, int, int, int) {
//...
}
}
It's hard to say more without seeing the full code (at least the definitions of the things the linker is complaining about).