Difference between revisions of "Complete roguelike tutorial using C++ and libtcod - part 1: setting up"

From RogueBasin
Jump to navigation Jump to search
(→‎Installing libtcod: http://roguecentral.org was taken down by Jice, it would seem, or is rarely ever up--changing the link to the latest versions released via GitHub)
(19 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{Template:Complete roguelike tutorial using C++ and libtcod}}
This article is the first part of a series heavily inspired by Jotaf's excellent [[Complete Roguelike Tutorial, using python+libtcod|"Complete roguelike tutorial using python + libtcod"]].
This article is the first part of a series heavily inspired by Jotaf's excellent [[Complete Roguelike Tutorial, using python+libtcod|"Complete roguelike tutorial using python + libtcod"]].


It is intended for C++ beginners and people who want to learn how to use [http://doryen.eptalys.net/libtcod libtcod] to create a simple [[What_a_roguelike_is#|roguelike]] video game. It covers both Linux and Windows operating systems.
It is intended for C++ beginners and people who want to learn how to use [https://bitbucket.org/libtcod/libtcod libtcod] to create a simple [[What_a_roguelike_is#|roguelike]] video game. It covers both Linux and Windows operating systems.


'''The source code of this tutorial uses the C99 standard. That means that it won't compile out of the box on Visual Studio.'''
'''The source code of this tutorial uses the C99 standard. That means that it won't compile out of the box on Visual Studio.'''


While an experienced C++ developer won't have much trouble to port the code to Visual Studio, if you're a C++ beginner, I strongly advise to use one of the [[Complete roguelike tutorial using C++ and libtcod - extra 1: about editors and IDE|suggested compilers/IDE]].
While an experienced C++ developer won't have much trouble to port the code to Visual Studio, if you're a C++ beginner, I strongly advise to use one of the [[Complete roguelike tutorial using C++ and libtcod - extra 1: about editors and IDE|suggested compilers/IDE]].
<center><big>[https://bitbucket.org/libtcod/tutorial/src/7f4f77fab400/src1/?at=master View source here]</big></center>


==Introduction==
==Introduction==
Line 47: Line 50:


'''When installing Mingw, you must absolutely choose the "Use pre-packaged repository catalogues" option. Apparently, the latest version is not working with libraries compiled with the previous one.'''
'''When installing Mingw, you must absolutely choose the "Use pre-packaged repository catalogues" option. Apparently, the latest version is not working with libraries compiled with the previous one.'''
For OS X/macOS :
First, you need to install [http://brew.sh/ homebrew]. Then you need to install Xcode through the App Store. Then, from the command line run the following command :
> xcode-select install
This will install gcc. Then run the following command :
> brew update && brew install gdb sdl


===Installing libtcod===
===Installing libtcod===


All you have to do is download the library corresponding to your platform from [http://roguecentral.org/doryen/libtcod/download this URL] and extract it to your hard drive.
All you have to do is download the library corresponding to your platform from [https://github.com/libtcod/libtcod/releases this URL] and extract it to your hard drive.


'''Note that the Windows/Mingw precompiled library only works with a 32 bits compiler. If you want to use a 64 bits compiler, you'll have to recompile the library.'''
'''Note that the Windows/Mingw precompiled library only works with a 32 bits compiler. If you want to use a 64 bits compiler, you'll have to recompile the library.'''
For OS X/macOS :
> git clone https://github.com/podiki/libtcod-mac.git
> cd libtcod-mac
> make -f makefiles/makefile-osx release
Also for OS X/macOS, at the time of writing this, there is a small file change to make. In the file ../libtcod-mac/include/libtcod.h on line 109, you will need to change the <SDL.h> to <SDL/SDL.h>.


==Setting up the project==
==Setting up the project==
Line 77: Line 98:
*lib/libtcod-mingw-debug.a
*lib/libtcod-mingw-debug.a
*SDL.dll
*SDL.dll
For OS X/macOS only :
*libtcod.dylib
*libtcodxx.dylib
*libtcod_debug.dylib
*libtcodxx_debug.dylib


==First program==
==First program==
Line 87: Line 114:
     TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
     TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
     while ( !TCODConsole::isWindowClosed() ) {
     while ( !TCODConsole::isWindowClosed() ) {
         TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,NULL,NULL);
        TCOD_key_t key;
         TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);
         TCODConsole::root->clear();
         TCODConsole::root->clear();
         TCODConsole::root->putChar(40,25,'@');
         TCODConsole::root->putChar(40,25,'@');
Line 97: Line 125:
You can compile this on Windows with (type a single line) :
You can compile this on Windows with (type a single line) :


  > g++ src/*.cpp -o tuto -Iinclude -Llib -ltcod-mingw-static-libgcc -static-libstdc++ -Wall
  > g++ src/*.cpp -o tuto -Iinclude -Llib -ltcod-mingw -static-libgcc -static-libstdc++ -Wall


If you want to get rid of the debug console when running the game from windows explorer, add the -mwindows flag. But since we're in the development phase, it's good to be able to get the program standard output.  
If you want to get rid of the debug console when running the game from windows explorer, add the -mwindows flag. But since we're in the development phase, it's good to be able to get the program standard output.  
Line 104: Line 132:


  > g++ src/*.cpp -o tuto -Iinclude -L. -ltcod -ltcodxx -Wl,-rpath=. -Wall
  > g++ src/*.cpp -o tuto -Iinclude -L. -ltcod -ltcodxx -Wl,-rpath=. -Wall
and on OS X/macOS with :
> gcc src/*.cpp -o tuto -Iinclude -L. -ltcod -ltcodxx -Wall


==Line by line explanation==
==Line by line explanation==
Line 125: Line 157:
Now we're starting the main game loop and we'll keep looping until the game window is closed by the player.
Now we're starting the main game loop and we'll keep looping until the game window is closed by the player.


  TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,NULL,NULL);
TCOD_key_t key;
 
This line creates a key variable we can use for handling input later.
 
  TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);


Even though we're not using keyboard input yet, we need to call [http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/console_non_blocking_input.html?c=false&cpp=true&cs=false&py=false&lua=false#2 checkForEvent] for libtcod to process the screen redraw events.
Even though we're not using keyboard input yet, we need to call [http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/console_non_blocking_input.html?c=false&cpp=true&cs=false&py=false&lua=false#2 checkForEvent] for libtcod to process the screen redraw events.
Line 150: Line 186:
     TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
     TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
     while ( !TCODConsole::isWindowClosed() ) {
     while ( !TCODConsole::isWindowClosed() ) {
         <span style="color:green">TCOD_key_t key;
         TCOD_key_t key;
         TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);
         TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);
         switch(key.vk) {
         <span style="color:green">switch(key.vk) {
             case TCODK_UP : playery--; break;
             case TCODK_UP : playery--; break;
             case TCODK_DOWN : playery++; break;
             case TCODK_DOWN : playery++; break;
Line 173: Line 209:


  TCODConsole::root->putChar(playerx,playery,'@');
  TCODConsole::root->putChar(playerx,playery,'@');
This time, we'll get the result from the checkForEvent function in a TCOD_key_t structure :
TCOD_key_t key;
TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);


The key variable contains everything we need to know about the keyboard input from the user. We can use it to update the player position :
The key variable contains everything we need to know about the keyboard input from the user. We can use it to update the player position :
Line 189: Line 220:
  }
  }
That's it. Recompile the program (you can press CTRL-R and type g++ in the terminal to recall the last compilation command).
That's it. Recompile the program (you can press CTRL-R and type g++ in the terminal to recall the last compilation command).
[[Category:Developing]]

Revision as of 23:20, 19 May 2019

Complete roguelike tutorial using C++ and libtcod
-originally written by Jice
Text in this tutorial was released under the Creative Commons Attribution-ShareAlike 3.0 Unported and the GNU Free Documentation License (unversioned, with no invariant sections, front-cover texts, or back-cover texts) on 2015-09-21.


This article is the first part of a series heavily inspired by Jotaf's excellent "Complete roguelike tutorial using python + libtcod".

It is intended for C++ beginners and people who want to learn how to use libtcod to create a simple roguelike video game. It covers both Linux and Windows operating systems.

The source code of this tutorial uses the C99 standard. That means that it won't compile out of the box on Visual Studio.

While an experienced C++ developer won't have much trouble to port the code to Visual Studio, if you're a C++ beginner, I strongly advise to use one of the suggested compilers/IDE.

View source here

Introduction

Why C++ ?

While being often criticized for being complex, for lacking features or for failing to enforce a single programming style, C++ is still one of the most used languages. Here are a few reasons that make it still relevant :

  • the language itself is public domain. It's not owned by a private company like the more elegant java or C#
  • there are compilers that produce high-performance native binaries for almost any existing platform
  • it has a great compatibility with C, which makes it easy to use with C libraries like SDL

Pre-requisite : this tutorial does not replace a C++ manual. You're supposed to have a basic knowledge of the C++ syntax and object oriented programming.

Why libtcod ?

It's easy to use and provides out of the box a lot of tools that are frequently used in a roguelike (Field of view and path finding algorithms amongst others). While browsing this tutorial, you should always have the libtcod C++ manual open. The code in this article series works with libtcod versions 1.5.1 and 1.5.2.

libtcod functions used in this article

TCODConsole::initRoot

TCODConsole::isWindowClosed

TCODSystem::checkForEvent

TCODConsole::clear

TCODConsole::putChar

TCODConsole::flush

Pre-requisites

Installing the compiler

First you need a C++ compiler. On Linux, it's easy :

> sudo apt-get install g++ gdb libsdl1.2debian-all

On Windows, follow this tutorial : libtcod 1.5.2 documentation.

When installing Mingw, you must absolutely choose the "Use pre-packaged repository catalogues" option. Apparently, the latest version is not working with libraries compiled with the previous one.

For OS X/macOS :

First, you need to install homebrew. Then you need to install Xcode through the App Store. Then, from the command line run the following command :

> xcode-select install

This will install gcc. Then run the following command :

> brew update && brew install gdb sdl

Installing libtcod

All you have to do is download the library corresponding to your platform from this URL and extract it to your hard drive.

Note that the Windows/Mingw precompiled library only works with a 32 bits compiler. If you want to use a 64 bits compiler, you'll have to recompile the library.

For OS X/macOS :

> git clone https://github.com/podiki/libtcod-mac.git
> cd libtcod-mac
> make -f makefiles/makefile-osx release

Also for OS X/macOS, at the time of writing this, there is a small file change to make. In the file ../libtcod-mac/include/libtcod.h on line 109, you will need to change the <SDL.h> to <SDL/SDL.h>.

Setting up the project

Create an empty directory somewhere on your hardrive. Inside, create 3 empty directories :

> mkdir include src lib

Then you'll have to copy those files from the libtcod directory to your project directory :

  • include/*.h
  • include/*.hpp
  • terminal.png

For Linux only :

  • libtcod.so
  • libtcodxx.so
  • libtcod_debug.so
  • libtcodxx_debug.so

For Windows only :

  • libtcod-mingw.dll
  • libtcod-mingw-debug.dll
  • lib/libtcod-mingw.a
  • lib/libtcod-mingw-debug.a
  • SDL.dll

For OS X/macOS only :

  • libtcod.dylib
  • libtcodxx.dylib
  • libtcod_debug.dylib
  • libtcodxx_debug.dylib

First program

We'll create a very simple program, just to check that we can compile and run. Let's create a src/main.cpp file :

main.cpp

#include "libtcod.hpp"
int main() {
   TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
   while ( !TCODConsole::isWindowClosed() ) {
       TCOD_key_t key;
       TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);
       TCODConsole::root->clear();
       TCODConsole::root->putChar(40,25,'@');
       TCODConsole::flush();
   }
   return 0;
}

You can compile this on Windows with (type a single line) :

> g++ src/*.cpp -o tuto -Iinclude -Llib -ltcod-mingw -static-libgcc -static-libstdc++ -Wall

If you want to get rid of the debug console when running the game from windows explorer, add the -mwindows flag. But since we're in the development phase, it's good to be able to get the program standard output.

and on Linux with :

> g++ src/*.cpp -o tuto -Iinclude -L. -ltcod -ltcodxx -Wl,-rpath=. -Wall

and on OS X/macOS with :

> gcc src/*.cpp -o tuto -Iinclude -L. -ltcod -ltcodxx -Wall

Line by line explanation

#include "libtcod.hpp"

Here we're importing all the libtcod classes declaration. Actually, before compiling the main.cpp file, the compiler will replace this line by the content of libtcod.hpp.

int main() {

This is the function that will be called when the program starts. It returns an error code. 0 : no error. Any other value : an error occured.

TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);

Here we're calling our first libtcod function to create the game window. It will contain a 80x50 console using the default font "./terminal.png". The false value indicates that we don't want to start in fullscreen mode.

initRoot is a static function inside the TCODConsole class. It's basically a global function inside the TCODConsole namespace.

while ( !TCODConsole::isWindowClosed() ) {

Now we're starting the main game loop and we'll keep looping until the game window is closed by the player.

TCOD_key_t key;

This line creates a key variable we can use for handling input later.

TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);

Even though we're not using keyboard input yet, we need to call checkForEvent for libtcod to process the screen redraw events.

TCODConsole::root->clear();

This is the first non static function we use. We access the static "root" variable inside the TCODConsole namespace. It's a pointer to the console bound to the main game window. We call the clear function on this console to erase everything with default color (black).

TCODConsole::root->putChar(40,25,'@');

Now we use putChar to print an @ in the middle of the screen, using the default color (white).

TCODConsole::flush();

This line actually generates the console image and displays it on the window.

The walking @

Now we're ready to reach the first step in any roguelike : the walking @ step :

#include "libtcod.hpp"
int main() {
   int playerx=40,playery=25;
   TCODConsole::initRoot(80,50,"libtcod C++ tutorial",false);
   while ( !TCODConsole::isWindowClosed() ) {
       TCOD_key_t key;
       TCODSystem::checkForEvent(TCOD_EVENT_KEY_PRESS,&key,NULL);
       switch(key.vk) {
           case TCODK_UP : playery--; break;
           case TCODK_DOWN : playery++; break;
           case TCODK_LEFT : playerx--; break;
           case TCODK_RIGHT : playerx++; break;
           default:break;
       }
       TCODConsole::root->clear();
       TCODConsole::root->putChar(playerx,playery,'@');
       TCODConsole::flush();
   }
   return 0;
}

We store the player position in two variables :

int playerx=40,playery=25;

and use them to draw the @ instead of the hardcoded values :

TCODConsole::root->putChar(playerx,playery,'@');

The key variable contains everything we need to know about the keyboard input from the user. We can use it to update the player position :

switch(key.vk) {
   case TCODK_UP : playery--; break;
   case TCODK_DOWN : playery++; break;
   case TCODK_LEFT : playerx--; break;
   case TCODK_RIGHT : playerx++; break;
   default:break;
}

That's it. Recompile the program (you can press CTRL-R and type g++ in the terminal to recall the last compilation command).