Should you develop a game engine or a game?

As someone who developed a 3D game engine from scratch, you may want to listen to what I have to say.

If your goal is to learn what makes a game engine tick, then go ahead and develop an engine. It is the best thing you can do. I guarantee you that you will become an expert in computer graphics, OpenGL, Linear Algebra, and computational geometry algorithms.

However, developing a game engine is an INSANELY complicated task. It took me about four years to develop the basic framework of the engine. That's right. Just to develop the basic framework of a 3D game engine took that long. By "Basic" I mean that the engine has a collision detection system, a physics engine, rendering engine, animation system, a Digital Asset importer, etc.

To test the features of the engine, I decided to develop a full blown soccer game. It is still a work in progress. Here is a video of the latest game update:

 
 

Here is another video that showcases what the engine can currently do:

 
 

And here is one of the very first demos showcasing the basic framework:

 
 

All in all, it has taken me about four years to develop the engine. However, the engine is not complete yet. There are bugs and issues with it. As I work on the soccer game, I'm finding more and more issues.

An engine requires a lot of maintenance and time; time that could be better spent developing your game instead. Thus, if you just want to develop a game, use an existing game engine instead.

You may be curious how a game engine works. If that is the case, I wrote several articles on game engine development that should give you a pretty good idea how it works.

How does a game engine works?

How does a rendering engine works?

How does a physics engine works?

And if you are interested, you can get a copy of my eBook: Components of a Game Engine

Enjoy

Implementing team formation-Soccer Game v0.0.4

This week was a very productive week for the development of the soccer game. As you can see in the video, I implemented most of the 11 players per team. Currently, I'm missing the goalies.

 
 

I improved the performance of the game by disabling shadows and collision detection on all but three players; dribbling player, receiving player and defender. Thus, at any time, the engine only renders a shadow to the player currently dribbling, the player who will get a pass and the defender. The same logic was applied to the collision system. Only three players have collision detection enabled at any time. Doing so improved the performance by 20%.

You may say that doing so will reduce the aesthetics of the game, and you are right. However, when you play a soccer game, your eyes are mainly focused on the controlling player and the defender. Your vision ignores all other players' aesthetics.

I also improved the AI of the game. Supporter players no longer go out of bound whenever they search for a good passing angle. The same logic applies for defenders. They are smart enough not to go out of bound.

Additionally, I added a feature that controls the strength of the kick depending on how long you press the game buttons. The longer you press the buttons, the stronger the pass; thus the farthest the ball will travel.

Implementing the 4-4-2 team formation

Up to now, I have been developing the soccer game with relatively few game characters. The reason was obvious. I was focused on implementing the properties of individual players and not the team properties.

However, this week I focused on implementing intelligence into the team as a whole. My first task was to apply "Formation" logic into the game.

There are several formations used in soccer. I decided to use the 4-4-2 formation. That is four defenders, four midfielders and two forwards.

The idea of a formation is the following:

When the team is in attacking mode, the formation should spread out; thus creating space.

In contrast, when the team is in defending mode, the formation should shrink; reducing space. Notice that no matter the mode, the team should always keep the 4-4-2 structure.

Since at any time, the game characters could be running towards a passing angle or defending positions, it made sense to implement separate game objects that serve as reference points for the players.

These game objects (formation objects) would spread out or come together depending on the state (attacking/defending) of the team. Each player is assigned a formation object and would use the position of the formation object only as a reference. The formation objects are shown as squares in the image below.

Doing so keeps the structure of team compact and resembling a 4-4-2 formation throughout the game.

Thanks for reading.

Computing Defending Positions-Soccer Game v0.0.3

This month I worked on implementing a bit of intelligence into the soccer game. The AI system can now determine the best position for a player to receive a pass. Alternatively, the system can also determine the best defending positions to intercept a pass.

The video below shows these implementations:

 
 

Computing Passing Angles

Passing angles are important concepts in soccer. Players are always scanning their surroundings looking for passing angles to reach. Passing angles is also an important concept for the dribbling player. If the dribbling player can spot a good passing angle, the chances of scoring a goal increases.

In the mobile game, I implement a method that scans 36 segments, each 10 degrees apart. Thus, forming a circle with the dribbling player at the center.

