Author Topic: Basic game programming concepts  (Read 19404 times)

chasm

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Basic game programming concepts
« on: September 24, 2013, 10:12:01 AM »
I know how to implement some basic RL components such as displaying characters in a terminal and make them moving or different kinds of dungeon algorithms. I have also written a lot of numerical programs, so it's not like I'm a complete beginner.
But when it comes to actual gameplay, I'm stuck how to do this.

Things like how (vectors, arrays, etc.) to store information about tiles (like open/closed for a door or traversable/non-traversable, etc.) or loading a new dungeon when leaving the screen, etc. So actually things that are not unique to roguelikes, but are necessary for games in general.
I haven't found any tutorial that stresses such concepts in a more general fashion, i.e. simply the ideas how to do this rather than giving instructions how to write this in a certain programming language with a certain library.

Do you know any good tutorials or even a book about this?
What would you consider the best to begin with?

I have thought about writing something similar to interactive fiction, just to get an idea how to implement acting within the game, would this be a reasonable start?

Thank you in advance.

george

  • Rogueliker
  • ***
  • Posts: 201
  • Karma: +1/-1
    • View Profile
    • Email
Re: Basic game programming concepts
« Reply #1 on: September 24, 2013, 03:37:44 PM »
Interesting question. It's true you won't see too many tutorials approach things in a totally language-agnostic way.

However your post is a bit paradoxical. You want tutorials that talk about things in a general way, but your example (vectors, arrays, etc.) is implementation details of specific languages.

Have you gone through a complete roguelike tutorial like the Python one at Roguebasin? Many times what seems obvious in observation (i.e. skimming through a tutorial) is only learned through practice (i.e. actually doing the tutorial).
« Last Edit: September 24, 2013, 03:39:28 PM by george »

Zireael

  • Rogueliker
  • ***
  • Posts: 604
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #2 on: September 24, 2013, 05:24:43 PM »
You could try using an existing engine such as T-Engine. I believe you could make an interactive fiction game using the engine easily, just making dialogs and buttons.

Trystan

  • Rogueliker
  • ***
  • Posts: 164
  • Karma: +0/-0
    • View Profile
    • my blog
Re: Basic game programming concepts
« Reply #3 on: September 24, 2013, 05:41:12 PM »
The implementation details don't really matter. Pick one approach (like storing the dungeon as an array of chars, or a dictionary of Points and Tiles, or a 2d array of Terrain instances) and play with it for a while. As long as it's encapsulated and other code isn't looking into the details of it, you'll be able to change it when you need to. Clean code hides those details anyway. So I often have a World class with methods like isOpenDoor(x,y), isClosedDoor(x,y), blocksVision(x,y), getCreature(x,y), etc. How that's handled within the Wold class (vector, arrays, etc) doesn't really matter and if it does (performance reasons, torus shaped worlds, blood splatters, etc) then I swap the implementation out for something more complex.

chasm

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #4 on: September 25, 2013, 11:42:13 AM »
Quote from: george
However your post is a bit paradoxical. You want tutorials that talk about things in a general way, but your example (vectors, arrays, etc.) is implementation details of specific languages.

I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that, array was my first idea (a vector is just similar idea-wise), maybe there are other (and better or more general) methods. But with the information “You need to store information” only, it's too general and diffictult to actually implement.

Quote from: george
Have you gone through a complete roguelike tutorial like the Python one at Roguebasin? Many times what seems obvious in observation (i.e. skimming through a tutorial) is only learned through practice (i.e. actually doing the tutorial).

I have read through the one that uses the libtcod library. However, I didn't find it useful to understand game programming profoundly. There were a couple of things that were already implemented within the library, so it wasn't explained how exactly this was coded and why it was done like that.


Quote from: Zirael
You could try using an existing engine such as T-Engine. I believe you could make an interactive fiction game using the engine easily, just making dialogs and buttons.

I don't want to use existing engines as they already have implemented those thing I want to understand.
I'm actually not really interested in interactive fiction either, but I thought that writing something simple like that could help me understand the processes behind.


Quote from: Trystan
The implementation details don't really matter. Pick one approach (like storing the dungeon as an array of chars, or a dictionary of Points and Tiles, or a 2d array of Terrain instances) and play with it for a while. As long as it's encapsulated and other code isn't looking into the details of it, you'll be able to change it when you need to. Clean code hides those details anyway. So I often have a World class with methods like isOpenDoor(x,y), isClosedDoor(x,y), blocksVision(x,y), getCreature(x,y), etc. How that's handled within the Wold class (vector, arrays, etc) doesn't really matter and if it does (performance reasons, torus shaped worlds, blood splatters, etc) then I swap the implementation out for something more complex

