Very basic game programming help and advices

That’s my feeling, too. HRose, you don’t have all the fundamental programming skills yet. Your Rogue game will make advanced use of all those skills Chris mentioned above.

Pick a language, study its basics, do their dumb exercises. For example, just try to write a simple Address Book program…that will teach you the fundamental of an input loop, a flexible non-array data structure, searching algorithms, modularization, DEBUGGING with a visual debugger.

Once you have this knowledge, you can study and deal with more advanced data structures needed to do all the flexible interactive things needed by a game, and know how to make use of them without making your code overly complex.

This is a great thread because it’s fun to see you working through the basic concepts :-)

You are effectively describing object-oriented programming.

The idea is that you associate functions with “boxes” (e.g. objects), and when you call an object’s function, that function operates on the contents of that box. In fact, the box may have its own definition of the code for that function.

“Boxes” come in different varieties. The varieties are called classes. Now you know the meaning of the term in both C++ and Python – it’s a very similar concept.

For example, you might have a GameObject class in your roguelike. Using pseudo-code that is somewhere in between C++ and Python, and leaving out lots of details (like how to construct / create Games or GameObjects):


class Game
{
    GameObject[][] m_objects; // 2D nested array of all the objects in the world
 
    void Update() {
        for (int j = 0; j < m_objects.Length; i++) {
            GameObject[] row = m_objects[j];
            for (int i = 0; i < row.Length; i++) {
                row[i].Update(); // tell the object to update
            }
        }
    }

    void Draw() {
        for (int j = 0; j < m_objects.Length; i++) {
            GameObject[] row = m_objects[j];
            for (int i = 0; i < row.Length; i++) {
                Console.Write(row[i].Appearance()); // draw the object's character
            }
            Console.WriteLine(); // end the line
        }
    }
 
    void Lose() { ... code for losing ... }
 
    void Destroy(GameObject object) {
        ... find the object in m_objects, and remove it ...
        ... don't forget to delete it if this is C++ ...
    }
}
 
class GameObject 
{
    Game m_game; // all GameObjects know what Game they're in
 
    char Appearance(); // get the character representing this thing on the map
 
    void Update(); // time just passed; update the thing
    void StepOn(Player stepper); // the player stepped on this object; do something to the player if appropriate
}

class Floor : GameObject
{
    char Appearance() { return '.'; } // all floors look like periods
}
 
class Player : GameObject // Player is a kind of GameObject
{
   char Appearance() { return [EMAIL="'@'"]'@'[/EMAIL]; } // player is an @ sign
   void StepOn(Player stepper) { } // players can step on each other and nothing happens
 
   int m_poisonLevel = 0; // player has a poison level
   void Poison(int strength) { m_poisonLevel = strength; }
 
   int m_health = 100; // player has 100 HP to start
   void Update() {
       if (m_poisonLevel > 0) m_poisonLevel--; // poison level drops on each Update()
       m_health -= m_poisonLevel; // health drops by current poison level
       
       if (m_health <= 0) {
            m_game.Lose(); // you lost
       }
   }
}
 
class PoisonTrap : GameObject
{
    char Appearance() { return '^'; } // deadly pointy spike
    void StepOn(Player stepper) {
        stepper.Poison(10); // poison the player
        game.Destroy(this); // this trap is now no longer in existence
    }
}

In this kind of structure, each little piece of your program is a little box (e.g. object), and each kind of box (e.g. each class of object) has different functions you can call on it. Each class of object redefines those functions to give the object its particular behavior.

So here, all GameObjects have a character appearance, they all have an Update() function to update them as time passes, and they all have a StepOn(Player) function that is called if the player steps on the object. The PoisonTrap class redefines StepOn to poison the player and to delete the trap itself when stepped on. The Player class redefines Update to decrement the poison level and to drop the player’s health, and to lose the game if health drops to zero.

The fundamental point here is that you always want to organize your program into small pieces that have limited, well-defined interactions with each other. My last post made this point at the higher levels of the system (e.g. handle rendering as one piece, sound as another, etc.), but it’s just as true in your gameplay logic. Your game objects, and your game world itself, should all be broken down into small units that interact with each other in limited ways. That way, if one object in your game world is behaving badly, you can change just that object and be confident that no other part of your gameplay will break, because no other part of your game logic has direct access to the internals of that object.

