EatenByAGrue
|
 |
«
Posted
2011-08-26 01:12:17 » |
|
Hello JGO-Community, Currently I'm working my way through the "Introduction to Programming Using Java" by David J. Eck. As i proceed through the chapters I try to implement and use the new learned features in a simple textadventure (Zork-Style). As of now I have a "Area System" that gives information about the area you are in and a working "Dialogue System" that first shows the NPC-Speech and then gives the player multiple choice answers. I use a switch statement for that. It basically looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public static void showDialogueNPC(int indexDialogue) { switch(indexDialogue) { case 1: { System.out.println("blablabla"); System.out.println(""); System.out.println("1. blablabla"); System.out.println("2. blablabla"); System.out.println("> ");
while(true) { playerDialogueReply = stdIn.nextInt(); if(playerDialogueReply == 1) { showDialogueNPC(2); break; } else { .... } } break; } case 2: . . . . default: { System.out.println("DEBUG"); } } } |
I know it's probably (well rather most presumably) not the best way to solve this, but as I said I try to use whatever I learn. Long story short: I have four questions at the moment. 1. Would it be reasonable to make a new Class called for example "Speech" and only use it to store the different "NPC-Dialouge lines" in strings? So that I only have to call 1
| System.out.println(Speech.DialogNPC) |
for example. The reason why I don't want to put it to the other variable declarations at the beginning of my Dialogue class is because I have lot's of text and it kind of overwhelmes my code... 2. At the moment I can only run this in eclipse. Is there a way to run this programm outside of eclipse without providing an actual GUI (for example starting it via console)? I guess this is a really noobish question but I'm not that far in the book and would like to show it to a friend of mine (because he can't wait to criticise my lousy dialogues and area-descriptions  ). 3. One problem I have with the Scanner is, that if the user types in a char where an int is awaited by the programm it crashes. I guess this is where try... catch would kick in but I can't quite wrap my head around it yet... Is there any other way to get the user's input? 4. The last question is more of a general kind as I know how to use subroutines but I kind of don't know WHEN to use them. Or in other words I have the feeling that I overuse them, trying to put every single bit of my programm in it's own methods... I hope you understand what I mean. Is there a guideline or a "proper" way? I haven't planned too much fancy stuff. As I said I try to implement only new stuff I learn from the book. Greetings, EatenByAGrue
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
Z-Man
|
 |
«
Reply #1 - Posted
2011-08-26 02:44:54 » |
|
1. I would do that at least, modularity is a big thing in Object Oriented programming. You could do something as simple as have a class that just holds static references to each NPC's dialog, or you could create a NPC super class and then have your NPC's extend that class to get all of it's talking methods. Something like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class NPC { protected String name;
public NPC(String name) { this.name = name; }
public void talk() { System.out.println("Hello my name is " + name); } }
class Male extends NPC { protected String gender;
public Male(String name, String gender() { super(name); this.gender = gender; }
public void talk() { System.out.println("Hello my name is " + name + ", I am a " + gender); } } |
2. Yes there is a way to run Java applications from the console. Check out these tutorials to see how. http://download.oracle.com/javase/tutorial/getStarted/cupojava/index.html3. Try-catch statements aren't terribly difficult once you get to know them. Here is a tutorial about them http://download.oracle.com/javase/tutorial/essential/exceptions/ and here is an example how how to catch the exception that Scanner throws when the wrong type of input is given: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Scanner in = new Scanner(System.in); int num = -999;
while(num == -999) { System.out.print("Please enter a number: "); try { num = in.nextInt(); } catch(InputMismatchException ime) { System.out.println("That's not a number!\n"); in.next(); } }
System.out.println("The number you entered is: " + num); |
4. I tend to prefer to do this but that's just my opinion, generally though you don't want to do it TOO much because then it's just excessive.
|
|
|
|
Bonbon-Chan
|
 |
«
Reply #2 - Posted
2011-08-26 06:55:25 » |
|
Be carefull, you are using a recursive method : At each answer, you are invoking showDialogueNPC within showDialogueNPC. So at each answer, you are allocation more and more memory.
You should create classes to store dialogs and answers. At some point, I should advise you to use file to store your dialogs. If you use classes it will more easy to change your code when need.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ra4king
|
 |
«
Reply #3 - Posted
2011-08-26 07:05:46 » |
|
1 2 3 4 5 6
| in.next(); } } |
Actually, the input is read and when determined that it is not an integer, an exception is thrown. However, when you press ENTER after typing a char/integer, it also includes the \r\n (if on Windows) or \n (if on Unix). in.next() simply clears those remaining chars.
|
|
|
|
Z-Man
|
 |