The system does interception tests of each segment against nearby players of the opposite team. If a segment intercepts one of these players, the segment is discarded as a passing angle. If it does not intercept a player, it is kept as a possible passing angle.

In the end, the system tries to select two segments whose angle with respect to the dribbling player is 45 degrees and 135 degrees, respectively.

The system then sorts the players closest to these segments and orders them to move to these passing angles.

Computing Defending Positions

Passing angles are not only important for a team who is in possession of the ball, but also for the defending team. As a defender, learning to read passing angles is crucial. And even more important is positioning yourself in a spot where you can intercept the pass.

The system determines defending positions by scanning the movement of the supporting players. And orders the defending players to move towards the passing angle. However, the defending players do not position themselves between the dribbling players and the supporting players. Instead, the defending players stand between the supporting players and the goal.

Determining a Time Interval

In a soccer game, players are constantly scanning for passing angles and defending positions. In a mobile game, the AI system scans for passing angles and defending positions at a set interval. There is no point in scanning for these items continuously.

The key is to find a balanced time interval to compute these elements. If you make the time interval too long, you will miss good passing angles and defending positions. If you make the time interval too short, you will make unnecessary computations; since players don't move around instantly.

Unfortunately, there is no formula to find the best time interval. The time interval to compute the passing angle and defending positions is determined through experimentation.

Thanks for reading

Implementing a State Design Pattern for an A.I. System

As you may know, I decided to develop a mobile soccer game using my game engine. The reason is quite simple. I want to test the features of the game engine and hopefully find as many bugs as possible.

Developing a mobile soccer game has introduced me to the world of Artificial Intelligence. Although I am not an expert in A.I., I have learned a valuable lesson; An A.I. system uses a state machine, and this state machine should be implemented as modular as possible.

State machines are taught using if-then or switch statements. Although such implementation is OK for small projects, it also leads to spaghetti code in complex projects.

A better way to implement a State Machine is with a Design Pattern known as State Pattern. The pros of using such pattern are that your State machine becomes modular and flexible. That is, you can remove or add as many States into your code without making it a chaotic mess.

Let me show you how to implement a State Pattern.

Note: You can download the project on my Github page so you can follow along.

Create an Abstract State Class

First, implement an abstract State class as shown below:

Abstract State Class
class StateInterface {

public:

    virtual ~StateInterface(){};

    virtual void enter(Player *uPlayer)=0;

    virtual void execute(Player *uPlayer, double dt)=0;

    virtual void exit(Player *uPlayer)=0;

};

The "execute" method will perform your "State" operations. The "enter" and "exit" methods are useful methods in an A.I. system. For example, you may have a 3D model that as it enters the "state", it waves his hand. Or it performs a goodbye gestures as it exits the "state."

Implement the concrete State Classes

Then, implement the concrete state classes. In this instance, let's implement a "Walking" and "Running" state class.

Walking State class
void WalkingState::enter(Player *uPlayer){

    std::cout<<"Player entering Walking State"<<std::endl;

}

void WalkingState::execute(Player *uPlayer, double dt){

    std::cout<<"Executing Walking State"<<std::endl;

}

void WalkingState::exit(Player *uPlayer){

    std::cout<<"Player exiting Walking State"<<std::endl;

}
Running State class
void RunningState::enter(Player *uPlayer){

    std::cout<<"Player entering Running State"<<std::endl;

}

void RunningState::execute(Player *uPlayer, double dt){

    std::cout<<"Executing Running State"<<std::endl;

}

void RunningState::exit(Player *uPlayer){

    std::cout<<"Player exiting Running State"<<std::endl;

}

As explained earlier, the "execute" method is the heart of your State operation. It is in this function where most of your logic resides. Moreover, this method will be called continuously until a change of state occurs.

You may notice that the States are implemented as Singletons. You don't have to implement the State classes as singletons, but I usually do.

Implement a State Manager

The State Manager class is responsible for changing the states and keeping track of previous states. This is shown in the snippet below:

State Manager Class
void StateManager::update(double dt){

    currentState->execute(player, dt);

}