Your short explanation quite describes what I'm looking for, like those examples you mentioned.
I just need something to begin with.

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: Basic game programming concepts
« Reply #5 on: September 25, 2013, 03:28:25 PM »
I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that

You are talking about save and load game, right? It really is implementation specific. In C++ and with classes it's actually quite easy, when you build the structure of game as tree-like, with possibly Game World class as the owner of everything else. Each class is going through the stuff that needs to be saved and that process is reversed in loading. Although there can be some issues in loading, when you need to construct empty objects and then fill them with saved data (but they can be solved of course).

You can look at the source code of Teemu to see how I did save/load game. It can be downloaded from the home page of the game:
http://koti.mbnet.fi/paulkp/teemu/teemu.htm

Look at Save and Load functions in classes. They are all using Tar_Ball class to store information in hybrid binary/text format.

Cfyz

  • Rogueliker
  • ***
  • Posts: 194
  • Karma: +0/-0
    • View Profile
    • Email
Re: Basic game programming concepts
« Reply #6 on: September 25, 2013, 04:36:05 PM »
I think george was right to call your question paradoxical. You ask about general concepts like storing game objects information and not implementation details. Yet those are exactly what implementation details of some specific game are. For example, game may have or may not have any tiles -- this will influence inner logic tremendously, both data- and algorithm-wise. There may be or may not be any doors to open and close. Whether there will be a new dungeon to load when leaving the screen is also up to you. There are multitude of options. So you cannot just wave this point aside as something 'oh i just meant similar idea-wise'. All these design choices together are the game itself.

That's why your question looks like "any tutorial on concepts about everything?".

Try to write several mock-ups. For example, trivial ping-pong game and simplest one-screen one-level rogue-like. You'll see there are almost no similarities. You can't expect any tutorial on the subject this broad.

Vanguard

  • Rogueliker
  • ***
  • Posts: 1112
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #7 on: September 27, 2013, 12:25:50 AM »
I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that, array was my first idea (a vector is just similar idea-wise), maybe there are other (and better or more general) methods. But with the information “You need to store information” only, it's too general and diffictult to actually implement.

But it's true - what matters is that the information gets stored, not how it gets stored (notwithstanding good programming practices).

You could store every tile as a single integer or a char in a multidimensional array and that will work fine.  Open a door and that tile's variable changes from the closed door value to the open door value.  You could make your tiles objects with isPassable, isDoor, isOpen, etc. variables for each one and that would work too.  You could program doors so that they're special objects on tiles instead of being the tiles themselves.  There are any number of possible implementations.

Is any specific thing giving you trouble?

chasm

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #8 on: September 30, 2013, 10:04:53 PM »
Ok, I think I got it now, I have just hoped that there acutally would be something 'general' to begin with.
So it's difficult to specify the question I originally asked.
Although your short explanations already helped me.


Quote from: Krice
You are talking about save and load game, right? It really is implementation specific. In C++ and with classes it's actually quite easy, when you build the structure of game as tree-like, with possibly Game World class as the owner of everything else.

This approach sounds comprehensible. I surely will give it a try to follow your code you mentioned.


Quote from: Cfyz
That's why your question looks like "any tutorial on concepts about everything?".

Yes, I now admit that it actually reads like this.
I was mostly referring to concepts that are used by traditional roguelikes. But now I see that even then there are plenty of possibilities do implement this.


Quote from: Vanguard
You could store every tile as a single integer or a char in a multidimensional array and that will work fine.  Open a door and that tile's variable changes from the closed door value to the open door value.  You could make your tiles objects with isPassable, isDoor, isOpen, etc. variables for each one and that would work too.  You could program doors so that they're special objects on tiles instead of being the tiles themselves.  There are any number of possible implementations.

This also sounds very comprehensible and a good approach to begin with.
Do you know by chance a text-based roguelike that uses this approach?


Quote from: Vanguard
Is any specific thing giving you trouble?

Currently, it's basically those examples I mentioned, because I know how to make the hero move and how to generate a dungeon (classical terminal output). It's how to make him interact within the dungeon and its objects.
Moreover I don't want to simply implement something, but also understand why and how it is working.

Vanguard

  • Rogueliker
  • ***
  • Posts: 1112
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #9 on: October 01, 2013, 05:57:30 AM »
Currently, it's basically those examples I mentioned, because I know how to make the hero move and how to generate a dungeon (classical terminal output). It's how to make him interact within the dungeon and its objects.
Moreover I don't want to simply implement something, but also understand why and how it is working.

