Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Section of Code Lagging the Program

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Section of Code Lagging the Program
AceBlkwell
Member #13,038
July 2011
avatar

I've got a program and it runs fine, but I when I added a moving star background the program starts to lag. The stars don't lag and the mouse doesn't hesitate but clicking the blocks in the game lags horribly. The overall while loop seems to run at a constant speed per my std::cout commands. It's just the mouse clicks or keyboard entry. If I commnent the function call out, other than looking strange, it runs and functions fine.

If you wouldn't mind, look this over and let me know where I've messed up. Thanks.

#SelectExpand
1void star_background() 2{ 3 static int y1 = 0; 4 static int y2 = -480; 5 6 al_set_target_bitmap(buffer); 7 8 al_clear_to_color(COLOR::BLACK); 9 al_draw_bitmap(still, 0,0,0); 10 al_convert_mask_to_alpha(stars,COLOR::WHITE); 11 al_draw_bitmap(stars, 0,y1, 0); 12 al_draw_bitmap(stars, 0,y2, 0); 13 y1++; 14 y2++; 15 if(y1>480) 16 y1 =-480; 17 if(y2>478) 18 y2 = -480; 19 20} // end of star_background

DanielH
Member #934
January 2001
avatar

1. Huge issue is al_convert_mask_to_alpha. It should be done once right after the bitmap is loaded or created. That function goes through every pixel. Does a comparison to your color and sets alpha to zero if there is a match. EVERY pixel. Very time consuming.
2. is target restored? Don't set it to another bitmap if not restored back to original bitmap.
3. SEPARATE logic and drawing. Logic timing should be consistent. Drawing should be done when it can and when all logic is done.

My preferred order
1. process all input
2. do all logic based on current input states (set to process consitently at 30 times per second using a timer).
3. do all drawing when all done with logic (FPS is based on how many times I can still draw the screen per second)
4. goto 1.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

AceBlkwell
Member #13,038
July 2011
avatar

Thanks guys. I thought I was probably calling a single call over and over. I did the same thing with random number seed.

Daniel,
I have a few lines of setting target to buffer and back to target etc. I'm not sure why. If I take out the "target" bitmap, the process doesn't work. My limited logic tells me I should be able to make the buffer the target bitmap and run with it, but if I don't flip back and forth, some of the scaling commands don't work. In short, I don't understand how that process works so I'm dropping copied code and if it works I just go with it. I'm sure I'm misusing at some level.

DanielH
Member #934
January 2001
avatar

The "target" is the current bitmap ALL drawing is done to. Yes, set it to your buffer. Then set is back to the display's buffer to draw your buffer to the display's buffer.

#SelectExpand
1// save current target (may or may not be display, depending on game 2ALLEGRO_BITMAP* target = al_get_target_bitmap(); 3 4// set to your buffer 5al_set_target_bitmap(buffer); 6 7// do your drawing here (or call drawing function) 8 9// restore back to previous target 10al_set_target_bitmap(target); 11 12// draw your buffer to target 13al_draw_bitmap(buffer, 0, 0, 0); 14//al_draw_scaled_bitmap(buffer, 0, 0, al_get_bitmap_width(buffer), al_get_bitmap_height(buffer), 0, 0, al_get_display_width(display), al_get_display_height(display), 0); 15al_flip_display();

or set your buffer then set to display's buffer. No need to store current target.

I do the first just in case the display is not my final target. It usually always is.

AceBlkwell
Member #13,038
July 2011
avatar

Thx all,

So Daniel, I don't necessarily need a "target" bitmap?

I'm trying to understand why one would need to write to buffer_one, then write buffer_one to buffer_too, then buffer_too to the display? Seems like buffer_too is an extra step.

Can you give me an example of why you would need to do that?

DanielH
Member #934
January 2001
avatar

You can do all your drawing to the display or all your drawing to a bitmap then draw that bitmap to the display. Depends on what you want.

Personally, I have a buffer bitmap of pre-determined, non-changing size. I do all drawing to it. Then I scale it to whatever size the display is.