«
Reply #4 - Posted
2011-08-26 11:12:17 » |
|
Oops my bad, I forgot nextInt() left behind the Enter key and that you have to call next() to get rid of it. I apologize, I haven't used Scanner in a while.
|
|
|
|
EatenByAGrue
|
 |
«
Reply #5 - Posted
2011-08-26 13:53:37 » |
|
Thank you for your support Z-Man, Bonbon-Chan and ra4king !  I made some changes according to your suggestions. First of all I created a new class in which I store the NPC-Textlines until I figure out how to read them out of a file (as Bonbon-Chan suggested). Then I made a new class called Reply that handles all the replies for the player, in which the method getPlayerReply() reads the users input after each NPC-Dialog. Here I also included the try - catch statement (the tutorial really helped Z-Man). I didn't even know about the recursive Method problem but I think I have fixed it now - thanks Bonbon-Chan! At the moment I couldn't use your suggestion about the Super-Class Z-Man, but I think I'll get to that in a few days. Now it looks like this (I included only one of the "NPCs" - Ignore the awefully written german dialogues  ): EDIT: Removed the code It still isn't pretty but it works for now. Looking forward to learning more about objects  EDIT: I almost forgot to say thank you for the tutorial about the console. I managed to run it from the terminal of my mac... but only if I compiled it first in eclipse. I guess the problem is, that when I compile it using the command line I have to manually care about the packages, right? -> Note to me: Look into that!  greetings, EatenByAGrue P.S.: Is it okay to post that "much" code??
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
|
Bonbon-Chan
|
 |
«
Reply #7 - Posted
2011-08-27 05:33:30 » |
|
You use an amfull number of switch/case. Must off them could be avoid using tables. You use a lot of static where I should not use them. You are still using recursion : getPlayerReply -> hauerPlayerReply -> getPlayerReply -> hauerPlayerReply -> ... As a template, I should start with something like (I put everything abstract to not put all the code  ) : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public abstract class Dialogues { public Dialogue getDialogue(int nb); }
public abstract class Dialogue { public String getText(); public int getNumberOfReply(); public Reply getReply(int nb); }
public abstact class Reply { public String getText(); public int getNextDialogue(); }
public class DialogueManager { private Dialogues dialogues;
public DialogueManager(Dialogues dialogues) { this.dialogues = dialogues; }
public void start() { int activeDialogue = 0; Scanner stdIn = new Scanner(System.in);
while(activeDialogue >=0) { Dialogue dialogue = dialogues.getDialogue(activeDialogue);
System.out.println(dialogue.getText());
for(int i=0;i<dialogue.getNumberOfReply();i++) { System.out.println((i+1)+" : "+dialogue.getReply(i)); }
int playerReply = -1;
while(playerReply <0) { try { System.out.print("> "); playerReply = stdIn.nextInt(); if(playerReply <= 0 || playerReply > dialogue.getNumberOfReply()) { System.out.println("Soll ich neue Antworten erfinden?"); playerReply = -1; } else { activeDialogue = dialogue.getReply(playerReply -1).getNextDialogue(); } } catch(InputMismatchException e) { System.out.println("\"Wie bitte?\""); } } } } } |
|
|
|
|
EatenByAGrue
|
 |
«
Reply #8 - Posted
2011-09-05 15:06:12 » |
|
Hello, sorry for the late reply, but to be honest the last days I tried to learn more and more about objects. Thank's to Bonbon-Chan for your script-example - the more I progressed the more I understood about what you are actually doing  I managed to finish a small game to a point where it is playable. Now I would love to include a save function but I don't know how to write and read data from a file. Basically I just need to store all the player related variables in a file and load them... Could someone point me into the right direction (Tutorial)? greetings EDIT: Nevermind. I think java.Io is the way to go 
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
Bonbon-Chan
|
 |