Alright, well the best way to handle that depends on what you want to do.  If your game is pretty simple and tiles don't do anything too wacky, you could make a two dimensional array for each floor, with the array's dimensions being the maximum width and the maximum height of a floor in your game.  Something like this:

Code: [Select]
int tile[MAX_SIZE_X][MAX_SIZE_Y];
or if you wanted persistent floors, maybe this instead:

Code: [Select]
int tile[MAX_FLOORS][MAX_SIZE_X][MAX_SIZE_Y];
Then elsewhere you'd have constant values for each type of tile in your dungeon.  Maybe EMPTY_FLOOR is 0, WALL is 1, OPEN_DOOR is 2, CLOSED_DOOR is 3, etc.

So let's say that the player/a monster/whatever uses the open command on coordinate 12,16, which is a closed door.  Your function might look something like this:

Code: [Select]
bool openDoor(int targetX,int targetY) {
     // If the action is unsuccessful, this should not consume the actor's turn.  If it's a monster, their AI needs to select a different action.
     // If it's the player, we can display a message about how they tried to open a wall or whatever.
     bool actionSuccessful;
     // If the tile is a closed door, we allow the actor to open it
     if(tile[targetX][targetY] == CLOSED_DOOR) {
          tile[targetX][targetY] = OPEN_DOOR;
          actionSuccessful = true;
     } else {
          actionSuccessful = false;
     }
     return actionSuccessful;
}

So the game will see that the value stored in tile[12][16] is 3, because that is the value we have associated with closed doors.  It will check whether that value matches the value for closed doors, and since it does, the game will change the value of tile[12][16] to 2, because that is the value we have associated with open doors.  Then it will set actionSuccessful to true and return the value of true so that the function that called this one will know that the door-opening attempt succeeded.

Maybe you'd want to add additional bits to check whether the actor in question is capable of opening doors at all, but you get the idea.

If you want your tiles to be more complex or more varied, making each tile an object would be a better idea.  That way each tile can have an "openable" variable, and your open door function will check for that instead.  Then you can have the function work for multiple door types without having to resort to this:

Code: [Select]
if(tileType == CLOSED_STONE_DOOR || tileType == CLOSED_WOODEN_DOOR || tileType == CLOSED_METAL_DOOR) {
     // Do whatever
}

instead you'd do

Code: [Select]
if(tile[targetX][targetY].openable == true) {
     // Do whatever
}

And then it'd be easy to give every tile the properties you want.  The burnable variable for wooden doors is set to true, but for metal doors it's false.  You could make the wooden door a member of the wooden tiles class, which is a subclass of tiles where burnable is always set to true.  Or you could have a variable for a tile's material and set it to equal a WOOD constant, which would mean the tile is burnable, and breakable if your character has enough attack power, and so forth.

If every wooden door is identical to every other wooden door (like, you can't carve anything into them and you can't partially damage them without breaking them or whatever), then another possibility is to combine the two implementations I've suggested above.  Make one object in the tiles class for each type of tile in the game.  So one object for empty floors, one object for stone walls, etc.  Then assign a constant number to each tile type.

That will allow you to make an array of integers for each tile in the game, and the value stored in the array is the number associated with the appropriate tile type.  So if the constant value for EMPTY_FLOOR is 0 and the tile at 25,19 is an empty floor, you'd set tile[25][19] to 0 and then whenever anything in the game needs to interact with 25,19, it'd look up its value in the array, see that its value is 0, and thus it is an empty floor, and from that point on the game would read whatever information it needs from the empty floor object's variables.

Does that make sense?  Is it the sort of thing you're looking for help with?

I'm sure there are people here who are much better at programming than I am.  If someone posts that I'm the worst coder of all time and my example code makes them want to gouge their eyes out, they're probably right and you should use their suggestions instead.
« Last Edit: October 05, 2013, 07:37:47 PM by Vanguard »

chasm

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #10 on: October 03, 2013, 09:59:13 PM »
Wow, this is great, thanks a lot.
I guess, I got the idea (or just an idea) how to set tile properties via integers and functions.

I haven't responded yet as I've been trying to implement it to show the result here, but I'm having some minor problems with ncurses and key capture.

I have begun with just one (simple) dungeon, the hero moving around and opening doors. I will put the code here, when I have succeeded.
I also made a boolean fuction similar to the door opening one above to determine wether a tile is passable or not.

chasm

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #11 on: October 09, 2013, 06:09:06 AM »
Ok, I still cannot get the code working. Maybe there's someone here more capable of ncurses and C who likes to give me some input.
Nevertheless, I put my code here, maybe I used some wrong approaches in the first place.

Code: [Select]
#include<stdio.h>
#include<stdbool.h>
#include<time.h>
#include<ncurses.h>