Make sense? I would definitely suggest you try making a very rudimentary Game and GameObject structure (2D array of GameObjects ought to work, something like the above, one per tile on your map), and start out with just making it draw itself (by cycling over all the GameObjects in the array and calling Appearance() on each, and just outputting the characters to the console). This would be a great starting point and would let you then start adding input handling, game logic, etc., bit by bit.

ADVANCED DIGRESSION:

And just as an example of the kind of issues that you start hitting immediately: the Game.Destroy(GameObject) function above says “find the game object in m_objects.” This could be expensive if your map is very big. So should you instead pass in the location of the relevant GameObject? Should GameObjects know their location? If they do, it means they can efficiently know where they are; but it also means that now the location is stored in two places (inside the GameObject, and in the Game.m_objects array), and if these two notions of “where the thing is” get out of sync (due to a bug), you now have very weird behavior indeed. It might be better to pass around the object’s current location when you’re updating objects.

Another benefit to this: if objects DON’T know their location, then simple objects that never change (like Floor) can actually be shared – e.g. you have just one Floor object in the world, and many array slots in Game.m_objects would all point to the same Floor object. (It doesn’t matter which square of floor you’re standing on, they all act the same.) This is called the “immutable sharing” pattern – things that can never change can be shared very easily, with no one the wiser. These kinds of optimizations can be critical if your game gets large.

LESS ADVANCED DIGRESSION:

Observant readers will notice a problem: this representation (one and only one GameObject per map square) doesn’t let multiple things occupy the same square. So there is no way in this structure for a trap, a monster, and a player (or even just a floor square and a monster!) to occupy the same location. So perhaps you want two maps, one that is the “terrain” and one that is the “living creatures” – kind of like map layers. Then you could add, e.g., flying creatures that don’t trigger traps because they’re not touching the floor, etc.

Props to RepoMan. I didn’t want to spend the time to explain OOP quickly, hence the tutorial book statement. It is also fun for me to see the question leading to the progression of concepts. I was just waiting to see what series of light bulbs lit up for HRose. We can all see him asking questions about 5 or 10 bulbs away, and trying to steer him back some.

HRose, don’t give up, but know that you have more work and learning ahead of you than you thought. Using an engine may save you from worrying about some areas, but sometimes the engine expects you to know those areas in order to be used.

Dude, the simulation book you linked is about 100x more information than HRose needs. He couldn’t care less about autocorrelation coefficients or probability distribution sampling.

Now, if you want to point specifically at an intro book on game programming, how about this one on programming graphical games in Python? More graphics than HRose wants, but let’s face it, the market for books on ASCII-game programming is limited ;-)

Or, for the more low-level intro-to-C++ angle, this one looks plausible.

The best C++ short intro book i have found is

It looks cheesy but is very good and covers what you want to know to get coding.

I also like this by the creator of C++, a bit heavier but good.

I know, it was a trap. I only browsed the table of contents, and I was looking the topic of simulations and event queues. I didn’t have to chance to look inside. What was it he wanted to do again? Oh, every “turn” he’s checking something. I think I would have tried a fixed-time simulation program, so I can stick sound events and other whatnots in the queue as future events. Not as much checking! I wonder if that’ll actually work…I’ve always thought games are generally written that way…especially fighting games.

As for programming games for beginners, my neighbour used some kind of game programming environment, which supported some non-standard language for moving sprites, detecting collisions and playing sounds. The company hosted a web site for people to post their games online for others to play and rate. Too bad I don’t know the name of it.

…I just read the digressions from RepoMan. Now I know why I don’t program games. Let me just stick to boring enterprise UIs…but hmmm overlaying layers of maps…

I take no offense because I know that. I stopped trying to learn how to code more than 10 years ago, and at the time I only knew the barebone basics of procedural languages, and only started looking at the first pages of a C++ book. I really know nothing.

That’s why upthread I said that my short term plan is to read books :) But while I can easily follow books, I know that coding something is completely different. So I’ll work on a roguelike as a way to understand.