«
Reply #9 - Posted
2011-09-06 06:54:52 » |
|
Yep, java.io. But you still have 36 000 way to do it : raw data, serialization, binary file, text file, xml file, ...  An easy and simple way is to use binary file with : DataInputStream / DataOutputStream 1 2 3 4 5 6 7 8
| DataOutputStream dos = new DataOutputStream(new FileOutputStream("./player.sav"));
dos.writeUTF(name); dos.writeInt(level); dos.writeBoolean(isLocked);
dos.flush(); dos.close(); |
1 2 3 4 5 6 7
| DataInputStream dis = new DataInputStream(new FileInputStream("./player.sav"));
name = dis.readUTF(); level = dis.readInt(); isLock = dis.readBoolean();
dis.close(); |
Pretty easy no ? (I didn't catch exception in my examples)
|
|
|
|
Games published by our own members! Check 'em out!
|
|
EatenByAGrue
|
 |
«
Reply #10 - Posted
2011-09-06 10:53:11 » |
|
Thank's again Bonbon-chan, the DataInput- /OutputStream was really easy to use , took me about 5 mins to write the load and save  I have a question regarding recursion. If I understood it right, recursion happens when I call a method from within itself, or (as in my dialogue-script) call two methods from each other. So I guess it's also recursive if I make something like this right? mainMenu() -> startGame() -> startFight() -> exit() -> mainMenu() But how can I get back to the main menu, after the player exited the current game (by dying, or chosing to leave) without using recursion? I hope I don't annoy people with my questions  greetings
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
ReBirth
|
 |
«
Reply #11 - Posted
2011-09-06 11:58:52 » |
|
Oh no that's wrong. Menu, start, fight etc should be implemented as state machine. Each state has its own "next state" to put it simple. Each state has its own bussiness without bothering others... ok maybe passing some values for use.
Recursion is used to solve problem that has same pattern with different parameter(s), where the parameter is given first and the result is used by next recursion as parameter and so on. For example, finding route in grid based map (A* logic)
function(function(function(function(function(function(function...(function(function(x))))))))) = a result after process x with N times function which is end on some value so the flow climbs up again.
|
|
|
|
Bonbon-Chan
|
 |
«
Reply #12 - Posted
2011-09-06 12:12:32 » |
|
By itselft, recursion is NOT a problem. It can be use for algorithm (like sorting, parsing tree, ...) without make really complicated code. There is technics to "unroll" recursion but it will be a lit too mush to explain that  . When you invoke method within another method, you should ask yourself : is there case, where I will never get to the "return" or the end of the function ? For example, if I continue to do fights without dying ? Most of the time, you can avoid problem using a return value and a loop. For example : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| while(!finish) { int state = doDialog();
if (state == DO_FIGHT) { state = doFight(); }
if (state == DIE) { die(); finish = true; } } |
It is what ReBirth call using a state machine (well this one is not nice but simple to understand).
|
|
|
|
EatenByAGrue
|
 |
«
Reply #13 - Posted
2011-09-07 12:51:25 » |
|
Okay I think I understand. I should do it like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void game() { boolean play = true; while(play == true) { play = Menu.mainMenu(); } }
public static boolean mainMenu() { boolean continuePlaying = true; switch(menuOption(2)) { case 1: startGame(); break; case 2: continuePlaying = false; break; } return continuePlaying; } |
Is this what you mean?  Greetings
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
Bonbon-Chan
|
 |
«
Reply #14 - Posted
2011-09-07 14:42:07 » |
|
More or less, yes. With practise, you will do better. I see that you are using a lot of "static" method. It is not in object oriented philosophically. In a perfect world, the main code should be something like : 1 2 3 4 5 6 7 8
| public class Game { public static void main(String args[]) { Game game = new Game(); game.start(); } } |
With almost everything else none static (if it is not shared, there is no point to put it static).
|
|
|
|
EatenByAGrue
|
 |
«
Reply #15 - Posted
2011-09-07 21:39:35 » |
|
I see that you are using a lot of "static" method. It is not in object oriented philosophically.
You are right. I still use "static" way too often. My "player" and "enemies" are objects already - I am currently rewriting the whole thing using objects and working on "state machines". Your replies help a lot for my understanding  EDIT: Removed picture.
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
ReBirth
|
 |
«
Reply #16 - Posted
2011-09-08 03:26:55 » |
|
To put it simple, use static for class that's not allowed to have multiple instance since all components inside your package only want it alone and same. For example, a class that load all resources for the game.
|
|
|
|
Orangy Tang
|
 |
«
Reply #17 - Posted
2011-09-08 07:43:24 » |
|
For example, a class that load all resources for the game.
...is a terrible idea and shouldn't be made static. What happens when you want to go multiplayer and have both a client and server running in the same vm for the host? Or having separate resource pools for out-game and in-game? Or preloading the resources for the next level while still using the current level's resources? You don't need "only ever one", you need "currently only one". The correct design pattern for that is to just create one object.
|
|
|
|
EatenByAGrue
|
 |
«
Reply #18 - Posted
2011-09-08 09:51:52 » |
|
To put it simple, use static for class that's not allowed to have multiple instance since all components inside your package only want it alone and same.
Well that's why I have used static for my "player" before (since there is only one player). You don't need "only ever one", you need "currently only one". The correct design pattern for that is to just create one object.
Here is the problem I ran into. I created a new object of the type "player" in my combat class (since this is were all the magic happens and the player-class is needed the most) but now when I try to change one of it's variables, for example the player's name outside of the combat class I somehow need to access that certain object. So is that the right time and place to make it static (the pointer not the whole player-class I mean)? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Combat { static Player player = new Player(); ... ... ... }
public class Menu { ... ... Combat.player.creation(); ... ... ... }
public class Player { ... public void creation() { ... ... } ... } |
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
Orangy Tang
|
 |
«
Reply #19 - Posted
2011-09-08 10:10:41 » |
|
Here is the problem I ran into. I created a new object of the type "player" in my combat class (since this is were all the magic happens and the player-class is needed the most) but now when I try to change one of it's variables, for example the player's name outside of the combat class I somehow need to access that certain object. So is that the right time and place to make it static (the pointer not the whole player-class I mean)?
I haven't studied your code in detail, but what I'd suggest is to create a single Player object at a higher level (in your Game or similar class), then pass it in as an argument to the Combat and Menus classes as needed.
|
|
|
|
Bonbon-Chan
|
 |
«
Reply #20 - Posted
2011-09-08 10:19:43 » |
|
I really don't understand why you need a static reference to the player in the Class combat... and ever less why you create it in it !!!! Like Orangy Tang said : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Combat { private Dice dice;
public Combat(Dice dice) { this.dice = dice; }
public int doCombat(Player play,Mob mob) { ....
return WIN / LOOSE ; } } |
You should have a Game class (aka your TegrgMain) where you create your object and deal with your game life: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class TegrgMain { private Dice dice; private Player player; private Combat combat; ... public TegrgMain() { dice = new Dice(); combat = new Combat(dice); player = new Player(); .... }
public void start() { ...
while(!finish) { ... case COMBAT: result = combat.doCombat(player,mob); ... } } } |
|
|
|
|
EatenByAGrue
|
 |