#define MAX_X 40
#define MAX_Y 70

int tile[MAX_X][MAX_Y];

// Tile Properties:
const int empty = 0;
const int wall = 1;
const int open_door = 2;
const int closed_door = 3;
const int locked_door = 4;
const int hero = 5;

// Passable objects
bool Passable(int tx, int ty)
{
  bool successful;
  if(tile[tx][ty]==empty || tile[tx][ty]==open_door)
    {successful = true;}
  else
    {successful = false;}

  return successful;
}

// Move
void Move(int x, int y)
{
  if (tile[x][y]==hero)
    {
      if(Passable(x,y+1)==true)
{tile[x][y] = tile[x][y+1];} 
      if(Passable(x-1,y)==true)
{tile[x][y] = tile[x-1][y];}
      if(Passable(x+1,y)==true)
{tile[x][y] = tile[x+1][y];}
      if(Passable(x,y-1)==true)
{tile[x][y] = tile[x][y-1];}
      else
{mvaddstr(0,0,"You cannot pass");}
    }
}

// Open Doors
bool OpenDoor(int tx, int ty)
{
  bool successful;

  if(tile[tx][ty]==closed_door)
    {
      tile[tx][ty] = open_door;
      successful = true;
      mvaddstr(0,0,"The door is opened");
    }
  else
    {
      successful = false;
      if(tile[tx][ty]==empty || tile[tx][ty]==wall)
{mvaddstr(0,0,"There is no door to open");}
      if(tile[tx][ty]==open_door)
{mvaddstr(0,0,"The door is already open");}
      if(tile[tx][ty]==locked_door)
{mvaddstr(0,0,"The door is locked");}
    }
  return successful;
}

// Generate the dungeon
void MakeMap()
{
  for (int x=1;x<=MAX_X;x++)
   {
     for (int y=1;y<=MAX_Y;y++)
      {
tile[x][y]=empty;
int x0 = MAX_X/2;
int y0 = MAX_Y/2;
tile[x0][y0]=wall;    //begin at (x0,y0)
       
for (int i=0;i<=N;i++)
  {
   // here should be a dungeon algorithm
           // just make some random distribution of
   // tile[x][y]=empty;tile[x][y]=closed_door;tile[x][y]=wall;
  }
      }
   }
}

// Put the hero
void Hero()
{
  tile[MAX_X/2][MAX_X/2]=hero;
}


void ShowMap()
{ //ncurses stuff here
  initscr();
  start_color();
  clear();
  cbreak();
  noecho();

  for (int ix=1; ix<MAX_X;ix++)
    {
      for (int iy=1; iy<=MAX_Y;iy++)
{
  switch(tile[ix][iy])
    {
    case 0:
      mvaddstr(ix,iy,"#");
break;
    case 1:
      mvaddstr(ix,iy,".");
break;     
    case 2:
      mvaddstr(ix,iy,"/");
break;
    case 3:
      mvaddstr(ix,iy,"+");
break;
    case 4:
      mvaddstr(ix,iy,"+");
break;
    case 5:
      mvaddstr(ix,iy,"@");
break;
    }
}
    }
  refresh();
  getch();
}
   
 
void Action()
{
  //starting point
  int x = MAX_X/2;
  int y = MAX_Y/2;
  wmove(stdscr,x,y);
  keypad(stdscr, true);   
  int key=getch();
 
  while (key != 'q')
  {
  switch(key)
    {
    case 'KEY_DOWN':
      Move(x,y+1);
      break;
    case KEY_LEFT:
      Move(x-1,y);
      break;
    case KEY_RIGHT:
      Move(x+1,y);
      break;
    case KEY_UP:
      Move(x,y-1);
      break;
    case 'h':
      OpenDoor(x-1,y);
      break;
    case 'j':
      OpenDoor(x+1,y);
      break;
    case 'u':
      OpenDoor(x,y-1);
      break;
    case 'n':
      OpenDoor(x,y+1);
      break;
    case 'q':
      endwin();
    default:
      mvaddstr(0,0,"Press 'q' to quit");
break;
    }
  }
}

int main()
{
  srand(time(0));
  MakeMap();
  Hero();
  ShowMap();
  Action();
  return 0;
}


Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Basic game programming concepts
« Reply #12 on: October 09, 2013, 11:52:26 AM »
Ok, I still cannot get the code working. Maybe there's someone here more capable of ncurses and C who likes to give me some input.
Nevertheless, I put my code here, maybe I used some wrong approaches in the first place.
To get help with problems in code and software, it's best to provide specific information about what went wrong - no-one can say much about something that "doesn't work", but if you say what doesn't work, when, whether there was an error message at runtime or compile time, what the error messages were, etc., then often there will be someone who's had a similar problem in the past.