Most stuff is covered in the roguelike tutorials. I then hope that I’ll be able to learn enough to keep working on it while I learn more about the language. My only concern is about hitting walls that I can’t overcome (whether in coding or in learning from books).

In my mind coding a pen&paper combat system should be “trivial”. It’s just a list of linear instructions and dice rolls. You only have to hardcode the options that a player has. So I think that working on the “ruleset” of a game should be easy, on the coding side. And I hope that the “primitives” of handling the data and presentation of a roguelike are simple enough that I don’t get totally swamped if my knowledge of programming is rather low.

The only thing I currently know about OOP: instead of just using predefined variables and functions, you can organize the predefined variables and functions together in a more complex object, and then use the emergent object while hiding the complexity within. The language simply gives syntax to support these custom data-types.

And then inheritance and polymorphism allow mostly to reuse the code and spare the time by making clones of objects slightly modified and adapted to a different task.

But I don’t know how to really use this yet, or even the C++ syntax.

About books:
Currently for C++ I’m using two books that I had at the time. One is by Herbert Schildt and must be some very old beginner guide, the other by Bruce Eckel (C++ Inside & Out, it came out in 1992, these books frequently mention Borland C++…).
For Python I bought “Learning Python”, which is really good to read, even if 60 pages in I still have to see some code. At least it’s updated to Python 3.

I was planning to buy a good and recent C++ book. But the idea is more about buying something I can read and use long term (so huge and throughout, heavy = good) than some quick reference that I can check online.

In fact I saw that one of the most recommended books is the “C++ Primer” by Lippman, but there’s a new 5th edition that is coming out in August that covers C++11 so I thought it was a good idea to wait for it: Amazon.com (even if I liked the “C++ Primer Plus”, but everyone seems to recommend the non-plus)

That Stroustrup book looks nice too. I’m wary of Stroustrup because I see it more like sophisticated academia than getting practical, and it’s usually about ancient reference manuals that aren’t really good at making you learn. It’s as if I’m learning something that I’ll never actually use, even if it could make me very good at it.

For example, looking at the summary:
from page 337 to 567 it does “Input and Output” (including lots of work with basic graphics). Not sure how much of this will be useful for me, or all the stuff covering the STL.

Btw, I could use some links on tutorials about debugging.

Wow!, that post RepoMan made is great!.

You are still thinking in procedural coding, while objects exist in a superior level of abstraction.

Doing this:


//[1]
for(t=0;t<maxWeapons;t++){
    weaponShot(t);
}

is completely different than doing this:


//[2]
foreach(weapons){
    this.Shot();
}

//[2] (alternate syntax)

weapons.each().Shot();


[2] is thinking in bigger building blocks. And there are less possible errors. In [1] maxWeapons need to be defined, can be wrong, t may iterate outside the valid range, or 1 less than the needed range. Procedure weaponShot can be defined everywhere, but method Shot is defined on the class Weapon.

In [1] your mind is busy with the problems of iterating T, limits for the for, and other LOW LEVEL problems. These managerial problems just don’t exist in [2], your mind can focus on HIGHER LEVEL problems.

Is less keystrokes, and is easier to understand… but these are just good side effects, and not important. Are important, but not why you do this.

Since Shot() is a method defined in the class Weapon, It may need a lot of different data, that can get directly from the object instance. The Shot method may work already just by the implicit “this”. This is important, because in procedural programming, wen you need more variables, you usually have to pass these variables as parameters of the function.


function weaponShot(index t){
  /* implementation here */
}

become:


function weaponShot(index t){
     weaponShotMultiple(t,1);
}

function weaponShotMultiple(index t, int numberBullets){
  /* implementation here */
}

In OOP you may not need to create new method. Just take the number of bullets from this.numBullets. It also make so you can fill numBullets in the constructor. So the constructor create a weapon that shot 1 bullet or M bullets. The constructor is a really sexy place to define these things. You don’t have to change any code after that. A weapon that used to shot 1 bullet, now shot 2000 bullets. No code changes needed. The procedural version is inferior, need a lot more changes, these changes can introduce errors. It was tested and debugged code, but is now alpha again.

Old code:


Weapon *current = new Weapon();

New code:


Weapon  *shotgun  = new Weapon(100);//100 pellets
Weapon  *pistol = new Weapon(1);//1 bullet

Weapon *current = shotgun;

You can even move /changes/ further, and load this numberOfBullets parameter from a database or a file. Having the number of bullets of a weapon in weaponstats.ini is much better than in weaponstats.cpp or weaponstats.hpp

Horrible code:


function playerShot(){
  switch(playerWeaponType){
        case "pistol":
             if(ammo>1){
               weaponShot(1);
              ammo--;
            }
            break;
        case "shotgun": 
            if(ammo>40){
                weaponShotMultiple(2,40);
               ammo -= 40;
            }
            break;
  }
}

Cool code:


player->currentWeapon->Shot();

That’s basically right.

But I don’t know how to really use this yet…

Dude, that’s exactly what I tried to explain in this post, which I have no idea if you even saw :-\ Please comment, otherwise I’ll be wondering why I bothered!

Sometimes I expect (as an extremely novice programmer myself) that–especially in relatively basic programs–Object Oriented Programming’s very nature makes it seem as though very little is being done at any one point in the program: the giant sheet of nested statements and function calls just sort of vanishes and the program is left feeling weirdly barebones: no one place just has a bunch of code “doing stuff” left in it.

Which, to me at least, made it feel as though I hadn’t really gotten any proper work done. That perhaps, even, I was doing something wrong or not using it right.

Could be that HRose just utterly ignored you, too, though ;)

I learned with OOP and complex procedural programming sometimes boggles my mind. I guess I just think of objects as blueprints. For example, a blueprint for a model of single-wide trailer. If you instantiate a bunch, you essentially have a trailer park where all of the trailers function the same way. If the dude in trailer #3 isn’t paying his power, you just say trailer03.shutOffThePower() and trailer03 knows how to do that because the blueprint for the trailers has a method called shutOffThePower() and since 03 was created from that blueprint, it follows those rules.

Shuma, I can’t really agree. See, the thing is, anytime you do a new project of any kind, you always learn on the go.

I am starting to think that programming is one continual lifelong exercise of making something that you know is wrong, just so you can fix it and make it better. “Refactoring” is the programming term for “taking something that works and rearranging it so it still works but is cleaner inside.” And it’s the secret to progress in software.

I think that starting with your actual project can be incredibly motivating. The key thing is to figure out how to build your actual project in one-day steps. I know all about this right now because of my hobby hacking project. I need each two- to three-hour evening of hacking I get to give me some little payoff.

So I structure all the work in bite-size pieces. If a piece isn’t bite-sized enough yet, I chop it in half somehow. That way I have clarity on what the next several tiny things to do are, and I always feel like I’m making headway. Once those tiny things are done, I look at the next medium-sized thing and chop it into a few tiny things, and repeat.

If you are the kind of person who views rewriting working code as a waste of time, then this won’t work for you. But for me, rewriting working code is the heart of programming – it’s where you take what you’ve learned and make the code reflect it. And you generally don’t know how to do it right until you’ve done it wrong once or twice. The upside is, once you get it right, you’ll know exactly why, and that learning is invaluable.

“Relax. Learn to enjoy losing.” - HST
“What failure? I now know 100 things that don’t work.” - Edison (paraphrased)

So my post above is an example of how to write something like the guts of a roguelike in half a page of code. Let’s try this mental exercise:

Try to write the tiniest game ever. Just so it can draw itself as text: a game that consists of one permanently empty room. Call it Sartre.

Then add a player, an @ sign.

Then add just one feature – say, up arrow to move the player up.

Then add the other three arrow keys.

Then fix the bug that the game crashes when you hit the edge of the world.

Then add walls that you can’t move through.

Then add holes that you fall into and you die.

Then add spikes that damage you whenever you touch them. (This means adding health.)

Then look at the code you wrote and realize that it is a morass of if statements:

if (currentSquareType == 1) { // 1 means wall
// don’t do anything, can’t move that way
} else if (currentSquareType == 2) { // hole
die();
} else if (currentSquareType == 3) { // spike
playerHealth -= 10;
if (playerHealth <= 0) die();
}