«
Reply #21 - Posted
2011-09-08 11:32:11 » |
|
The problem is, that the tutorials I read mostly only use two classes to show an example, so when I started writing this "game" I played around with what I already knew and get it to do what I want it to do (that's why I used static reference for example) . As I said it worked ... and now I wanted to try to make it better as I progress. But for example I didn't know that you should create all objects in the main class and then pass them on. I guess I'm gonna stop doing this for now as I see I still lack the basic understanding of how things work. I'll finish the book I'm currently reading and then try again.  Thank's for your help @ all
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
ReBirth
|
 |
«
Reply #22 - Posted
2011-09-09 03:28:01 » |
|
...is a terrible idea and shouldn't be made static. and I learned it from Kev's tutorial Or preloading the resources for the next level while still using the current level's resources? I load all resource even before the menu appears. All sprites are hold by a static HashMap.
|
|
|
|
Bonbon-Chan
|
 |
«
Reply #23 - Posted
2011-09-09 06:31:36 » |
|
For me, it is more on a philosophy point of view. Static was not mean to be use like that... but a working code is a working code. And if not using a static make thing far more simple (not parse an object through 36 invocations...), I will not be embarased to use it  To EatenByAGrue (you are a french worm ?), you have choosen a good game to start with (aka not MMO guys  ). Since it is your first time, you should have to redo your design 5 or 6 times. Since your game is working, you should take what we say as advice and not thinks that you must do. If you see that it will make your code more simple go for it, otherwise continue until you see a problem. We will always be pleased to help you so don't hesitate to ask question.
|
|
|
|
EatenByAGrue
|
 |
«
Reply #24 - Posted
2011-09-11 01:22:22 » |
|
Guess who's back!  It was really frustrating for me, that you guys tried so hard to explain something to me, that I could've learned by myself if I had just read a few more tutorials... That's why I sat down and read a lot about objects (and their usage) the last two days and now started rewriting my game. I think I now at least understand the basics  I thought that you had to create an object "where it is needed" ... that's why I wanted to create it in the Combat class in the last version. I now know better  I also removed all the "method1() -> method2() -> method3() -> method1()" invocations (is that the correct word?) and improved some of my methods (for example creating only one method that can roll multiple different dice at once, instead of having multiple methods for each kind of dice like W4, W6 ... and so on). I hope I can finish it until tomorrow evening. Thank you once again  P.S.: EatenByAGrue (you are a french worm ?)
I really laughed about that (for those who don't know the scariest monster in Gaming history: http://en.wikipedia.org/wiki/Grue_%28monster%29)
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
ra4king
|
 |
«
Reply #25 - Posted
2011-09-11 01:52:09 » |
|
Oh what a coincidence! I'm currently playing Zork for a CS project where I have to make my own text-based interactive fiction game!
|
|
|
|
EatenByAGrue
|
 |
«
Reply #26 - Posted
2011-09-11 14:44:56 » |
|
Okay I finished updating my game. Maybe I should change the title of this thread as it basically isn't a Textadventure anymore but more a "Text-based Hack and Slay"  I wanted to add Armor and Weapon Items but I can't motivate myself enough to do so atm. But I have to say I'm quite happy how it is right now. I also think the "balancing" is quite okay. This is the profile of my own char which died after 22 won fights because I wasn't able to find a merchant to buy potions  ======================================== Name: Robert Race: Orc Class: Brawler Health: 1 ---------------------------------------- Skills I: 4 W: 5 S: 9 R: 7 E: 12 ---------------------------------------- Level: 3 Exp: 1450 LvlUp: 4450 Fights Won: 22 ======================================== If anybody is interested I could upload the jar file (but I have to warn you the graphics aren't quite on the Next-Gen-Level  ). Thank's to everyone who helped me, especially bonbon-chan  @ra4king: Zork is a great game. Have you played "A Hitchhiker's Guide to the Galaxy"? I really love these kind of games. > Inventory You have: a splitting headache no tea 
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
ReBirth
|
 |
«
Reply #27 - Posted
2011-09-12 03:38:47 » |
|
Armor and weapon can be created by making a super class i.e Item. Then make one class per item extending Item class so they can have value like ATK pow, DEF pow etc.
You can upload your jar (I want see it too). If it is almost complete (or beta state) you can make thread on showcase. Good luck!
|
|
|
|
EatenByAGrue
|
 |
«
Reply #28 - Posted
2011-09-14 14:51:00 » |
|
Armor and weapon can be created by making a super class i.e Item. Then make one class per item extending Item class so they can have value like ATK pow, DEF pow etc.
It's funny because that's excactly how I tried to do it (as I've read on about inheritence and polymorphism)  This is what I've come up with so far. EDIT: If I understood it right, I could declare the Item class as abstract because it only serves as a "blueprint" for the subclasses and will never be used to create an object of the type "Item". 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public class Item { protected Player player; protected int amount; public Item (Player player) { this.player = player; }
public void buy(int price) { int money = player.getMoney(); if(money >= price) { money -= price; player.setMoney(money); increaseAmountOfItem(); } else { System.out.println("Sorry, but you don't have enough money!"); System.out.println(); } } public void increaseAmountOfItem() { } public int getAmount() { return amount; } }
class SmallPotion extends Item { public SmallPotion(Player player) { super(player); }
public void increaseAmountOfItem() { amount++; System.out.println("You now have " + amount + " small Potion(s)."); System.out.println(""); } } |
You can upload your jar (I want see it too). If it is almost complete (or beta state) you can make thread on showcase. Good luck!
Even if it's only a text-based game like this? I mean I don't even have an executable jar file - it's only runnable in the console at the moment  Greetings, EatenByAGrue
|
It is pitch black. You are likely to be eaten by a grue.
|
|
|
Z-Man
|
 |
«
Reply #29 - Posted
2011-09-14 20:33:07 » |
|
Even if it's only a text-based game like this? I mean I don't even have an executable jar file - it's only runnable in the console at the moment  You can still run jars from the console. EDIT: D'oh! I clicked the appreciate button before I clicked the quote button xD free medal for you
|
|
|
|
|