Why? 1. if the display size never changed then I might draw only to display. 2. I don't want the display to determine my graphics sizes. 16x16 tiles might be too small to display without scaling. Same goes for any fonts I have. I prefer a set size buffer for that reason. Then scale to any size needed at once.

#SelectExpand
1// option 1 2void draw_to_buffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP* buffer) 3{ 4 // save current target (may or may not be display, depending on game 5 ALLEGRO_BITMAP* target = al_get_target_bitmap(); 6 7 // set to your buffer 8 al_set_target_bitmap(buffer); 9 10 // do your drawing here (or call drawing function) 11 12 // restore back to previous target 13 al_set_target_bitmap(target); 14 15 // draw your buffer to target 16 al_draw_scaled_bitmap(buffer, 0, 0, al_get_bitmap_width(buffer), al_get_bitmap_height(buffer), 0, 0, al_get_display_width(display), al_get_display_height(display), 0); 17 al_flip_display(); 18} 19 20// option 2 21void draw_to_display(ALLEGRO_DISPLAY *display) 22{ 23 // set target to display's buffer 24 al_set_target_bitmap(al_get_backbuffer(display)); 25 26 // do your drawing here (or call drawing function) 27 28 al_flip_display(); 29} 30 31// option 3 32void draw_to_display(ALLEGRO_DISPLAY *display) 33{ 34 // by default, target is already set to display's buffer. 35 // no need to set target unless you changed it somewhere else 36 37 // do your drawing here (or call drawing function) 38 39 al_flip_display(); 40}

AceBlkwell
Member #13,038
July 2011
avatar

Thanks Daniel,

One more question concerning buffers. I've been drawing to a buffer bitmap and then flipping it to the display. Are you saying the display already has a buffer by default? Or is drawing to the display literally drawing to the screen directly?

Thanks.

DanielH
Member #934
January 2001
avatar

Yes, by default, the display has a main bitmap and the back buffer bitmap.

You draw to the back buffer then flip them. You can remove the back buffer with an ALLEGRO_SINGLE_BUFFER option.

If you set single buffer then you don't need to call al_flip_display as there is nothing to flip.

AceBlkwell
Member #13,038
July 2011
avatar

Daniel thanks for the insight. I think I'm going to try Option 2.

DanielH
Member #934
January 2001
avatar

Sounds great. If you don't need to change target to another bitmap then you don't need to call al_set_target_bitmap(al_get_backbuffer(display));

AceBlkwell
Member #13,038
July 2011
avatar

All,

Ok, I moved my al_convert_mask_to_alpha() to where I initialize the bitmap files. I removed all references of going back and forth with target / buffer bitmaps. The visual aspect of the program looks great. The moving star background works well. However, my lag is still present and it grows longer between clicks.

My question is, is there something that would cause the event queue to lag? I’ve put in std::cout print outs at different locations in the program. Granted not scientific or exact, but it does expose variations. At program start, each time through the game loop the timer is checked (timer event) so looking at my output I have a one to one condition, maybe an occasional one to two.

“Loop Check”
“Timer Check”
“Loop Check”
“Timer Check”
“Loop Check”
“Timer Check”

(Loop check is located just underneath the while() statement. The Timer check is the first item in the if(event.type == ALLEGRO_EVENT_TIMER) section)

Then as I start clicking as part of the game, the gap between them grows to one Timer Check to five or six Loop Checks. If I stop clicking after 5-10 sec it goes back to one to one. It’s almost like the event queue, which would include key down and mouse clicks slows down or doesn’t samples as fast. I must point out, if you have the patience, the games functions as it should. It's just the mouse click results lag horribly.

While the star code earlier in the thread may not be problematic, when I comment it out my lag issue goes away. Maybe it’s the bitmaps being used with in the star code.

Any ideas / comments are welcome. If I don’t hear back, have a great 4th holiday.

DanielH
Member #934
January 2001
avatar

Is it possible to post the code? At least the loop and event sections?

I suspect the issue is there.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

AceBlkwell
Member #13,038
July 2011
avatar

I'll send the loop data. First I want to ask a follow up on my original question.

