Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

It's been a long time since I've had a problem I couldn't solve (happily) but unfortunately I just ran into one.

Code: Select all

#include <iostream>
#include <time.h>   //Both of these are needed for Code::Blocks to use rand
#include <stdlib.h> //Both of these are needed for Code::Blocks to use rand
#include <windows.h>

//ADD TWO PLAYER WHERE THEY HAVE TO TRAP EACH OTHER - ONE CREATES TRAPS, OTHER ATTEMPTS TO ATTACK THE OTHER PLAYER
//ADD TRAPS AS AN ARRAY (MULTI-DIMENSIONAL) WITH RANDOM GRID LOCATOR - EASIER TO CREATE MULTIPLE TRAPS ESPECIALLY FOR TWO PLAYER

#define HEIGHT 8 //I don't really no why I used #define as I don't what the difference is...
#define WIDTH 12 //It works though :)
#define TRAPS 4 //How many traps? The more traps the longer it takes to load
#define ENEMIES 3 //How many enemies? The more traps the longer it takes to load

char GameBoard[HEIGHT][WIDTH]; //GameBoard

int i, j; //Global Counters

int action, enemyMove;
bool quit = false;
int posy = 0, posx = 0; //Player pOSition - X-grid/Y-grid
int tosy = (HEIGHT-1), tosx = (WIDTH-1); //Treasure pOSition
int TrapLocations[TRAPS][2]; //Trap location array
int EnemyLocations[ENEMIES][2]; //Enemy location array

char player = 'G'; //The Player Character
char board = '.'; //Blank Board
char trap = 'T'; //Trap symbol
char treasure = 'X'; //Treasure symbol
char enemy = 'E'; //Enemy character

using namespace std;

void BlankBoard(char GameBoard[HEIGHT][WIDTH]); //Used once to create a blank board
void PrintBoard(char GameBoard[HEIGHT][WIDTH]); //Prints out the current board
void ActionLoop(char GameBoard[HEIGHT][WIDTH]); //Handles all events around a user's turn
void EnemyMove(char GameBoard[HEIGHT][WIDTH]);

int main()
{
    cout << "Please wait while the game loads...";

    for (i = 0; i < TRAPS; i++)
    {
        srand( (unsigned)time(0) );
        TrapLocations[i][0] = (rand() % (HEIGHT) + 1);
        TrapLocations[1][i] = (rand() % (WIDTH) + 1);
        Sleep(125); //Because seed is based on time this increases the randomness although decreases portability because
                    //of the need of <windows.h>
    }

    for (i = 0; i < ENEMIES; i++)
    {
        srand( (unsigned)time(0) );
        EnemyLocations[i][0] = (rand() % (HEIGHT) + 1);
        EnemyLocations[1][i] = (rand() % (WIDTH) + 1);
        Sleep(125); //Because seed is based on time this increases the randomness although decreases portability because
                    //of the need of <windows.h>
    }

    cout << string(100, '\n');
    cout << "Welcome to Dungeon Crawl!\n";
    cout << "Use the arrows on the number pad followed by enter to move\nNOTE: Make sure NUM LOCK is on!\n";
    cout << "To begin press ENTER\n> ";
    cin.get();

    BlankBoard(GameBoard);
    GameBoard[posy][posx] = player; //Creates the player on the board
    GameBoard[tosy][tosx] = treasure; //Creates the treasure
    for (i = 0; i < TRAPS; i++) //Creating traps
    {
        while (GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == trap || GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == treasure || GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == enemy || GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == player)
        {
            TrapLocations[i][0] = (rand() % (HEIGHT) + 1);
            TrapLocations[1][i] = (rand() % (WIDTH) + 1);
        }
        GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] = trap;
    }
    for (i = 0; i < ENEMIES; i++) //Creating enemies
    {
        while (GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] == trap || GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] == treasure || GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] == enemy || GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] == player)
        {
            EnemyLocations[i][0] = (rand() % (HEIGHT) + 1);
            EnemyLocations[1][i] = (rand() % (WIDTH) + 1);
        }
        GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] = enemy;
    }

    while (quit == false)
    {
        cout << string(100, '\n');
        ActionLoop(GameBoard);
    }

    cout << "\n\nPress ENTER to exit\n";
    cin.get();
    cin.get();
    return 0;
}

void BlankBoard(char GameBoard[HEIGHT][WIDTH])
{
    for (i = 0; i < HEIGHT; i++)
    {
        for (j = 0; j < WIDTH; j++)
        {
            GameBoard[i][j] = board;
        }
    }
}

void PrintBoard(char GameBoard[HEIGHT][WIDTH])
{
    for (i = 0; i < HEIGHT; i++)
    {
        for (j = 0; j < WIDTH; j++)
        {
            cout << GameBoard[i][j];
        }
        cout << endl;
    }
}

void ActionLoop(char GameBoard[HEIGHT][WIDTH])
{
    PrintBoard(GameBoard);
    cout << "\n> ";
    cin >> action;
    while (action != 2 && action != 4 && action != 6 && action != 8)
    {
        cout << "Please only use 2, 4, 6, and 8 on your number pad as arrows.\n";
        cout << "Once you choose a number press ENTER to confirm\n> ";
        cin >> action;
    }

    switch (action)
    {
        case 2:
        if (posy == (HEIGHT-1))
        break;
        else
        {
            GameBoard[posy][posx] = board;
            posy += 1;
            GameBoard[posy][posx] = player;
            if (posy == tosy && posx == tosx)
            {
                cout << "You win!\n";
                quit = true;
            }
            break;
        }

        case 4:
        if (posx == 0)
        break;
        else
        {
            GameBoard[posy][posx] = board;
            posx -= 1;
            GameBoard[posy][posx] = player;
            if (posy == tosy && posx == tosx)
            {
                cout << "You win!\n";
                quit = true;
            }
            break;
        }

        case 6:
        if (posx == (WIDTH-1))
        break;
        else
        {
            GameBoard[posy][posx] = board;
            posx += 1;
            GameBoard[posy][posx] = player;
            if (posy == tosy && posx == tosx)
            {
                cout << "You win!\n";
                quit = true;
            }
            break;
        }

        case 8:
        if (posy == 0)
        break;
        else
        {
            GameBoard[posy][posx] = board;
            posy -= 1;
            GameBoard[posy][posx] = player;
            if (posy == tosy && posx == tosx)
            {
                cout << "You win!\n";
                quit = true;
            }
            break;
        }
    }
    for (i = 0; i < TRAPS; i++)
    {
        if (GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == player)
        {
            cout << "You lose...\n";
            quit = true;
        }
    }
    for (i = 0; i < ENEMIES; i++)
    {
        if (GameBoard[EnemyLocations[i][0]][EnemyLocations[1][i]] == player)
        {
            cout << "You lose...\n";
            quit = true;
        }
    }
}

void EnemyMove(char GameBoard[HEIGHT][WIDTH])
{
    srand ( (unsigned)time(0) );
    enemyMove = (rand() % 4);
    //WORK IN PROGRESS
}
The code isn't done but does run. The problem is that sometimes it crashes at different points. I have theories but nothing concrete. If anyone has ideas I'd be glad to read them :)

Oh, and some comments are simply notes for me so I don't forget. Also, if you don't have windows just delete the windows.h include and the Sleep function and it should work pretty much the same.

Thanks

EDIT:

Oh, and my algorithm to prevent traps and enemies from going on top of each other is not working what so ever when I don't see a problem with it although am sure there is. Thanks again :/
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

The Unix nanosleep function is defined in time.h and there are other sleep functions. It's best to use a macro to wrap functions from different systems to make a program portable.

I think you can compile POSIX code for Windows. It might be best to stick with POSIX libraries where possible. I don't know how that works though.

I'll try porting your code and I will attempt to run it to see what happens.

I've gone down the C route and I don't think I'm going to focus much upon C++ for now. I'm making a Python to C converter made in C.

#define is a pre-processor (compile time) directive. When your program is compiled all occurrences of the constant are replaced by the definition.
//Because seed is based on time this increases the randomness although decreases portability because
//of the need of <windows.h>
No need to worry about that. Especially since you should only seed the pseudo-random once in a programs execution.

Well, I tried to go up and what seems to be a buffer overflow occured on this line:

Code: Select all

if (GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == player)
You have yet to add input checks on the input at the beginning of the program.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:The Unix nanosleep function is defined in time.h and there are other sleep functions. It's best to use a macro to wrap functions from different systems to make a program portable.

I think you can compile POSIX code for Windows. It might be best to stick with POSIX libraries where possible. I don't know how that works though.

I'll try porting your code and I will attempt to run it to see what happens.

I've gone down the C route and I don't think I'm going to focus much upon C++ for now. I'm making a Python to C converter made in C.
Not really into macros yet. To be honest, I have not learned anything new about C++ for months now. I have just been using my knowledge I already had about the language and have been playing around with some new stuff (such as the above program that is giving me problems). I really should get my book back though...soon. Anyway, I await your feedback.
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

I edited it with the feedback which was basically, you have an error.

Someone the other day mentioned they did not like C++ and people should use C instead. I'm on the verge of agreeing with that.

With C you can always learn C++ afterwards. Getting good with C is a good thing, I think. C has many simple "low level" features which can be used to make very powerful features and you have much control over how the program behaves.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:#define is a pre-processor (compile time) directive. When your program is compiled all occurrences of the constant are replaced by the definition.
//Because seed is based on time this increases the randomness although decreases portability because
//of the need of <windows.h>
No need to worry about that. Especially since you should only seed the pseudo-random once in a programs execution.

Well, I tried to go up and what seems to be a buffer overflow occured on this line:

Code: Select all

if (GameBoard[TrapLocations[i][0]][TrapLocations[1][i]] == player)
You have yet to add input checks on the input at the beginning of the program.
I had a feeling that #define was to do with the pre-processor although had completely forgotten.

But the program calculates the random seed using time and the loop would use the same time each time (approximately) would it not?

Add input checks? What do you mean?
Matthew wrote:I edited it with the feedback which was basically, you have an error.

Someone the other day mentioned they did not like C++ and people should use C instead. I'm on the verge of agreeing with that.

With C you can always learn C++ afterwards. Getting good with C is a good thing, I think. C has many simple "low level" features which can be used to make very powerful features and you have much control over how the program behaves.
Is C not structured though while C++ is OOP? Could that not cause some confusion? I don't have too many problems with C++ although they do arise.
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

When you call rand() it calculates the next pseudo-random number. The first time you call rand() it uses the seed value to calculate the first value. Once it has calculated the first value from the seed, it will calculate random numbers just fine. You only need one seed to create a tree so you only need one seed to create random numbers.

If you press any button other than enter at the beginning, your program corrupts. You need some input checks.

C is not structured? Just because it doesn't have the same level of OOP as C++? You can actually achieve good OOP effects with C.

C has a less cluttered standard library and prefers to give more control to the programmer. Some people say C++ is over-engineered. There are many inconsistent features which can confuse people. C is *relatively* simple.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:When you call rand() it calculates the next pseudo-random number. The first time you call rand() it uses the seed value to calculate the first value. Once it has calculated the first value from the seed, it will calculate random numbers just fine. You only need one seed to create a tree so you only need one seed to create random numbers.
So when rand() is called it uses the seed? If so I see what you're saying. I thought you had to call srand every time to create the new seed. The cplusplus.com references aren't described well (like any documentation really).
Matthew wrote:If you press any button other than enter at the beginning, your program corrupts. You need some input checks.
Oh ya, I can see that happening. As of now it has a lot of work but my main concern is with the odd crash (which I can't determine why it occurs) and the trap and enemy algorithms not working how they should. I have not had a chance to look at it but as of now I am clueless to why it is not working...
Matthew wrote:C is not structured? Just because it doesn't have the same level of OOP as C++? You can actually achieve good OOP effects with C.

C has a less cluttered standard library and prefers to give more control to the programmer. Some people say C++ is over-engineered. There are many inconsistent features which can confuse people. C is *relatively* simple.
I don't have enough of an opinion on the subject of languages, performance, or simplicity as I have not had a chance to experience many languages personally. I hope to dive into more in the future (particularly University) but am enjoying the experience learning C++. Over the two other languages I've dabbled in (Ruby and Python) it is amazing fast. They are dynamically typed though which I'm sure has something to do with (as well as Ruby being interpreted). Anyway, any discussion about the subject I will gladly attempt to carry as I find it very interesting but my facts may not always be spot on. *exhale*
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

rand() generates numbers from a seed and you only need one seed. You only need to call srand() once.

C and C++ aren't dynamic typed when declaring variables but you can keep check of datatypes at run time and create you own dynamic type system. To do this you should use structures to store information about a data structure and void pointers to store various data with one pointer.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:rand() generates numbers from a seed and you only need one seed. You only need to call srand() once.
Noted.
Matthew wrote:C and C++ aren't dynamic typed when declaring variables but you can keep check of datatypes at run time and create you own dynamic type system. To do this you should use structures to store information about a data structure and void pointers to store various data with one pointer.
I don't really have much interest in making them dynamically typed but I didn't know it was even possible. I probably wouldn't be able to do it anyway.

Regarding my previous problem(s): I fixed them. I simply changed the arguments for the loop and it works.
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

Using void pointers is rather simple. Look at this program I just made to show you:

I hope it interests you. As you can see, I only declare one variable (The void pointer) but create two data types with it.

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main (int argc, const char * argv[]) {
	void * void_ptr; //Makes a void pointer. A void pointer can point to any memory address so any data
	void_ptr = malloc(sizeof(int)); //This allocates memory for an integer
	*(int *)void_ptr = 10; // You can't dereference void pointers. This is why you need to keep track of what data types you are using. THis line assigns an integer to the memory address pointed by the void pointer which was allocated with malloc. The star on the left dereferences the pointer so you can assign data to where it points to but the void pointer is casted to an integer pointer so the program knows we want to use the pointer dereferenced to an integer space.
	printf("%i\n",*(int *)void_ptr); //This line casts the void pointer to an integer pointer. You must do this before dereferencing to the integer. The left star does the dereferencing. The right star is there because int * means an integer pointer. You must cast the void pointer to this. As long as you keep track of what data the void pointer should point to, you can cast them properly and then printf prints the integer we just go by dereferencing. Dereferencing means to get what is pointed by a pointer which is the integer.
	free(void_ptr); //This deallocates the memory allocated for the integer. This is vital to prevent memory leaks in your programming.
	void_ptr = malloc(sizeof(char *) * 6); //Now we are allocating memory for a string of 5 characters plus a null termination character.
	strcpy(void_ptr,"Hello"); //By sending in out coid pointer to strcpy, strcpy expects a char pointer so the pointer is automatically casted to a char pointer and the char array pointed by a void pointer is filled with the "Hello" string.
	puts(void_ptr); //This prints the string
	free(void_ptr); //This deallocates the memory
	//There we have used a void pointer to create an integer and a string with only one declared variable which was that void pointer.
	return 0;
}
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:Using void pointers is rather simple. Look at this program I just made to show you:

I hope it interests you. As you can see, I only declare one variable (The void pointer) but create two data types with it.

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main (int argc, const char * argv[]) {
	void * void_ptr; //Makes a void pointer. A void pointer can point to any memory address so any data
	void_ptr = malloc(sizeof(int)); //This allocates memory for an integer
	*(int *)void_ptr = 10; // You can't dereference void pointers. This is why you need to keep track of what data types you are using. THis line assigns an integer to the memory address pointed by the void pointer which was allocated with malloc. The star on the left dereferences the pointer so you can assign data to where it points to but the void pointer is casted to an integer pointer so the program knows we want to use the pointer dereferenced to an integer space.
	printf("%i\n",*(int *)void_ptr); //This line casts the void pointer to an integer pointer. You must do this before dereferencing to the integer. The left star does the dereferencing. The right star is there because int * means an integer pointer. You must cast the void pointer to this. As long as you keep track of what data the void pointer should point to, you can cast them properly and then printf prints the integer we just go by dereferencing. Dereferencing means to get what is pointed by a pointer which is the integer.
	free(void_ptr); //This deallocates the memory allocated for the integer. This is vital to prevent memory leaks in your programming.
	void_ptr = malloc(sizeof(char *) * 6); //Now we are allocating memory for a string of 5 characters plus a null termination character.
	strcpy(void_ptr,"Hello"); //By sending in out coid pointer to strcpy, strcpy expects a char pointer so the pointer is automatically casted to a char pointer and the char array pointed by a void pointer is filled with the "Hello" string.
	puts(void_ptr); //This prints the string
	free(void_ptr); //This deallocates the memory
	//There we have used a void pointer to create an integer and a string with only one declared variable which was that void pointer.
	return 0;
}
It does interest me. I was referring to doing it myself as I know it would cause more frustration at this point then fun.

I actually get errors upon compiling the code. 2 at line 12, and 2 at line 13.

Although I'm sure you must be sick of hearing this question, but I seem to have changing requirements or at least interests, but if you had to give someone advice, what would you use (libraries, etc) as a first attempt at game programming? Thanks again.
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

It depends what type of game programming.

For the most effective and efficient games programming I'd recommend using the best libraries which are tied to individual platforms. Eg. Xlib for Linux, Cocoa for OSX and the Windows APIs for Windows.. On top of this OpenGL is effective for both 3D and 2D graphics.

Oh, you will get errors if you try to compile with C++. C++ is based on C but some things are different. To get it to compile with C++ you should add c before all the library names such as cstdlib.h.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:It depends what type of game programming.

For the most effective and efficient games programming I'd recommend using the best libraries which are tied to individual platforms. Eg. Xlib for Linux, Cocoa for OSX and the Windows APIs for Windows.. On top of this OpenGL is effective for both 3D and 2D graphics.
So Windows API would handle the key presses and events?

I forgot that it was C code. My bad, it works now. Very cool.
Image
Jedi Master
Jedi Master
Posts: 336
Joined: Sun Aug 09, 2009 9:16 am
Allegiance:: Jedi
User avatar
Jedi Master
Jedi Master
Re: C++ GUI Frameworks

Post by Matthew »

The Windows APIs should handle key events, yes. I think you can also include a program which emulates the X11 window system on Windows and use Xlib with your games. Maybe not the best approach for Windows though.

And yes, the void pointer is brilliant. You have to remember it can point to anything, including structures. In C++ I think it will point to objects fine as well. It's simply a pointer to a memory address which could be anything.
Administrator
Administrator
Posts: 3307
Joined: Thu Dec 24, 2009 2:06 am
Allegiance:: Space Rome
Location: ON, Canada
User avatar
Administrator
Administrator
Re: C++ GUI Frameworks

Post by Scott »

Matthew wrote:The Windows APIs should handle key events, yes. I think you can also include a program which emulates the X11 window system on Windows and use Xlib with your games. Maybe not the best approach for Windows though.
I'm a bit frightened of the WinAPI but it's definitley something I would like to learn in the future. I'm glad to know it will handle games. Is it not commonly used to create tools and engines? ie. Animators, image editors/creators, modelling tools, etc.
Matthew wrote:And yes, the void pointer is brilliant. You have to remember it can point to anything, including structures. In C++ I think it will point to objects fine as well. It's simply a pointer to a memory address which could be anything.
I absolutely detest pointers. I have never found a use for them yet (like recursion). I know they are useful but personally I have found no reason thus far. I have actually heard some C++ programmers (much more talented than me) saying they avoid using pointers and references.
Image
Post Reply