Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: [1] 2

Author Topic: C++ curses  (Read 13934 times)

Rotten

  • Bay Watcher
    • View Profile
C++ curses
« on: June 06, 2010, 10:01:25 pm »

So I'm pretty new to C++, currently reading through the learncpp.com tutorials (which are quite good by the way).
What kind of sucks, however, is that they're only for console applications. I was wondering if anyone had a link to a good tutorial on using the curses library to display rougelike-type stuff? Googling 'curses tutorial' was flooded with exactly what you would expect and adding in C++ or programming gave a lot of examples but not really a solid tutorial-type thing.

tl;dr Curses/pdcurses tutorial for a rougelike.
« Last Edit: June 07, 2010, 08:44:52 pm by Rotten »
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

timmeh

  • Bay Watcher
    • View Profile
    • My Portfolio
Re: C++ curses
« Reply #1 on: June 06, 2010, 10:15:30 pm »

There's a good NCurses tutorial, and all the basic stuff applies to PDCurses as well.  Just keep a window open to the PDCurses documentation, in case something doesn't work.   And if you google PDCurses SO you can get a binary installer for windows, which makes installin the library far simpler.  Fail that, there's video tutorials for setting it (and Allegro) up on CodeBlocks here.
Logged
On the Wall is a Masterfully engraved carving of Urist McHardcastle and Goblins. Urist McHardcastle is surrounded by the Goblins. The Golbins are stamping on Urist McHardcastle. Urist McHardcaste is laughing at the Goblins. The carving related to the prolonged and bloody death of Urist McHardcastle in the Fall of 1659, the Winter of 1659, and the Spring of 1660. On the engraving is an image of Cheese.

Outcast Orange

  • Bay Watcher
  • [SOMETIMES_SQUID]
    • View Profile
    • The Outcast Orange
Re: C++ curses
« Reply #2 on: June 06, 2010, 10:23:05 pm »

Using curses is very similar to not using curses.

To make a 2D text map,
 just roll through the stored map positions from top-left to bottom-right,
 like printing regular text.

When using curses, it is the same,
 but you can specify color more easily,
 pick the exact grid location to write to next,
 and the input and refreshing is a lot smoother.
Logged
[7:53:55 PM] Armok, why did you demand that I don't eat you?
[7:54:34 PM] [Armok]: woooooo

Burried Houses - Platform Explorer Demo H - Cloud Scream

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses
« Reply #3 on: June 06, 2010, 10:39:30 pm »

There's a good NCurses tutorial, and all the basic stuff applies to PDCurses as well.  Just keep a window open to the PDCurses documentation, in case something doesn't work.   And if you google PDCurses SO you can get a binary installer for windows, which makes installin the library far simpler.  Fail that, there's video tutorials for setting it (and Allegro) up on CodeBlocks here.
Thanks, the tutorial is great. I couldn't get the manual install to work, but the installer worked first try! Thanks!
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses
« Reply #4 on: June 06, 2010, 11:30:47 pm »

OK, I have a question.
I'm trying to make a little test where an 'N' moves around a field of .'s. Now I got printing the periods and the N ok, but though the program compiles fine the N doesn't budge whatever I do.
Code: [Select]
#include <curses.h>

int main()
{
initscr();
cbreak();
noecho();
int chx=0;
int chy=0;
start:
printw("............ \n");
printw("............ \n");
printw("............ \n");
printw("............ \n");
printw("............ \n");
    move (chx, chy);
addch(78);
    int ch;
    getch();
    if (ch == KEY_DOWN)
        --chy;
    else if (ch == KEY_DOWN)
        ++chy;
    else if (ch == KEY_RIGHT)
        ++chx;
    else if (ch == KEY_LEFT)
        --chx;
    else
refresh();
goto start; // I know goto statements are bad form, not sure how else to do it though
endwin();

return 0;
}
I'm 100% sure I fucked up, I'm just not sure how.
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

darius

  • Bay Watcher
  • ^^
    • View Profile
Re: C++ curses- another stupid question
« Reply #5 on: June 07, 2010, 12:37:39 am »

First while instead of gotos and your not setting ch. Should be like this:
Code: [Select]
#include <curses.h>

int main()
{
   initscr();
   cbreak();
   noecho();
   int chx=0;
   int chy=0;
   while(1) // could be for(;;)... Later replace by while(!finished) and put "if (ch=='q') finished=true;"
{
   printw("............ \n");
   printw("............ \n");
   printw("............ \n");
   printw("............ \n");
   printw("............ \n");
    move (chx, chy);
   addch(78);
    int ch= getch();
    if (ch == KEY_DOWN)
        --chy;
    else if (ch == KEY_DOWN)
        ++chy;
    else if (ch == KEY_RIGHT)
        ++chx;
    else if (ch == KEY_LEFT)
        --chx;
    else
   refresh();
   }
   endwin();

   return 0;
}

should work
Logged

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses- another stupid question
« Reply #6 on: June 07, 2010, 05:34:05 am »

Quote
int ch= getch();
Oh, so that's how you do it. I was trying to do
Quote
int ch;
getch();
Because that's what the tutorial on getch() used. Maybe I read it wrong. Thanks.
Using a While loop is also a good idea.

EDIT: Still doesn't work. I'm baffled.
« Last Edit: June 07, 2010, 05:42:51 am by Rotten »
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

darius

  • Bay Watcher
  • ^^
    • View Profile
Re: C++ curses- another stupid question
« Reply #7 on: June 07, 2010, 05:57:46 am »

 :-\
maybe the if/else statement is to blame?
Code: [Select]
if (ch == KEY_DOWN)
        --chy;
    else if (ch == KEY_DOWN)
        ++chy;
    else if (ch == KEY_RIGHT)
        ++chx;
    else if (ch == KEY_LEFT)
        --chx;
   refresh();
or better:
Code: [Select]
switch(ch)
{
case KEY_DOWN:
   --chy;
break;
case KEY_UP:
   ++chy;
break;
case KEY_RIGHT:
 ++chx;
break;
case KEY_LEFT:
  --chx;
break;
}
   refresh();

sorry that i can't test it. My c++ does not have curses and i'm too lazy to install them (using libtcod anyway).
Logged

timmeh

  • Bay Watcher
    • View Profile
    • My Portfolio
Re: C++ curses- another stupid question
« Reply #8 on: June 07, 2010, 07:27:32 am »

You're going to want something more like this:
Code: [Select]
int main()
{
  initscr();

  //The NCurses tutorial was pretty clear on this one,
  //it's in the "Initialization" section, read up on it.
  keypad(stdscr, TRUE);

  cbreak();
  noecho();
 
  int chx = 0;
  int chy = 0;

  //Using a boolean for the loop makes it easier to stop later.  Just
  //change shouldQuit to true, and the loop condition will fail next time.
  bool shouldQuit = false;
  while(shouldQuit == false)
  {
    printw("............");
    printw("............");
    printw("............");
    printw("............");
    printw("............");

    //You can combine move() and addch() like this.  Also,
    //if you read the documentation, the y (row) value has
    //to come first, both in this and the move function.  There
    //was a warning about this in the section "A word of caution"
    //in the Output "chapter".
    mvaddch(chy,chx, 78); 

    refresh();

    //getch() waits for input then *returns* it as an integer, you
    //have to store it somehow if you want to reference it later.
    int input = getch();
    switch(input)
    {
      case KEY_UP:
        //You don't want to let it move up if it's already
        //at the top, weird things can happen.
        if(chy>0) {chy--;}
        break;
      case KEY_DOWN:
        if(chy<24) {chy++;}
        break;
      case KEY_LEFT:
        if(chx>0) {chx--;}
        break;
      case KEY_RIGHT:
        if(chx<79) {chx++;}
        break;
      case 'q':  //If this looks weird, the two case conditions,
      case 'Q':  //you may want to read up on switch statements.
        shouldQuit = true;
        break;
    }
  }

  return 0;
}

You may want to review the NCurses tutorial again, it covered both the keypad() and move(y,x) mistake fairly well.

[EDIT]:  Also, I just wrote this up in the forum window, so I haven't actually tested it.  There's a decent chance I've made some incredibly stupid mistake, since my IDE wasn't there to catch me :P  Should you choose to copy-paste it you may have to correct a spelling or syntax mistake or two.  That being said, I'd highly suggest you copy it by hand, you'll probably learn more doing it yourself than by just using someone else's code.

Also, in reference to the goto thing, goto is bad, it does what it's supposed to, but you end up with a horrible mess of spaghetti code if you use it too often, or somewhere the label is hard to find from.  Google "C++ Functions", there's God-only-knows how many solid tutorials covering the basics of functions.  You may also want to read up on "Object-Oriented" programming.  Admittedly, I didn't for far too long, and it's making it hard for me to work with my old code now, wanting to change it all :P
« Last Edit: June 07, 2010, 07:37:10 am by timmeh »
Logged
On the Wall is a Masterfully engraved carving of Urist McHardcastle and Goblins. Urist McHardcastle is surrounded by the Goblins. The Golbins are stamping on Urist McHardcastle. Urist McHardcaste is laughing at the Goblins. The carving related to the prolonged and bloody death of Urist McHardcastle in the Fall of 1659, the Winter of 1659, and the Spring of 1660. On the engraving is an image of Cheese.

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses- another stupid question
« Reply #9 on: June 07, 2010, 05:00:30 pm »

Thanks for the idea of using a switch statement and using a bool to quit, hadn't thought of either of those.
I had to tweak your code a bit, it spammed the character all over the screen. adding in a move(0,0) before printing the dots fixed it though. More my fault for not putting it in the original code.

Quote
    //You can combine move() and addch() like this.  Also,
    //if you read the documentation, the y (row) value has
    //to come first, both in this and the move function.  There
    //was a warning about this in the section "A word of caution"
    //in the Output "chapter".
    mvaddch(chy,chx, 78); 
Using separate move and add statements was intentional, it makes the code a bit more clear in my opinion, and there isn't really a reason not to I don't think.
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

Outcast Orange

  • Bay Watcher
  • [SOMETIMES_SQUID]
    • View Profile
    • The Outcast Orange
Re: C++ curses- another stupid question
« Reply #10 on: June 07, 2010, 06:18:24 pm »

Combining them into one function makes a lot less code to scan through.
Think of it as "Put this at this location",
instead of "move here, and then put this down".

Also, printing an initial grid of dots like that is okay,
 but it would really show skill if you wrote a looping function to lay those down.

Take this with a grain of salt, I am a petty horrible teacher.
Logged
[7:53:55 PM] Armok, why did you demand that I don't eat you?
[7:54:34 PM] [Armok]: woooooo

Burried Houses - Platform Explorer Demo H - Cloud Scream

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses- another stupid question
« Reply #11 on: June 07, 2010, 08:43:10 pm »

Code: [Select]
#include <iostream> // I know it's not in Curses, just something quick, not hard to move over anyhow

using namespace std;

int xdot(int xdot)
{
    while (xdot < 79)
    {
        cout << ".";
        ++ xdot;
    }
}

int ydot(int ydot)
{
    while (ydot < 24)
    {
        xdot(0);
        ++ ydot;
        cout<<"\n";
    }
}


int main()
{
 ydot(0);
 return 0;
}
Eh, maybe later. Right now I'm trying to get working walls and fixing the bit that clears the screen so it doesn't delete said walls.
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

timmeh

  • Bay Watcher
    • View Profile
    • My Portfolio
Re: C++ curses
« Reply #12 on: June 07, 2010, 08:55:23 pm »

What you'll probably want is a 2D array of the tiles that should be drawn to the screen.  Then each time the game loops you clear() the screen, then loop through the array outputting the tiles, then draw the player (and eventually any items, enemies, etc).  At least, that's how I've always done it.  None of the methods I tried to only refresh the parts that needed it actually worked any faster, or at least, by such a small margin that it wouldn't matter unless I were outputting some ungodly huge map....

Again, the object oriented stuff makes this infinitely simpler.  I cannot stress enough how much you should at least read up on it.  I didn't and it's caused me more problems along the road than I care to talk about.
Logged
On the Wall is a Masterfully engraved carving of Urist McHardcastle and Goblins. Urist McHardcastle is surrounded by the Goblins. The Golbins are stamping on Urist McHardcastle. Urist McHardcaste is laughing at the Goblins. The carving related to the prolonged and bloody death of Urist McHardcastle in the Fall of 1659, the Winter of 1659, and the Spring of 1660. On the engraving is an image of Cheese.

Rotten

  • Bay Watcher
    • View Profile
Re: C++ curses
« Reply #13 on: June 07, 2010, 10:27:01 pm »

Wouldn't a much easier way to do it be simply storing the player's (or monster's) old position as well as the new position after a keypress, and simply draw a . at the old position?
It seems like it would be more efficient, as you wouldn't have to redraw the entire array.
Well, it is Curses. Probably would make a millisecond difference :p.
Logged
True, but at a certain velocity the resulting explosion expels invader-bits at fatal speeds. You don't want to be dropping trogdolyte-shaped shrapnel bombs into your boneworks.
Only in Dwarf Fortress...

Blacken

  • Bay Watcher
  • Orange Polar Bear
    • View Profile
Re: C++ curses
« Reply #14 on: June 08, 2010, 02:04:11 am »

Wouldn't a much easier way to do it be simply storing the player's (or monster's) old position as well as the new position after a keypress, and simply draw a . at the old position?
It seems like it would be more efficient, as you wouldn't have to redraw the entire array.
Well, it is Curses. Probably would make a millisecond difference :p.
Premature optimization is the root of all evil.

That optimization is premature.
Logged
"There's vermin fish, which fisherdwarves catch, and animal fish, which catch fisherdwarves." - Flame11235
Pages: [1] 2