I thought I no longer needed a target bitmap and I could work with the buffer bitmap only. But when I commented the target code out, my screen won't change from the title screen. If I choose Setup, the screen changes fine. If I choose Play, it doesn't. Below is the code for drawing the game play itself. Can you tell me why I would still need the target code? I'm thinking I started using it when I started working with the scale command. Maybe it requires it. Let me know what you think. Thanks.

#SelectExpand
1void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[]) 2{ 3 target = al_get_target_bitmap(); 4 al_set_target_bitmap(buffer); 5 star_background(); 6 display_verbiage(nError,nGameOver,nTurnPos,nPlayer); 7 draw_cards(Cards); 8 9 al_set_target_bitmap(target); 10 al_draw_scaled_bitmap(buffer, 0, 0, nBufferWD, nBufferHT, 0, 0, nDispWD, nDispHT, 0); 11 al_flip_display(); 12} // end display_print

DanielH
Member #934
January 2001
avatar

ALL drawing functions draw to the target bitmap. What's your target? Is it the display's back buffer or your buffer?

If you don't use a buffer and always draw to the display then you don't need to mess with the targeting.

If you use a buffer and want to draw to that buffer then you need to change the current target to that buffer. Draw to the buffer. Then change the current target again back to previous target (the display's back buffer). Then draw your buffer to the display.

Scaling is tricky if you don't use a buffer. You would have to scale each bitmap drawn to the display and calculate the scaled position. Or use transforms, which is what the scale functions use in the background.

I find it so much easier to use a buffer and scale it once after I draw everything to it.

AceBlkwell
Member #13,038
July 2011
avatar

This is a situation where I copied the scale code & altered for my needs without understanding what is going on.

If I comment out both lines 3 & 9, the program won't run. Or the screen won't change from the title screen.

I don't write to target (Line 3)so I'm not sure why it's needed. In line 4 I set the targeted bitmap to buffer. I draw in star background(), display verbiage(), & draw cards() functions. I assume they are drawing to the buffer bitmap since it's the last set as the targeted bitmap. Upon returning I scale the buffer bitmap and flip. The actual target bit map in line 3 isn't used at all.

In any case, I vaguely remember when looking into the scale command, someone saying I needed to switch the targeted bitmap to a second bitmap (target bitmap in this case) before scaling the buffer bitmap. It's like they are saying a targeted bitmap can't be scaled. This maybe the case, but I'm not understanding why.

Thanks

*UPDATE*
Ok, I researched further. As I understand, the scale command scales the bitmap listed in the command (buffer) to a second bitmap that is currently targeted. The the flip writes the targeted bitmap to the display. I thought buffer bitmap was being flipped. The targeted bitmap (target in this case) in my program is the scaled version of the buffer bitmap. Now I get it I think.

BTW using names like target and buffer in the program makes sense, but not very helpful when trying to explain your program flow. I think I need to come up with a new naming scheme.

DanielH
Member #934
January 2001
avatar

There's a bit of confusion on 'target' especially. It's just a bitmap. By default it is the display's back buffer bitmap.

I didn't make the names

Target = Destination
Buffer = temp storage

In allegro 4 and previous, you could specify the target as a parameter
void blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);

in this function dest is the target bitmap of the draw call.

In allegro 5, target is implied
void al_draw_bitmap(ALLEGRO_BITMAP *source, float dx, float dy, int flags);

#SelectExpand
1void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[]) 2{ 3 // get current bitmap target 4 target = al_get_target_bitmap(); 5 6 // set current bitmap target to the bitmap buffer 7 al_set_target_bitmap(buffer); 8 9 // draw to target bitmap 10 star_background(); 11 display_verbiage(nError,nGameOver,nTurnPos,nPlayer); 12 draw_cards(Cards); 13 14 // set to previous target (probably the display's bitmap buffer) 15 al_set_target_bitmap(target); 16 17 // draw to target bitmap 18 al_draw_scaled_bitmap(buffer, 0, 0, nBufferWD, nBufferHT, 0, 0, nDispWD, nDispHT, 0); 19 20 // swap front and back buffers 21 al_flip_display(); 22}

Like I said, you don't need your bitmap if you draw directly to the display back bitmap.

void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[])
{
  // draw to display's back buffer
  star_background();
  display_verbiage(nError,nGameOver,nTurnPos,nPlayer);
  draw_cards(Cards);

  // swap front and back buffers
  al_flip_display();
}

