drawString, boolean switching, and circle Rotation

I’m having 3 problems with my code that I’ve been working on for hours and still can’t get. The first one is a problem with the drawString function. I’m making a program that’s a word guessing game, and if the user enters in a letter that is a part of the word, it goes in the correct space on the screen. This is working, the only problem is that every time a new letter is entered, the other one is erased. Basically: it is only printing one letter at a time on the screen. I need it to be able to write a letter in the correct spot, and keep it there instead of overwriting it somewhere else. Does anyone know how I can do this?
Here’s the code I have for this:

for(i=0; i<len; i++)
{
    if (word[i]==guess)
    {
        ofSetColor(0, 0, 0);
        if (len+1>=8)
        {
            font5.drawString(mystery, 415+((i+1)*100), 315);
        }
        else
        {
            font5.drawString(mystery, 565 +((i+1)*100), 315);
        }
    }
}

len is the string length of the mystery word, guess and mystery are both the letters entered by the user.

My second issue also pertains to this in a way. I want the game to use 2 players, and for the “guess” char to appear on each players side during their turn. I just want it to switch back and forth every time someone takes a turn. I tried using both a boolean, and an integer (equaling to 0, then 1) to do this, but nothing is working. The code I have for it now is:

 if (switch1==0)
{
    font4.drawString(str, 280, 360);
    switch1=1;
}
else if (switch1==1)
{
    font4.drawString(str, 1730, 360);
    switch1=0;
}

with switch1 just being an int equal to 0. I just want it to draw the char on the screen on one side for player 1, then on the other for player 2 (switching back and forth between turns).

My third problem is with a circle I have on the screen. It has 4 numbers on it (10, 20, 30, 40), and the numbers rotate in the circle when clicked with the mouse. I need to be able to get the value of the number at the top of the circle after I rotate them. (The point of this is, it’s a game that you click the wheel to rotate it, and the number on top is the amount of points you get if you guess the right character in the mystery word). I have absolutely no idea how to do this.
The code I have to rotate the numbers is:

ofPushMatrix();
    ofTranslate(950, 725, 0);//move pivot to center
    ofSetColor(255, 0, 0);
    ofCircle(0, 0, myCircleRadius);
    ofSetColor(0, 0, 0);
    ofCircle(0, 0, 10);
    ofRotate(spin, 0, 0, 1);//rotate from center
        font2.drawString("10", -20+(cos(spin)), -175+(sin(spin)));
        font2.drawString("20", 150+(cos(spin)), 0+(sin(spin)));
        font2.drawString("30", -20+(cos(spin)), 200+(sin(spin)));
        font2.drawString("40", -200+(cos(spin)), 0+(sin(spin)));
   ofPopMatrix();

This is currently what the program looks like. Note: the yellow word behind the blue rectangles is not staying. It’s for me to know what the mystery word is, and I’m going to take it out later once I finish the program.

If anyone could possibly help me with these issues, I would be so extremely grateful. Please excuse my ignorance on openframeworks, this is the first time I’ve used it and my c++ background isn’t even strong to begin with.
Thanks!

Hello,

1- do not draw something immediately if guessed. In the beginning prepare a lookup table for found letters. Then switch it to true when a letter guessed. After this check, draw all found letters together.

//in the beginning
int letternum = word.length;
bool somethingfound = false; //I added this for your second question
bool letterfound[letternum];
for (int i=0; i<letternum; i++) letterfound[i] = false;

//in the turn
somethingfound = false;
for (int i=0; i<letternum; i++) {
    if (word[i] == guess) {
        letterfound[i] = true;
        somethingfound = true;
    }
}

if (somethingfound) {
    for (int i=0; i<letternum; i++) {
        if (letterfound[i]) {
            //draw the found letter here
        } else {
            //whatever you do with unfound letter
        }
    }
}

2- do not limit yourself with 2 players. You may need more players in the final release of the game, like 4-6-8 players…

//in the beginning
int playernum = 2; //so you can change this to 4-6-8 or more whenever you want
int currentplayer = 0;

//in the player turns
if (!somethingfound) {
    currentplayer++;
    if (currentplayer >= playernum) currentplayer = 0;
}

//Just a side note;
//If you still want to switch 2 players, you should do it like this line:
//switch1 = 1 - switch1; // this code is to switch between 0 and 1

3- the top number in the graphics you share, may be calculated like that:

int topnumber = 10 + (((360 - spin) / 90) * 10);

Hi! Thanks so much for your help!! I tried running your code for these three things, but it’s still not working properly :confused:
For problem 1, your code did exactly the same thing as mine did. I don’t understand why it’s doing that–but it’s only printing one character at a time.

The second problem, it still won’t switch. The logic seems to be correct, but the char just stays on one side (usually the first side) of the screen and doesn’t switch.

