Are 'if' statements the backbone of all games?

This is a non-code question but I still feel that it is a beginner question and worth asking/answering.

Are if/switch statements the backbone of games written in c++?
What I mean is, does programming a game rely mostly on things like, if (some object) collides with (some other object) then (code that runs?) or:

if(mouse or keyboard event) then (object does this) etc.
A thorough answer would be very appreciated as I want to be able to make my own game but I still am lost as to good practices or how to go about making decisions in games.

Thank you in advance :)

I've been programming a game for the past several months in C++ using SDL. I'm building the game from the ground up, which includes all the movement, collision, and other basic functions that come pre-packaged in already written game engines. I'm a very novice programmer, but a lot of my code consists of if statements. I'm not sure if there is a good way of getting around it. That being said, I've been told by indie game devs not to worry about optimization until it's really necessary, especially if you're creating a simple game (mine is a 2D 16-bitish platformer). So far I haven't hit a performance wall in my program, and I don't really expect to.
It's hard to write any program without using if statements.
That said, if statements can be misused.

What I commonly see are long strings of if statements, where a loop and a single if statement operating on a table would have accomplished the same thing. It not so much a matter of efficiency as it is readability and maintainability of the code. Which is easier to understand and maintain? A string of if statements spanning 100 lines of code? Or a simple loop and if statement testing a table that takes perhaps 10 lines of code?
What I mean is, does programming a game rely mostly on things like, if (some object) collides with (some other object) then (code that runs?) or:

if(mouse or keyboard event) then (object does this) etc.
Not unless the language for the game logic is procedural and doesn't support function pointers.
There are two parts of your question: function polymorphism and event-driven programming.

First I'll address events:
Most commonly, an object that needs to do something when something happens will have some sort of Event object (e.g. OnMouseClick) that other objects can "subscribe" to; that is, these objects can pass to the Event a function or function object. When the event (lower-case 'e') is considered to have occurred, the Event calls all its subscribers in succession. Since you can subscribe to the Event by giving it one function or another, this works like an if.

Function polymorphism is the whole point of OOP. Basically, you want to say actor.move(there) without caring if actor is a spider or a car or if there is a an actual position or something more abstract like "wherever the player happens to be now". The object should figure it out. This is done by making move be a function pointer whose value can be changed. Then when a new spider is created, move is made to point to spider_move(); likewise when a new car is created. Using this with recursion it's technically possible (but obviously impractical) to write any program without using any ifs or loops.
Thanks for all your answers. I appreciate it.
Thank you hyperfine for that insight from an aspiring game programmer.

Helios, your answer intrigued me the most though, I was hoping if statements were the only things to be used, but it seems now I should definitely study function polymorphism and other stuff you mentioned here. Would you mind linking me to any good resources about this?
I know this doesn't mean I won't be using if statements any longer, but I had thought "was there any way for things to happen because of object behavior" and this seems to be it, however, I didn't understand any of it. Some links or resources would be greatly appreciated.

Thanks!
Thanks for the reply Helios. Let me ask a question to see if I understand what you're talking about. (Sorry for hijacking the thread, bryan. Hopefully this should help you out too.)

Function polymorphism is the whole point of OOP. Basically, you want to say actor.move(there) without caring if actor is a spider or a car or if there is a an actual position or something more abstract like "wherever the player happens to be now". The object should figure it out. This is done by making move be a function pointer whose value can be changed. Then when a new spider is created, move is made to point to spider_move(); likewise when a new car is created. Using this with recursion it's technically possible (but obviously impractical) to write any program without using any ifs or loops.


What I have along these lines right now is a class called Enemy. The derived classes of Enemy are all the different types of enemies in the game right now. For example, let's say I have a Bat and a Rat. In the Enemy class I've declared a virtual function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Enemy
   {
      virtual void Move_Enemy(int dt); //dt is time since last movement update
   };

class Bat: public Enemy
   {
      void Move_Enemy(int dt);
   };

Bat::Move_Enemy(int dt)
   {
      //Code for bat to fly
   }

class Rat: public Enemy
   {
      void Move_Enemy(int dt);
   };

Rat::Move_Enemy(int dt)
   {
      //Code for mouse to scurry
   }

//...rest of the game code

for(int i = 0; i < EnemyList.size(); i++) //EnemyList is a vector containing pointers to the Enemy class
   {
      EnemyList[i]->Move_Enemy(t);
   }

//...rest of the code


That's obviously a sketch of what I have, but is that the idea that you are getting at for using polymorphism?

Next question:
Most commonly, an object that needs to do something when something happens will have some sort of Event object (e.g. OnMouseClick) that other objects can "subscribe" to; that is, these objects can pass to the Event a function or function object. When the event (lower-case 'e') is considered to have occurred, the Event calls all its subscribers in succession. Since you can subscribe to the Event by giving it one function or another, this works like an if.