Sticking to that advice will make learning to program much smoother, and will get problems solved much quicker online. Stackoverflow is a great model of this kind of interaction.

Vanguard

  • Rogueliker
  • ***
  • Posts: 1112
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #13 on: October 10, 2013, 01:53:32 PM »
Making "hero" a tile type is a Real Bad Idea.  It's confusing and it'll lead to more than a few problems.  Instead you should have heroX and heroY integers to track their location.  Better yet, make arrays of integers to store the x and y locations of every man, animal, and monster in the dungeon.

Even though programming a game is about manipulating abstract data, imo the best way to do it is to think about everything in terms of concrete nouns and verbs (with objects and variables being nouns and functions/methods being verbs).  The tile array describes different segments of the building the game is taking place in.  That description doesn't fit the hero, so he or she shouldn't be tracked by that variable.

xee

  • Newcomer
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Basic game programming concepts
« Reply #14 on: October 10, 2013, 06:42:03 PM »
I'm up to a few thousand lines of code already into my project and so far using tables to keep track of everything seems to be working out: 

;pWorldTable    coords from (0,0) to (4 Billion,4 Billion)
;     DWORD,DWORD == # entries,ID# of active area (used to calculate which WX,WY to -> to)
;     DWORD,DWORD == WorldX,WorldY   our first area starts at (2 Billion, 2 Billion)
;     DWORD,DWORD == pLocalTable,RESERVED
;     DWORD,DWORD == WorldX,WorldY   
;     DWORD,DWORD == pLocalTable,RESERVED
;               etc.
;
;   pLocalTable    coords start from (0,0) to (width of window,height of window)
;        DWORD == <RESERVED>
;        DWORD == MobsTable
;        DWORD == StructsTable
;               etc.
;
;      pMobsTable
;        DWORD,DWORD == # mobs,<RESERVED>
;        DWORD,DWORD == X|Y,pChar pointer to char/mob/item detail sheet
;        DWORD,DWORD == X|Y,pChar pointer to char/mob/item detail sheet
;               etc.
;
;      pStructsTable
;        DWORD  ==  RESERVED
;        DWORD  ==  pStructure
;        DWORD  ==  pStructure
;        ...
;        ...
;        0     
;
;         pStructure
;           DWORD,DWORD == RESERVED, RESERVED
;           DWORD,DWORD == RoomX|RoomY,RoomW|RoomH
;           DWORD,DWORD == WallX|WallY,pChar pointer to char/mob/item detail sheet
;           DWORD,DWORD == WallX|WallY,pChar pointer to char/mob/item detail sheet
;                  etc.

I use nested tables, so for instance my WorldTable contains a bunch of LocalTables and each LocalTable contains a MobTable, StructsTable and soon an ItemsTable.  And each MobsTable would list an X,Y and it's corresponding pointer to a Character Sheet of the mob/item at that location.

And everything, you, the mobs and even a piece of the wall in a structure has their own Character Sheet:

;Char sheet offsets
OFFSET_MOB_OBJ_ID   equ 0
OFFSET_MOBSPEED     equ 4
OFFSET_NAME         equ 8
OFFSET_SYMB         equ 12
OFFSET_COLOR        equ 16
OFFSET_ALTCOLOR     equ 20
OFFSET_VISIBLE      equ 24
OFFSET_MOBMEM       equ 28
    OFFSET_MOBMEM_COMBATANT equ 0
    OFFSET_MOBMEM_NUMSTEPS  equ 4
    OFFSET_MOBMEM_ENCCS     equ 8
    OFFSET_MOBMEM_ORIGPATH  equ 12
    OFFSET_MOBMEM_ALTPATH1  equ 16
    OFFSET_MOBMEM_ALTPATH2  equ 20
    OFFSET_MOBMEM_DMGMSG    equ 24
OFFSET_FONTWH       equ 32
OFFSET_STATS        equ 36
OFFSET_HPCURRHP     equ 40
OFFSET_ALLEGIANCE   equ 44
OFFSET_WEAPON       equ 48
OFFSET_DOORWAY      equ 52
OFFSET_BgXY         equ 56
OFFSET_STATUS       equ 60
OFFSET_STATUSMSG    equ 64


To keep it simple I'm just using a single character sheet for everything so not all the fields would be used by some things so I'm wasting quite a few bytes for sure but OTOH if I decide later on to implement destructible environments, the HP field is already in place for me to use for the walls for instance.

I'm using Assembly btw so I don't know if any of this would apply at all in an OOP language.