The third problem, I plugged in your code to get the number, but the numbers aren’t coming out correctly. First, the numbers started out at 40, but I tweaked it until they started at 0. But they’re still not adding up correctly.

I’m going to post all of my code, there might be a problem with something else. If someone could take a look at it and let me know, I would really appreciate it!
Thanks again!

void ofApp::setup(){
ofBackground(255,255,255);

//font functions
myFont.loadFont("Fortune.ttf", 70);
font2.loadFont("Fortune.ttf", 35);
font3.loadFont("Fortune.ttf", 20);
font4.loadFont("Fortune.ttf", 25);
font5.loadFont("Fortune.ttf", 55);

//randomize functions
r=ofRandom(10, 15);
random1=ofRandom(0, 4);
random2=ofRandom(0, 5);
randSpin=ofRandom(0.5, 1.3);

srand(time(NULL));

ofSetWindowTitle("empty example");

ofSetFrameRate(60);

}

void ofApp::draw(){

int i;

//categories and words for the game
string category[4]={"Celebs", "Animals", "Countries", "Movies"};
string cat=category[random1];
string Celebs[5]={"eminem", "pink", "madonna", "cher", "prince"};
string Animals[5]={"elephant", "kangaroo", "cheetah", "zebra", "giraffe"};
string Countries[5]={"indonesia", "austria", "brazil", "scotland", "thailand"};
string Movies[5]={"terminator", "lincoln", "taken", "gladiator", "divergent"};

//setting up the word to randomize per category
if (cat=="Celebs")
{
    word=Celebs[random2];
}
   if (cat=="Animals")
{
    word=Animals[random2];
}
if (cat=="Countries")
{
    word=Countries[random2];
}
if (cat=="Movies")
{
    word=Movies[random2];
}

str = "";
str += guess;

mystery = "";
mystery += guess;

int len=strlen(word.c_str());

//drawing all the text on the screen
ofSetColor(255, 100, 0);
myFont.drawString("WHEEL OF FORTUNE!", 475, 100);

ofSetColor(250, 230, 0);
font2.drawString("Category: ", 550, 200);
font2.drawString(cat, 800, 200);
font2.drawString(word, 800, 300);

ofSetColor(0, 0, 0);
font2.drawString("Player 1: ", 50, 300);
font2.drawString(".............................", 50, 325);
font3.drawString("Guess a Letter: ", 50, 360);
font3.drawString("Pot: ", 50, 415);
font2.drawString("Player 2: ", 1500, 300);
font2.drawString(".............................", 1500, 325);
font3.drawString("Guess a Letter: ", 1500, 360);
font3.drawString("Pot: ", 1500, 415);
font3.drawString("Letters Guessed:", 25, 670);

//circle rotation
   ofPushMatrix();
    ofTranslate(950, 725, 0);//move pivot to center
    ofSetColor(255, 0, 0);
    ofCircle(0, 0, myCircleRadius);
    ofSetColor(0, 0, 0);
    ofCircle(0, 0, 10);
    ofRotate(spin, 0, 0, 1);//rotate from center
        font2.drawString("10", -20+(cos(spin)), -175+(sin(spin)));
        font2.drawString("20", 150+(cos(spin)), 0+(sin(spin)));
        font2.drawString("30", -20+(cos(spin)), 200+(sin(spin)));
        font2.drawString("40", -200+(cos(spin)), 0+(sin(spin)));
   ofPopMatrix();

int topnumber = 4-(((360 - spin) / 90));
string myNumString = ofToString(topnumber);
font4.drawString(myNumString, 100, 415);

//setting up the rectangles for the letters of the mystery word
ofSetColor(0, 90, 255, 110);
ofFill();
for(i=1; i<len+1; i++)
{
    if (len+1>=8)
    {
        ofRect(400+(i*100), 235, 75, 100);
    }
    else
    {
        ofRect(550+(i*100), 235, 75, 100);
    }
}
//rectangle for the guessed letters
ofSetColor(0, 20, 255, 170);
ofRect(25, 680, 575, 230);



ofSetColor(0, 0, 0);
int isPresent=0;
for(i=0; i<lettersGuessed.length(); i++)
{
    if(lettersGuessed[i]==guess)
    {
        isPresent=1;
    }
}
if (isPresent==0)
{
    lettersGuessed+=guess;
}
font4.drawString(lettersGuessed, 30, 735);

bool somethingfound = false; //I added this for your second question
bool letterfound[len];
for (int i=0; i<len; i++) letterfound[i] = false;

//in the turn
somethingfound = false;
for (int i=0; i<len; i++) {
if (word[i] == guess) {
letterfound[i] = true;
somethingfound = true;
}
}

if (somethingfound) {
    for (int i=0; i<len; i++) {
        if (letterfound[i]) {
            ofSetColor(0, 0, 0);
            if (len+1>=8)
            {
                font5.drawString(mystery, 415+((i+1)*100), 315);
            }
            else
            {
                font5.drawString(mystery, 565 +((i+1)*100), 315);
            }
        }
    }
}


ofSetColor(0, 0, 0);

switch1=0;
if(switch1==0)
{
    font4.drawString(str, 280, 360);
    switch1=1+switch1;
}
else if(switch1==1)
{
    font4.drawString(str, 1730, 360);
    switch1=1-switch1;
}

}

Sorry not too sure why that middle part wouldn’t print in the code format.

void ofApp::keyPressed(int key){

//getting the letter entered by the user
guess=(char)key;

}

void ofApp::mousePressed(int x, int y, int button){

//spinning the wheel only if the mouse is clicked inside it
if(distance = ofDist(950, 725, x, y))
{
    spin=RAD_TO_DEG*(2*PI*(randSpin+0.5));
}
else
{
    spin=0;
}

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

 if(distance=ofDist(950, 725, x, y))
{
    spin=ofGetFrameNum()*8;
}
else
{
    spin=ofGetFrameNum()*0;
}

}

TL;DR

I sifted through your question and the given answer, and I apologize if I’m writing something that is already well known, but here goes:

The thing that is in common to all your problems is how you structure your code. You haven’t specified (at least I haven’t found this explicitly written) where did you write your code, but I suspect that the entire thing is in the “draw” call. The main problem is that “draw” is called again and again. You cannot change state just because you passed through the draw call.

The correct way is to have state changed before hand (for example when reacting to touches) and stored in members, and then act upon that state in the draw call and draw whatever the state tells you to draw.

Regarding problem #3, there’s another issue there. You are mixing state and view. You should not draw a view and then try to query the view in order to know what the state is. The state should be well known whether you are drawing a view or not. For your specific issue, I would recommend: have a member that holds the current angle. have another member that tells you the current speed of the rotation (start it at 0). When clicking, set a speed to the wheel. In “update”, every time speed > 0, change the rotation a bit and decrease the speed a bit. In “draw”, just draw the wheel in the correct rotation according to the state.

Tal

1 Like

I see what you mean.
Yeah, I have almost everything written in draw, and part of it written in setup. I tried to break it up even more and write most of the stuff in setup, but for some reason it wouldn’t run correctly when I did that.

For problem 3, I actually managed to fix it. It took me a long time and a much longer amount of code than I expected, but it works properly now.
I’m still having problems with drawing the string and not having it overwrite each character. I don’t know how I would go about doing this. I’ve tried it over and over again, not matter what I put it just keeps overwriting every time a new character is added.
Problem two I’m still working on, but I’m sure I’ll get it after a while.

You can’t just move stuff from draw to setup. setup is called only once, draw is called all the time again and again.

setup - stuff you only want done once (load textures, initialize members to their default value, etc.).
draw - act upon members to draw he view, don’t change members here.

So where do you change the members? Usually it should be done when responding to touches. When there’s a touch, see what the members say the current state is (who’s turn is it, is the wheel already rotating, etc.), figure out where the user touched and change the state accordingly.

Regarding the overwriting of the string. I again suspect that you try to hold the letters that you “already drew” on the view and not in a member. There’s no such concept as “already drew” in OF. The moment you finished drawing, a new drawing begins. This occurs around 60 times per second. So, you need to have a state member that tells you which letters are uncovered and which not. My suggestion (that may or may not fit with what you need): keep it in a string, with underscores for covered letters, like: “Op_n f____works _s fun!”. That way you can always draw the entire string as it should be.

How do you know you have enough state members? Look at them and figure out if you know EXACTLY what your view looks like right now. If you are unsure (what is the current rotation of the wheel? who’s turn is it? which letters are uncovered and what are they?), there’s a chance you need more members.

Hope it helps,

Tal

1 Like

I’ve actually started trying to do that, but it’s still not working. It must be something wrong with the way I wrote my code. Now, it just prints the whole string with the dots, with the letter guessed in the right spot, but when I guess another, the previous letter goes back to a ‘.’

In update:

for(i=0; i<len; i++)
{
    dashArray[i]='.';
    if (guess==word[i])
    {
        dashArray[i]=word[i];
    }
}
string str(dashArray);

In draw:

    for(i=0; i<len; i++)
    {
        if(dashArray[i]==word[i])
        {
            if (len+1>=8)
        {
            font5.drawString(dashArray, 415+((i+1)*100), 315);
        }
        else
        {
            font5.drawString(dashArray, 565 +((i+1)*100), 315);
        }
        }
    }

Well have you debugged it and saw if dashArray indeed contains all the letters as you expect it? In other words - is it a state issue or a drawing issue?