AceBlkwell
Member #13,038
July 2011
avatar

Thanks Daniel.

At some point in this thread you and Edgar asked for my game loop code so you could see the various events. Keep in mind, I didn't write it with the intent of sharing with others. If there are process improvements that I can make, I'm excited to hear them. I'm always open to learn from the more experienced. If your just critiquing my coding technique, I already know it's sloppy ;D.

This code is in its own file and function. In main() I show title screen and wait for choice of Play, Setup, & Quit. If Play is chosen, we end up here.

#SelectExpand
1while (!bQuit) 2{ 3 al_wait_for_event(queue, &event); 4 5 if(nTurn == 0) // Alters palyer's turn arrow 6 nTurnPos = 450; 7 if(nTurn == 1) 8 nTurnPos = 480; 9 10 if(nChoiceCount ==2) 11 { 12 13 if(bDraw == false) // clears card flipped status for card choice that didn't match 14 { // bDraw is made false after screen draw and stall of non matching cards. 15 nRest = 38; 16 for(int count = 0;count<CQTY;count++) 17 { 18 if(!Cards[count].bMatched) 19 { 20 Cards[count].bFlipped = false; 21 } 22 } // Card Flip Cleared 23 nChoiceCount=0; 24 } //if bDraw 25 } //end nChoiceCount if 26 27 28 if(event.type == ALLEGRO_EVENT_KEY_DOWN) 29 { 30 nKey = event.keyboard.keycode-1; // nKey is Card array index. Needs to start with zero. 31 if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE && nGameOver == 24) // Checks for Escape key after all 24 cards have been played 32 { 33 return false; 34 } 35 if(event.keyboard.keycode >= ALLEGRO_KEY_A && event.keyboard.keycode <= ALLEGRO_KEY_X && !Cards[nKey].bMatched) 36 { // Loop for keyboard choice A ~ X 37 Cards[nKey].bFlipped = true; 38 if(nChoiceCount == 0) nFirstChoice = nKey; 39 if((nChoiceCount == 1)&& (nKey == nFirstChoice)) nError = 1; // Checking for hitting same key 40 41 else 42 { 43 nSecondChoice = nKey; 44 nError = 0; // clears any previous duplicate choice/ 45 nChoiceCount++; 46 } 47 48 } // end if for block choice 49 50 if(nChoiceCount == 2) 51 { 52 if(Cards[nFirstChoice].nValue == Cards[nSecondChoice].nValue ) // Sets matched flag if values match 53 { 54 Cards[nFirstChoice].bMatched = true; 55 Cards[nSecondChoice].bMatched = true; 56 nGameOver+=2; // Adds to more to end of game total 57 nPlayer[nTurn]++; 58 bTurn = true; 59 } // end match if 60 if((Cards[nFirstChoice].bFlipped && Cards[nSecondChoice].bFlipped )&&(Cards[nFirstChoice].nValue != Cards[nSecondChoice].nValue )) 61 { // allows two nonmatching cards to be drawn and stay visible for X.XX secs 62 bDraw = true; // bDraw prevents the resetting of the cards prior to being visible. 63 64 } 65 switch(nTurn) // Switch to alter players back and forth. 66 { 67 case 0: 68 if(!bTurn) 69 nTurn = 1; 70 bTurn = false; 71 break; 72 case 1: 73 if(!bTurn) 74 nTurn = 0; 75 bTurn = false; 76 break; 77 } // end nTurn switch 78 }// end if nChoiceCount == 2 actions 79 }// end if event.type 80 81 if(event.type == ALLEGRO_EVENT_MOUSE_AXES) 82 { 83 nPos_y = event.mouse.y; 84 nPos_x = event.mouse.x; 85 } // end mouse axis 86 87 if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) //Checking to see if mouse location is within Card location 88 { 89 90 for(int count = 0;count<CQTY;count++) 91 { 92 if(nPos_x >= (Cards[count].fTX*fPercent_Diff_WD) && nPos_y >= (Cards[count].fTY*fPercent_Diff_HT)) 93 { 94 if(nPos_x <= (Cards[count].fBX*fPercent_Diff_WD) && nPos_y <= (Cards[count].fBY*fPercent_Diff_HT)) 95 { 96 if(!Cards[count].bMatched) // Checks to see if choice is already matched or chosen. 97 { 98 Cards[count].bFlipped = true; 99 if(nChoiceCount == 0) nFirstChoice = count; 100 if((nChoiceCount == 1)&& (count == nFirstChoice)) nError = 1; 101 else 102 { 103 nSecondChoice = count; 104 nError = 0; 105 nChoiceCount++; 106 } //end else 107 } //end if for matched card re-click 108 }// end if for bottom corner check 109 } //end if for top corner check 110 }// end for 111 if(nChoiceCount == 2) // Sets matched flag if values match 112 { 113 if(Cards[nFirstChoice].nValue == Cards[nSecondChoice].nValue ) 114 { 115 Cards[nFirstChoice].bMatched = true; 116 Cards[nSecondChoice].bMatched = true; 117 nGameOver += 2 ; // adds 2 to game end total 118 nPlayer[nTurn]++; 119 bTurn = true; 120 } // end match if 121 122 if((Cards[nFirstChoice].bFlipped && Cards[nSecondChoice].bFlipped )&&(Cards[nFirstChoice].nValue != Cards[nSecondChoice].nValue )) 123 { // allows two non-matching cards to be drawn and stay visible for X.XX secs 124 bDraw = true; // bDraw prevents the resetting of the cards prior to being visible. 125 126 } 127 switch(nTurn) // Switch to alter players back and forth. 128 { 129 case 0: 130 if(!bTurn) 131 nTurn = 1; 132 bTurn = false; 133 break; 134 case 1: 135 if(!bTurn) 136 nTurn = 0; 137 bTurn = false; 138 break; 139 } // end nTurn switch 140 }// end if nChoiceCount == 2 actions 141 }// end button down 142 143 if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 144 { 145 bQuit = true; 146 } 147 if(event.type == ALLEGRO_EVENT_TIMER) 148 { 149 if(bDraw == true) 150 nRest--; 151 if(bDraw == true && nRest == 0) 152 bDraw = false; 153 154 display_print(Cards,nError,nGameOver,nTurnPos,nPlayer); // After all the changes and checks are made, calls card drawing, screen flipping function. 155 156 157 }// end while() 158 159return true; 160} //end game_play()

Thanks for taking the time to look it over.

DanielH
Member #934
January 2001
avatar

Couple things I see

I'll preface this by saying this is my opinion. :)

Your braces don't match. The end brace for timer is labeled // end while. That puts the draw call inside the timer code.

    if(event.type == ALLEGRO_EVENT_TIMER)
    {
      if(bDraw == true)
          nRest--;
      if(bDraw == true && nRest == 0)
        bDraw = false;
    } // end timer

    // Never link drawing to a timer. NEVER. Timers are for logic. 
    display_print(Cards,nError,nGameOver,nTurnPos,nPlayer); 
    // drawing should happen every time something changes on the screen. 
    // a boolean dirty variable can be used if it's dirty and needs a refresh
    // that should be set by the logic not the timer. dirty = (did_something_change)

That is probably most of your lag problem ... maybe. I don't like waiting for events.

the other lag I see is that you are doing a ton of logic during an event. That can't be helped unless you make some variables to store your input.

The timer should regulate the logic not your input events. That way the logic is running at the same speed regardless the computer speed. Input events are there to set your keyboard/mouse state variables (if you had them). They should be short and fast. They should not to tie up processing speed by doing logic in the events themselves.

All you need is 2 extra variables

bool mouse_is_being_pressed = false;
bool mouse_was_pressed_since_i_last_did_logic = false;

These are set in your mouse button up/down events.

if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
{
    mouse_is_being_pressed =
    mouse_was_pressed_since_i_last did_logic = true;
}
if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
{
    mouse_is_being_pressed = false;
}

Your mouse_axes event code is short enough it's fine. Then all the logic code you currently have in your button up/down should be put in the timer. or another function to keep clean.

if(event.type == ALLEGRO_EVENT_TIMER)
{
    if (mouse_was_pressed_since_i_last_did_logic)
    {
        // do your code that checks
    }
    else
    {
    }

    mouse_was_pressed_since_i_last_did_logic = false;
}

add the same for keyboard if you need to

AceBlkwell
Member #13,038
July 2011
avatar

Thanks Daniel. I'll look and see how I can rearrange. However I did find one thing confusing (shock huh?). When I first wrote a small program to test an idea for a moving star background. I notice the stars looks great until I started clicking the mouse. Then it would hang for a split second or speed up. At that time I was told on this site, can't remember by who, to put the drawing in the timer event so it would be uniformed. The thought being the time event is going to be true with each click of the clock. Does this make sense or did I misunderstand? Or is it a personal choice type thing?

Thanks again for all the help.

DanielH
Member #934
January 2001
avatar

I have heard that too and I've been trying to stop it. They think they can get uniform control by putting the drawing in the timer.

The logic handles control not the drawing.

The logic should be in the timer if you want uniformity. The drawing should either be done every loop or using the dirty boolean like I said.

Try putting the draw call outside of timer for the time being and see if that helps at all.

There are a couple other little things:

#SelectExpand
1 switch(nTurn) // Switch to alter players back and forth. 2 { 3 case 0: 4 if(!bTurn) 5 nTurn = 1; 6 bTurn = false; 7 break; 8 case 1: 9 if(!bTurn) 10 nTurn = 0; 11 bTurn = false; 12 break; 13 } // end nTurn switch 14 15// could be shortened to 16if (!bTurn) {nturn = 1 + -nTurn; bTurn = false;}

That's if it's an int. If it's a bool then you can use:
if (!bTurn) {nTurn = !nTurn; bTurn = false;}

No big deal, but I find it funny you didn't use a switch for the event types, but went with ifs. Then for something small with 2 choices you used a switch. Just a personal thing. :D

---

One thing you could to to decrease processing time. Multiplcation is expensive. Avoid if necessary or do some precalculations. Add a few extra variables to Cards[] and store already calculated values.

        if(nPos_x >= (Cards[count].fTX*fPercent_Diff_WD) && nPos_y >= (Cards[count].fTY*fPercent_Diff_HT))
        {
           if(nPos_x <= (Cards[count].fBX*fPercent_Diff_WD) && nPos_y <= (Cards[count].fBY*fPercent_Diff_HT))

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

A good event loop is the basis of all allegro programs.

#SelectExpand
1bool quit = false; 2bool redraw = true; 3 4while (!quit) { 5 if (redraw) { 6 Draw(); 7 al_flip_display(); 8 redraw = false; 9 } 10 do { 11 ALLEGRO_EVENT ev; 12 al_wait_for_event(queue , &ev); 13 if (ev.type == ALLEGRO_EVENT_TIMER) { 14 redraw = true; 15 } 16 else if (ev.type == ALLEGRO_EVENT_MOUSE_AXES) { 17 18 19 } 20 else if (ev.type == ...) { 21 22 } 23 } while (!al_is_event_queue_empty(queue)); 24 25} 26 27return 0;

Really take it to heart, because when you don't follow a proper event loop you get all kinds of problems in your program like drawing lag and input lag.

AceBlkwell
Member #13,038
July 2011
avatar

Daniel, I think the program has a larger issue. I moved the draw command but it didn't help, maybe even increased the lag. I'll dig deeper.

Edgar, I appreciate the insight. I'll look into it. I wouldn't dream of questioning someone who knows far more than I but someone on here stated part of my original issue was using if else. They suggested using ifs only. Does it really matter either way? Thanks.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

The only difference between if and else if is when you want to chain conditions.

Here both will execute.

if (a) {

}
if (b) {

}

Here the second is only triggered if !a is true.
if (a) {

}
else if (b) {

}

if/else if/switch they're all the same pretty much, but the small differences are what separates them.

Premature optimization is not good. Even a decade old computer can handle millions of multiplications per second. You're not coming anywhere near a bottleneck in performance, so write the code the way it is easiest to understand.

 1   2 


Go to: