|
RPG game help |
Antone333
Member #15,545
March 2014
|
ok so i am making an RPG game. I am in the process of rewriting the ENTIRE game using allegro and a simple tile set that i have made myself. but every time i as for help people always tell me one of two things with my program. 1: 2: I know more or less how to use a struct but i have no idea how to use it for the purpose that i want. People dont have to tell me that this is ugly I realize its a terrible god aweful way to make an inventory/banking system. but it was what i knew how to do. i know most people hate it when people ask for exactly how to do it. but that is pretty much what im asking for at this point, but please explain it to me in great detail if you can. You can find the function that actually allows you to mine and get ore at: 1555 ok my computer is being extremely slow at the moment and wont upload my attachment so you can find it here on google sites: https://sites.google.com/site/temprpgquestion/go-here-for-the-program Thank you all for the help in advance. i really appreciate it. so i am working on the menu screen right now and this is what i have so far |
OnlineCop
Member #7,919
October 2006
|
My first suggestion is to break your file apart. Don't EVER be afraid of splitting a single large file into smaller parts.
My second suggestion: Instead of telling us the line numbers you need advice with, specify the name of the function you need help on. Line 1555: void Start_Mining() My third suggestion: Within your Bank_Action() function, you have long if() blocks. Break those out into their own functions. I'd love to see this 3300-line function broken down to something a little more manageable: 1void Bank_Action()
2{
3 cout << endl << "You have: " << bank << " free bank spaces" << endl;
4
5 Show_Items_In_Storage();
6
7 cout << endl << "Would you like to withdraw or deposite?";
8 cout << endl << "1 deposite, 2 withdraw" << endl;
9 cin >> choice;
10 if(choice == 1)
11 {
12 Bank_Prompt_To_Deposit();
13 }
14 else if(choice == 2)
15 {
16 Bank_Prompt_To_Withdraw();
17 }
18}
Now within Bank_Prompt_To_Deposit(), you have its own if() blocks: 1void Bank_Prompt_To_Deposit()
2{
3 cout << endl << "What would you like to deposite?" << endl;
4 cout << "1 ore, 2 fish, 3 wood, 4 cooked fish" << endl;
5 cin >> choice;
6 if(choice == 1)
7 {
8 Bank_Prompt_To_Deposit_Ore();
9 }
10 else if(choice == 2)
11 {
12 Bank_Prompt_To_Deposit_Raw_Fish();
13 }
14 else if(choice == 3)
15 {
16 Bank_Prompt_To_Deposit_Wood();
17 }
18 else if(choice == 4)
19 {
20 Bank_Prompt_To_Deposit_Cooked_Fish();
21 }
22}
You'd do the same for all the rest of the stuff. Last of all, I'm not exactly sure what question you're asking. Antone333 said: ...please explain it to me in great detail if you can... What did you want explained?
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Something that would shorten your level select code would be a function pointer array. Then all you would need to do is index the array to run the function to select the level. Example : 1void SelectLevel1();
2void SelectLevel2();
3void SelectLevel3();
4
5typedef void (*LEVEL_SELECTOR_FUNC)()
6
7LEVEL_SELCTOR_FUNC level_selector_array[] = {
8 SelectLevel1 , SelectLevel2 , SelectLevel3
9};
10
11int level = GetUserLevelInput();
12// run level function
13*level_selector_array[level]();
14
15
16void SelectLevel1() {
17 // whatever
18}
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Antone333
Member #15,545
March 2014
|
@OnlineCop Wow. yeah i did not think about that. It would take care of not knowing how to use structs. i would still have to use that big long ugly list everything out but it would be so much easier just to list it once in its own function. thanks a bunch. |
OnlineCop
Member #7,919
October 2006
|
I think that two things will help this code: the use of struct or class, and replacing redundant code with functions. Many things can be simplified, like when you have text that is identical in all places except maybe the monster name or the amount of damage taken. One example is void Monster_1(): 1 int Monster = rand()%8+1;
2
3 int Monster_Health = rand()%5+5;
4 int Monster_Attack = rand()%5+1;
5 int Monster_Defence = rand()%5+1;
6
7 if(Monster == 1)
8 {
9 //system("cls");
10 cout << "A Rat has emerged." << endl << endl;
11 pause(2);
12 cout << "Enemy: " << endl << "Health: " << Monster_Health << endl << "Attack: " << Monster_Attack << endl << "Defence: " << Monster_Defence << endl << endl;
13 cout << "You: " << endl << "Health: " << Health << endl << "Attack: " << Attack_Level << endl << "Defence: " << Defence_Level << endl << endl;
14 pause(2);
15 cout << "You ready your weapon in the: 1 Defencive Position, 2 Offencive Position." << endl;
16 cin >> Monster;
17 if(Monster == 1)
18 {
19 cout << "You ready your weapon for the Rat to attack." << endl << endl;
20 cout << "The rat with its sharp fengs jumps at you. ";
21 Monster = Monster_Attack - Defence_Level;
22 cout << "It deals " << Monster << " damage.";
23 }
24 }
25 else if(Monster == 2)
26 {
27 // ...
28 }
29 else if(Monster == 3)
30 {
31 // ...
32 }
You can convert this into a simple function that you can reuse multiple times: 1int Fight_Monster(
2 const string &monster_name,
3 const string &monster_attack_type,
4 const int &monster_health,
5 const int &monster_attack,
6 const int &monster_defence,
7 const int &health,
8 const int &attack_level,
9 const int &defence_level
10)
11{
12 cout << "A " << monster_name << " has emerged." << endl << endl;
13
14 cout << "Enemy: " << endl
15 << "Health: " << monster_health << endl
16 << "Attack: " << monster_attack << endl
17 << "Defence: " << monster_defence << endl
18 << endl;
19
20 cout << "You: " << endl
21 << "Health: " << health << endl
22 << "Attack: " << attack_level << endl
23 << "Defence: " << defence_level << endl
24 << endl;
25
26 cout << "You ready your weapon in the: 1 Defencive Position, 2 Offencive Position." << endl;
27
28 int AttackOrDefendResponse;
29 cin >> AttackOrDefendResponse;
30
31 int DamageTaken = 0;
32 if(AttackOrDefendResponse == 1)
33 {
34 cout << "You ready your weapon for the " << monster_name << " to attack." << endl << endl;
35 cout << monster_attack_type << endl;
36 DamageTaken = monster_attack - defence_level;
37 cout << "It deals " << DamageTaken << " damage.";
38 }
39
40 return DamageTaken;
41}
42
43void Monster_1()
44{
45 srand(time(0));
46
47 int Monster = rand()%8+1;
48
49 int Monster_Health = rand()%5+5;
50 int Monster_Attack = rand()%5+1;
51 int Monster_Defence = rand()%5+1;
52
53 int DamageTaken = 0;
54 if(Monster == 1)
55 {
56 DamageTaken = Fight_Monster("Rat", "The rat with its sharp fengs jumps at you.",
57 Monster_Health, Monster_Attack, Monster_Defence,
58 Health, Attack_Level, Defence_Level
59 );
60 }
61 else if(Monster == 2)
62 {
63 DamageTaken = Fight_Monster("Spider", "The spider with its long legs and poisonous bite jumps at you.",
64 Monster_Health, Monster_Attack, Monster_Defence,
65 Health, Attack_Level, Defence_Level
66 );
67 }
68 else if(Monster == 3)
69 {
70 DamageTaken = Fight_Monster("Snake", "The spider with its venomous fangs lunges at you.",
71 Monster_Health, Monster_Attack, Monster_Defence,
72 Health, Attack_Level, Defence_Level
73 );
74 }
75 // ...and so on...
76
77 // Do something with 'DamageTaken'...
78}
As you can see, the text is almost the same for each battle, the logic is nearly the same, and you can simply pass in parameters to change the parts that should differ. Next, use of struct or class. For C++, they are identical except that the former makes everything public unless you specify otherwise, and the latter makes everything private unless you specify (respectively). Two perfect candidates for a struct are monsters and the player. 1struct S_Player
2{
3 string Name;
4
5 int Health;
6 int Health_Level;
7 int Health_Skill;
8 int Health_Skill_M;
9
10 int Attack_Level;
11 int Attack_Skill;
12 int Attack_Skill_M;
13
14 int Defence_Level;
15 int Defence_Skill;
16 int Defence_Skill_M;
17
18 int Fishing_Level;
19 int Fishing_Skill;
20 int Fishing_Skill_M;
21
22 int Woodcutting_Level;
23 int Woodcutting_Skill;
24 int Woodcutting_Skill_M;
25
26 int Mining_Level;
27 int Mining_Skill;
28 int Mining_Skill_M;
29
30 int Firemaking_Level;
31 int Firemaking_Skill;
32 int Firemaking_Skill_M;
33
34 int Cooking_Level;
35 int Cooking_Skill;
36 int Cooking_Skill_M;
37};
This is the general structure of the Player. It doesn't contain any data (yet). It just specifies that anything that gets defined as a Player will have a Name, will have Health and Attack/Defence attributes, and so forth. You create an instance of the player (which will contain values for all the attributes) like: S_Player player; Now, you pass around the player and it's much easier to understand whether "Health" belongs to monster.Health or player.Health. If you're struggling to understand any of these, ask.
|
Antone333
Member #15,545
March 2014
|
Yeah I get both of those just fine and will for sure be adding them into my current remaking of the project. Someone along the line of that console based game told me that I should make the inventory into I think they said boolean structure. And I was like... what? And so I didn't implant that. I tried looking it up and stuff but I just could not wrap my mind around any way to take a structure such as tuna fish; and tuna.amount; and use that in my inventory system any different then how I am already using my inventory system.couldn't quite figure out how a boolean would go in there to make it different. So where I have those big long if statements where I list everysingle item in the game and repeat for every single item in the game. If(tuna + Items list <= BankSpace) I'm on my phone at the moment because I couldn't sleep so I don't really remember how that one went exactly. But is that possible to pass all the items through a function like that in an if statement? so I don't have to type so much? Because that was by far the worst part of typing that code and why I stopped working on it where i did. Thanks a lot for all the help you guys. |
OnlineCop
Member #7,919
October 2006
|
Yes, it's actually a good idea to pass things through functions for that reason. I suggest that you create an enumeration: 1enum Ores
2{
3 Copper_Ore,
4 Tin_Ore,
5 Blurite_Ore,
6 Iron_Ore,
7 Silver_Ore,
8 Elemental_Ore,
9 Gold_Ore,
10 Mithril_Ore,
11 Adamantite_Ore,
12 Runite_Ore,
13 Magic_Ore,
14 Cursed_Ore,
15 Blood_Ore,
16 Dragon_Ore,
17 Crystal_Ore,
18
19 Number_Of_Ores // 'Number' enum entries always last
20};
Then you create an array: int All_Ores[Number_Of_Ores]; Now instead of keeping track of individual ores, you can specify exactly ONE array, index any of the individual ores whenever you want, and counting up the total ores is as simple as iterating over the array: int Total_Ore_Count = 0; for (int i = 0; i < Number_Of_Ores; i++) { Total_Ore_Count += All_Ores[i]; } cout << "You have " << Total_Ore_Count << " ores in your inventory."; You're also able to update only the ore you care about: All_Ores[Mithril_Ore] += 5; If you do that with all your other items as well (one for fish types, one for wood types), then you can get rid of that long if() block and condense it down to only a handful of lines.
|
Antone333
Member #15,545
March 2014
|
Thanks a bunch. i more or less get how to use enum but i think i could use that one. can i have an enum within an enum for example enum AllItems nothing happens. it still only displays the first map. but when i get rid of the else and have a double if statement then the opposite happens. only the second map is drawn to the screen. i am doing basically the same type of code i used for my character movement in the console to move between the maps. and will have a copy of the map arrays that is left blank except for the added in character and npc. this way i can manipulate on top of the drawn map without having to redraw it. and also the only way i know how to do collision detection. void LevelSelect() int LevelSelectArray[10][10] = { |
Thomas Fjellstrom
Member #476
June 2000
|
Nope. Enums are not nestable. -- |
Antone333
Member #15,545
March 2014
|
ok so they are not nestable. but what if i did something like this? enum all ore enum all fish enum all items |
Thomas Fjellstrom
Member #476
June 2000
|
You can probably do that. though the last enum may not be needed (I'm not sure of the purpose for that). Just note that each enum starts from 0 if you don't give it a starting value. -- |
OnlineCop
Member #7,919
October 2006
|
The last enum is not needed: correct. HOWEVER, it just "happens" to be the total number of all the items in the enum, so you don't have to try to determine the enum's size at runtime (or remember all the places that you hardcoded the size) in case you need to add any more enum values. Logically, you want to separate your "fish" from your "ores". Wood doesn't feed you, so won't make sense to have inside of a massive enum or array that contains food-based items. In the same vein, weapons aren't armor. It makes a LOT more sense to me to have multiple for() loops, one after the other, than to have some massive array of "everything in the game". My mind just doesn't work like that. Antone333 said: if(ArrayLevelSelect[LevelX][LevelY] = 1) You are assigning the value of 1 into ArrayLevelSelect[LevelX][LevelY] here. You probably meant == (equality). Next, onto the subject of your maps. I have always been of the mindset that all levels in a map should potentially be different sizes: the memory can be allocated when you need it, and freed when you're done with it. Some maps are the "interiors" of a large house, so they can be smaller. Other maps are vast oceans with a special hidden island right in the middle of them, and can be much larger. When you create a level, there should be a class that is specifically dedicated to all aspects of its generation and tear-down. You should pass in the level number you want loaded, and get a level back. You should pretend that you have NO idea what's going on "behind the curtain" when you request a level from it. This class might have the array in memory. It might load it in from a file. It might parse a Tiled-generated XML file. That's the point: it should be a mystery to everything else so you can change it at any time in the future, and as long as "give me level X" always returns a predictable map structure, how it works should always be a black box. Last of all, DON'T (did you see all the emphasis I put there?) create function calls for levels and things that "will come". Don't copy-and-paste 70 "placeholder" levels when you really only have about 7-8 truly defined. Don't do placeholder fish/wood/weapons/armor. Don't create "dummy" monsters that you'll revisit "someday". It might make you much less overwhelmed if you drop your file down from the nearly 10,000 lines to about 5,000. Strip away ALL pre-"defined" stuff: get rid of levels 9-70. Get rid of all enemies but two: the rat, and maybe the spider. Get rid of all types of fish. You can leave some of the fish/wood/monster "types" in comments somewhere so you remember them later, but get them out of your current codebase. Once you have all that, post your new source file results, and we'll move on to breaking them apart into individual files. Your Monsters should be in one or more files (either a massive monster.cpp file, or individual monster_rat.cpp/monster_spider.cpp files). Your Items should be in one or more files (items.cpp or item_wood.cpp/item_fish.cpp, etc.). Etcetera, etcetera.
|
Thomas Fjellstrom
Member #476
June 2000
|
OnlineCop, while I agree that separating the item types could be more logical, its a lot more work to manage. Using a single item namespace allows for more efficient loading and saving as you don't have to figure out the category of the item first, and no item ids will ever overlap. -- |
pkrcel
Member #14,001
February 2012
|
I think that the superfluous enum in Tomasu view was this: Antone333 said: enum all items The "last item in an enum is the one that enumerates the enum itself" is quite handy It is unlikely that Google shares your distaste for capitalism. - Derezo |
LennyLen
Member #5,313
December 2004
|
pkrcel said: I think that the superfluous enum in Tomasu view was this: Not only is it superfluous, it also won't work as intended, since it will give the number of ores as 0, the number of fish as 1, etc...
|
pkrcel
Member #14,001
February 2012
|
Well in case it is strongly typed I guess ti would be only superfluous, but of course in this case......er now that I come to think of it, would it be even possible? The names should clash as multiple definition? (too rusty to remember ) It is unlikely that Google shares your distaste for capitalism. - Derezo |
OnlineCop
Member #7,919
October 2006
|
Thomas, while I agree with this, I'm trying to work with his code on his programming level. If I were talking to LennyLen, Arthur or Trent, I'd be suggesting more advanced methods. I feel that these topics wouldn't be appropriate for where he's at now, so I'm doing my best to suggest things that will help him get this project far enough along that he can see some significant success.
|
Thomas Fjellstrom
Member #476
June 2000
|
OnlineCop said: Thomas, while I agree with this, I'm trying to work with his code on his programming level. I honestly think throwing more code at the problem just makes it harder an item is an item, no matter the category. I think that is pretty darn simple -- |
Antone333
Member #15,545
March 2014
|
@OnlineCop Oh. wow. duh. haha == i know that. thats a silly mistake. ok so my maps work well now and i have loaded 2 in. 1 wall 2 grass 0 player 11111 11111 in the second array the only thing that gets drawn is the player and everything else is blank. i did this so the player can move freely ontop of the map without changing the map itself. so a couple of things. first of all, I know i am going to get crap for having all those huge arrays in my program itself. i get it. they should be in different files. and i am also seeing the result of it when the game is loading in the maps. it takes a minute. and this is only 2 maps! but i dont know how to use an array in a txt file like that. i have tried but i only know how to do simple variables and store them in an array using fstream. so if someone could help me out with that i would be grateful. and also, i am trying to figure out how to at this time make the player move. I am going for the same type of movement i have in my console game that i will repost. but i am pretty sure i will have to make the game redraw every time and i thought i had that working but it doesnt work so i will post my current project aswell and a final question comes when i create my inventory equipment and my incomplete date time thing. when you create them by pressing the "buttons" on the toolbar display it takes a couple of clicks before the new display shows up. and at line 373 of Game() i thought that would close the window. but for some reason it doesnt and i dont know why. for the Allegro 5 game go to line 470 PlayerMovement() to see how i thought the player should move when down is pressed. |
|