I never thought about handling Events like that. Let me take your example of a button being pressed. Let's say that the "A" button on the controller is pressed, which is supposed to make my character jump.

What I have right now in my program is a boolean called K_A, which is set to false if the A button is not held and true if the A button is pressed down. The main character in my game is in his own class, called Hero. I have a function called Move_Hero that basically consists of a number of if statements. Here's a snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Move_Hero(int dt)
   {
      if( K_A == true ) //jump button is pressed
         {
            if( HeroIsInAir == false ) //Boolean to tell if hero is able to jump or not
               {
                  //make hero jump
               }
         }

      if( K_RIGHT == true ) //button to run right is pressed
         {
            //Make hero move to the right
            //Check collisions, etc...
         }
   }


Now, like I said this is just a small snippet of code. In fact, the function to make my Hero move is something like 600 lines! Awful practice, I know. Anyways, is there any reason that this method isn't so good? Why do you suggest having the Hero "subscribe" to the Event of a button being pressed?
bryan177mcsc: Just any book about object oriented design should do.

hyperfine:
First question: yes, but it's generally a bad idea for the function to include the name of the class. Also, although this design is fine, a more flexible design would not tie down a Bat as a subtype of Enemy, but rather would give Actors the concept of Factions or Sides. Such a design would accomodate more complex rules, such as allowing non-player actors to fight amongst themselves, or switch sides.

Second question: There are several reasons why an event-driven design is desirable:
* The code that decides how to "route" an event is in a single place.
* The code that is interested in the event is simpler, as it doesn't have to decide when the event happens.
* All the code is more organized.
I notice that you're checking for input in a Move() function. That's usually a bad sign. Event handling should happen very close to the main loop. Sort of like
1
2
3
4
5
while (running){
    handle_events();
    update_actor_states();
    draw();
}
The input handling you're using is a symptom of not having the right control flow mechanisms. You'd like to be able to say thing.move(there), and when move() returns, thing is there. It's very difficult to accomplish without having a loop inside move().
There's a control flow mechanism that goes beautifully with event-driven programming: coroutines. I would dare to say any game can be written more elegantly with coroutines than without. Unfortunately, not many languages support them, but Lua and C++ (through Boost.Coroutines) do.

Also, although this design is fine, a more flexible design would not tie down a Bat as a subtype of Enemy, but rather would give Actors the concept of Factions or Sides.


My original rationale was that the Hero class differed from Enemy in that the Hero's movement depends on user input, while Enemies move independent of the key inputs (although, they do react to the Hero's motion). Can you suggest a simple Class hierarchy for different objects, say Hero, Bat, and Door? I realize they all share certain things in common, like they can be hit and they have HP (I open doors by shooting them a couple times). I still do not know how they would fit into a proper class hierarchy.


I notice that you're checking for input in a Move() function. That's usually a bad sign. Event handling should happen very close to the main loop.


I don't technically check for input in the Move() function; I have a game loop that is roughly like the example you gave above, with handle_events() as the first part of the loop. My handle_events() checks which buttons are pressed, and then, if a button is pressed, sets a boolean representing that key to true. I then check the truth status of those booleans inside the Move() function. I can see how this is essentially the same as what you are saying, though.

In the example code you have above, how is handle_events() sending the relevant key status to the hero, who needs to respond to them? You mentioned in your previous post that entities should "subscribe" to Events by passing a function to them. Not entirely sure what you mean by that, or how it would be implemented.

A quick glance at Coroutines shows that they are a little over my head... for now at least. Thanks for pointing them out, I'll read into it and try to understand how it works.

Thanks for all the responses.
Can you suggest a simple Class hierarchy for different objects, say Hero, Bat, and Door? I realize they all share certain things in common, like they can be hit and they have HP (I open doors by shooting them a couple times). I still do not know how they would fit into a proper class hierarchy.
Anything that can perform actions on other things is an Actor. Actors may be input-driven (PlayerActors, of which Player may be the only type) or computer-driven (NonPlayerActors).

handle_events() sending the relevant key status to the hero, who needs to respond to them
Actually, pretty much the same as what you have, but it'd be better to map the input values to values that are actually related to to the object. What I mean is, Hero::Move() doesn't need to know what keys the user is pressing, it just needs to know how the PC should move next. You would move the logic that figures this out to a callback for handle_events().
Great, thanks again for all the help!
Yes normally 'if' is heavily used. But there're some special cases.
If your language supports pattern matching, you can hardly see 'if'.
Topic archived. No new replies allowed.