Then go fix the code to use a GameObject class instead, as in my post above. This time, you’ve spent an evening not adding anything that a player can see, but instead making your own programmer life easier. Now you can just write more GameObject classes to add interesting stuff, without having to touch a single if statement.

Then add an inventory of some kind. (This means sorting out whether GameObjects can be transferred into your inventory, or whether you have a separate InventoryObject kind of thing.)

AND SO ON.

The point is, doing any kind of programming – especially self-directed hobby programming – requires breaking down the big problem into individual steps. You don’t have to break down the whole big problem into tiny steps at once. But you do have to break it into medium-sized steps, prioritize those, then break down the most important medium problem into small steps, and prioritize those, and then you get to the most important tiny steps. And that’s how you can make progress on a problem of any size, without feeling totally lost and without spending your whole life thinking and none coding.

I think it’s true that you don’t know how to do a project until you’ve done it once, which is why ideally you prototype, then throw the prototype away and design it for reals using what you learned.

In practice, it’s really hard to do that both because of time pressure on work projects and tedium pressure on hobby projects. You think “I can re-work this just enough to make it work”, and you usually can. The problem is that if you’re paying attention, you keep coming up with better ways to do it at every step of the way, so it’s potentially a never-ending cycle of throw-away and restart if you’re a perfectionist.

In this particular case, I think a rogue-like is probably small enough that you can get away with learning as you go. But I’d still say to spend some time learning the basics of OOP before you start, if that’s what you’re planning on using in the end. It just such a big paradigm shift, you’re probably going to end up starting over halfway anyways, or have some unholy bolted together monster.

Yes, perfectionism is anathema to progress.

For me, when those perfectionist urges hit, they go on the task list. Then it becomes a continual tradeoff between building new features with the structure you have, and rebuilding the structure so the next features will go in better.

If you are too perfectionistic because you’re working on your dream project, maybe working on a project you care about less would help route around that. But really when you get back to your dream project, you’ll still be just as perfectionistic… so why not tackle the core problem – perfectionism – in the context of the project you really want to be doing?

But I’d still say to spend some time learning the basics of OOP before you start, if that’s what you’re planning on using in the end. It just such a big paradigm shift, you’re probably going to end up starting over halfway anyways, or have some unholy bolted together monster.

I hear what you’re saying, and there’s some truth to that. But if you take small enough steps, then starting over halfway is really easy – if you take that leap soon enough, like, after less than a week or two of coding. Definitely agree that OOP should be in on the ground floor, not something you decide to move to after working for a solid month or two. (let alone a year or two!!!)

Also, if you modularize your app well, then some bits of it can be prototypey while others are more finalized. My scene graph is prototype city, but that’s all I need right now out of that part of it. Of course, OOP helps there as well, by giving you a good structure for modularization.

I see everything and everything will be used ;)

Though the more complex stuff requires enough time to go through. I’m accumulating lots of material even outside this thread (last thing I found is this, but for C# and mono, or this) and none of it will go wasted (including the pdf linked above)… In due time.

I have a question.

I’m using CodeBlocks and MinGW for C/C++. What the hell is LLVM? And if the goal is compile C++ code and it’s far more efficient than GCC, why doesn’t everyone jumps on it?

in the cases where raw performance is benchmarked, LLVM 2.9 trails GCC 4.6.1 in code quality (speed of the compiled programs) by about 10% on average, while compiling 20-30% faster.

thanks, google

I’m reading a bunch of stuff about it. I’m asking practical usage. If it’s THAT fast, then why it’s not universal standard? Why even bother with other compilers?

On the other hand, Clang extremely clear diagnostics are definitely easier for beginners to interpret.

P.S.
What I figured out after some research is that it’s hell to make it work on Windows, still in development and so not so well supported and so on.

I don’t think you need a roguelike to be fast. Is turn based, people can wait 200 miliseconds for the ‘turn’ to complete. You probably will be introducing a delay so the rogue don’t mave too fast.

If you’re actually looking at different C/C++ compilers, can you use the free version of Visual Studio instead? Being a graphical IDE, its debugger will help you learn more about programming than any compiler alone. A debugger can help you run a program a line at a time, and you can examine interim variable values.

If you switch, you will have to figure out how to make your old program a Project, and specify its libraries and include files correctly in the project configuration.