void StateManager::changeState(StateInterface *uState){

    //keep a record of previous state
    previousState=currentState;

    //call the exit method of the existing state
    if (currentState!=NULL) {
        currentState->exit(player); 
    }

    //change state to new state
    currentState=uState;

    //call the entry method of the new state
    currentState->enter(player);

}

Before changing to a new state, the manager keeps a copy of the current state. It then calls the "exit" method of the current state. Changes to the new state and calls the "enter" method of the new state.

After the "changeState" method has completed, the manager enters the "update" method, where it continuously calls the "execute" method of the current state.

Putting it all together

Let's implement a simple class called "Player." This object will hold a pointer to the State Manager object. It will also contain a "changeState" and "update" method. Note that these methods delegate its operations to the State Manager member. See snippet below:

Player class
Player::Player(StateManager *uStateManager){

    stateManager=uStateManager;

}

Player::~Player(){
}

void Player::update(double dt){

    stateManager->update(dt);
}

void Player::changeState(StateInterface *uState){

    stateManager->changeState(uState);

}

Finally, let's put the State Pattern in action.

In the "main" function, let's create a state manager object, a player object and let's change the player object state as shown below:

main() Method
//Create a State manager object
    StateManager *stateManager=new StateManager();

    //Create a player object
    Player *player=new Player(stateManager);

    //Change the state of the object to a RUNNING state
    player->changeState(RunningState::sharedInstance());

    //call the update method
    player->update(1.0);

    //Change the state of the object to a WALKING state
    player->changeState(WalkingState::sharedInstance());

    //call the update method
    player->update(1.0);

When you run the project, the output window will show the player entering, executing and exiting the state as shown below:

  • Player entering Running State
  • Executing Running State
  • Player exiting Running State
  • Player entering Walking State
  • Executing Walking State

If you want to add a new state, you simply create a new state class, without having the need to modify the if-then/switch statements commonly used in state machines.

State Patterns make the implementation of a state machine very flexible, modular and clean. If 100 years from now, you need to add more states to your project, you won't have to modify the inner workings of your application. Instead, you just create new state classes.

Hope this helps

Should you start a technical blog?

I started this blog on Dec 2014. I've been writing for about two years (and some months) and have published about 190 articles. I think I have enough experience to comment if you should or shouldn't start a technical blog.

First, let me start off with the harsh aspects of blogging.

Writing Consistently

The hardest part of blogging is making writing a habit. I love writing, but I must confess that writing regularly has been quite a challenge. There are times when an influx of writing energy flows through me that I end up writing a post a day. Other times, I go weeks or months without writing a single post. I used to fight this writing drought by forcing myself to write, but I realized that writing is like music. When it comes, it comes; there is no point in pushing it.

No rewards for a long time

This past January I got about 3.5K visits. That is the highest number of visits I've ever gotten in a month. However, during the first year, my average number of visitors was less than 20 a day.

 
 

Be prepared to write and have no one read your articles. This fact brings me to an important point; your purpose should be to HELP readers, not be concerned about your blog stats.

If helping your readers, even if it is only one, brings you satisfaction, then blogging is for you. Else, do yourself a favor and find another hobby.

Now, let me share the positive of having a blog.

Your writing will improve

Writing is a skill. You need to practice it to improve it. Blogging is the perfect stage to practice this skill. I have noticed a huge improvement in my writing. If you go back to my articles written around 2015 and compare them to recent articles, you will see improvements; not only in clarity but also grammatically.

You get to help people

Helping others is the one reason that makes blogging worthwhile. I feel an enormous sense of satisfaction every time I get a message from a reader thanking me for a post or asking for advice. This type of satisfaction is hundred times more rewarding than seeing your blog stats improve. A "Thank-You" message from readers like you, makes all the trouble of writing an article worth it.

You will become an expert

It is interesting how cracks in your understanding of a topic emerge once you start teaching others. As a matter of fact, It was writing that improved my understanding of game engine development and allowed me to complete my project.

I modified the engine's architecture several times after writing an article. Writing and teaching solidified my understanding and gave me ideas how to improve the engine. Teaching, not coding, enhanced my computer graphics knowledge.

So, should you start a technical blog?

If your goal is to express yourself through writing and you have an honest desire to help others, then blogging will be rewarding. However, if your goal is to make money like some bloggers have been able to, then be aware that the money will not come that easily and it may take a while.