Javaの学習のため、CUIによるテキストアドベンチャーを作っています。
現在学習開始から一ヶ月ほどで、基本的な文法と、クラスや継承、カプセル化、ポリフォーミズムなどを学びました。
(基本的な理解は一応したつもりですが、もちろんまだ使いこなせるレベルではないです)
テキストアドベンチャーはいわゆる美少女ゲーム的な内容にしようと思い、Mainクラスでゲームの主なループをさせつつ(このクラス内にmainメソッドがあります)、他に主人公やヒロインのクラスを作っていくという設計を考えました。
仮に主人公クラスにTaro、ヒロインクラスにHanako、Yoshikoを作るとします。
ヒロインは随時増やすという体で、オブジェクト指向の練習も兼ねてHeroineというクラスをそれぞれに継承させて作ることにしました。
Heroineクラスは以下↓のようなものです。
該当のソースコード
public class Heroine{
private String name;
private int koukando;
public void koukandoUp(){
koukando++;
}
public void koukandoDown(){
koukando--;
}
public int getKoukando(){
return this.koukando;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
//-------------コンストラクタで初期化-----------
Heroine(){
this.koukando = 10;
}
}
発生した問題
Hanako,Yoshikoに上記のHeroineクラスを継承させたうえで、MainクラスとTaroクラスのそれぞれで好感度パラメーターを受け取ろうとして、やり方がわからなくなりました。
(※下部「追記」にて詳細を書き加えました)
getKoukando();を使うには、まずHanakoやYoshikoをインスタンス化しないといけませんよね?
ですがMainクラスとTaroクラスでそれぞれにHanako hanako = new Hanako();としてしまうと、作られた2つのhanakoインスタンスは全く別物となるのでしょうか?
これはMainとTaroの二つのクラスで好感度パラメーターを受け取ろうとする設計自体が、そもそもおかしいのでしょうか。
それとも何かもっとスマートなやり方がありますでしょうか?
教本やwebページで調べてみると項目ごとに詳しい説明が書かれてはいます。
インスタンス化の仕方、カプセル化の使い方、継承のやりかた……等々。
しかしながら「こういったプログラムを作る場合にどういうやり方がセオリーであるのか」ということが全く分からず、つまづいてしまっています。
ご教示いただけたら幸いです。
補足情報(他に試してみたこと)
であるならば、koukandoやnameをstatic変数にすればいいのかな? と思いHeroineクラスのメンバをあらかたstaticにしてみたところ、ヒロインの名前が両方とも「よしこ」になるなどHanakoとYoshikoのパラメーターがごっちゃに混ざってしまいました……汗
追記(MainクラスとTaroクラスのそれぞれで好感度パラメーターを受け取ろうとしたことについて)
Taroクラスには、以下のようにたろうくんが実行する行動を記載しました。
import java.util.Scanner;
public class Taro{
public String name;
public int hp;
public final int max_hp;
public int intelligence;
public void action(){
Scanner scan = new Scanner(System.in);
System.out.println("行動を選んでください。");
System.out.println("1.移動 2.勉強 3.寝る");
int val = scan.nextInt();
switch(val){
case 1:
this.move();
break;
case 2:
this.study();
break;
case 3:
this.sleep();
break;
}
}
public void sleep(){
this.hp = 100;
System.out.println(this.name + "は眠った。体力が回復した!\n");
}
public void move(){
Scanner s = new Scanner(System.in);
Hanako hanako = new Hanako();
Yoshiko yoshiko = new Yoshiko();
System.out.println("どこに移動しますか?");
System.out.println("1.校舎裏 2.公園 3.プール 4.帰宅する");
int val = s.nextInt();
this.hp-=5;
switch(val){
case 1:
System.out.println("校舎裏に移動した。");
hanako.upKoukando();
break;
case 2:
System.out.println("公園に移動した。");
yoshiko.upKoukando();
break;
case 3:
System.out.println("プールに移動した。");
break;
case 4:
System.out.println("帰宅した。");
break;
}
}
public void study(){
this.hp -= 10;
this.intelligence += 5;
System.out.println("知力が5上がった。\n");
}
//-------------コンストラクタで初期化-----------
public Taro(){
this.hp=100;
this.max_hp=100;
this.intelligence = 60;
}
}
はなこさんはいつも校舎裏に、よしこさんはいつも公園にいるということにして、会いにいくと(それだけで)好感度が上がるということにしました。
この際にupKoukando()メソッドを使うため、HanakoクラスとYoshikoクラスのそれぞれをインスタンス化しています。
そしてMainクラスでは、
public class Main{
static int dayCount=1;
public static void main(String[] args){
Taro taro = new Taro();
taro.name = "たろう";
for(int i=1;i<11;i++){
putStatus(taro.intelligence,taro.hp);
taro.action();
dayCount++;
}
}
//------------------
public static void putStatus(int intel,int hp){
System.out.println("+++++++++++++++++++++++++++");
System.out.println(" "+dayCount+"日目"+" "+"知性"+intel+" "+"体力"+hp);
System.out.println("の好感度");
System.out.println("の好感度");
System.out.println("+++++++++++++++++++++++++++");
}
}
for文で10日間のループを、putStatus()で現在のパラメーターを表示させました。
そしてputStatus()の中、3,4行目の「System.out.println("の好感度");」のところにそれぞれはなこ、よしこの名前と好感度を呼び出そうと、mainメソッド内で再度Hanako hanako = new Hanako();としたところ、MainクラスとTaroクラスにそれぞれ別のhanakoインスタンスができてしまいうまくいきませんでした。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
MainクラスとTaroクラスでそれぞれにHanako hanako = new Hanako();としてしまうと、作られた2つのhanakoインスタンスは全く別物となるのでしょうか?
はい。
これはMainとTaroの二つのクラスで好感度パラメーターを受け取ろうとする設計自体が、そもそもおかしいのでしょうか。
ゲーム全体を統括するクラスを書けば良いです。
Taroくんは必要に応じてそのクラスに問合せします。
シングルトンを使っても解決出来ますが、安易に使うとスパゲッティ化するのでお勧めしません。
それとも何かもっとスマートなやり方がありますでしょうか?
Hanakoクラス、Yoshikoクラスは要らないと思います。
Heroine hanako = new Heroine(花子の情報); で充分ですよね。
クラスや継承、カプセル化、ポリフォーミズム
x ポリフォーミズム
o ポリモーフィズム
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+3
オブジェクトは, 現実的なイメージを基にすることで, 分かり易く, 扱い易くするものです.
イメージしてみてください. 「たろう(Taro)が移動(move)する度に, はなこ(Hanako)やよしこ(Yoshiko)は生まれる(new)」ことは現実的でしょうか?
私なら, ヒロインは主人公と同等にゲームの世界に存在するオブジェクトのほうが良いようにイメージします.
ですので move の度に new はせず, Taro 同様に先に Main で new し, Taro の行動に応じてその場所に居るヒロインを得て変化するようにします.
注: 以下のコードは切り貼りしただけで, コンパイル等確認していません.
Mainクラス
public class Main{
//修正: static を削除, ヒロインを追加
int dayCount=1;
Taro taro;
Hanako hanako;
Yoshiko yoshiko;
//修正: "世界"を生成して起動する.
public static void main(String[] args){
Main main = new Main();
main.start();
}
//コンストラクタ追加: "世界"もオブジェクトとして扱うため
Main() {
taro = new Taro();
taro.name = "たろう";
//ヒロイン追加
hanako = new Hanako();
hanako.setName("はなこ");
yoshiko = new Yoshiko();
yoshiko.setName("よしこ");
}
//追加: "世界"は動き出す
void start() {
dayCount=1;
for(int i=1;i<11;i++){
putStatus(taro.intelligence,taro.hp);
taro.action(this);
dayCount++;
}
}
//追加: その場所に居るヒロインを返す. 居ない場合は null.
public Heroine getHeroine(int location) {
switch(val){
case 1: //校舎裏
return hanako;
case 2: //公園
return yoshiko;
}
return null;
}
//------------------
public void putStatus(int intel,int hp){
System.out.println("+++++++++++++++++++++++++++");
System.out.println(" "+dayCount+"日目"+" "+"知性"+intel+" "+"体力"+hp);
System.out.println(hanako.getName()+"の好感度"+hanako.getKoukando()); //修正
System.out.println(yoshiko.getName()+"の好感度"+yoshiko.getKoukando()); //修正
System.out.println("+++++++++++++++++++++++++++");
}
}
Taroクラス
public void action(Main world){ //パラメータ追加
Scanner scan = new Scanner(System.in);
System.out.println("行動を選んでください。");
System.out.println("1.移動 2.勉強 3.寝る");
int val = scan.nextInt();
switch(val){
case 1:
this.move(world); //パラメータ追加
break;
(略)
public void move(Main world){ //パラメータ追加: Mainクラスを登場人物の住む"世界"とする
Scanner s = new Scanner(System.in);
//Hanako hanako = new Hanako(); //削除
//Yoshiko yoshiko = new Yoshiko(); //削除
System.out.println("どこに移動しますか?");
System.out.println("1.校舎裏 2.公園 3.プール 4.帰宅する");
int val = s.nextInt();
this.hp-=5;
switch(val){
case 1:
System.out.println("校舎裏に移動した。");
//hanako.upKoukando(); //削除
//その場所に居るヒロインを得て, 居たら(null で無ければ)好感度アップ
Heroine heroine = world.getHeroine(val);
if(heroine != null) {
System.out.println(heroine.getName() + "に会った");
heroine.upKoukando(); //注意: 定義と使用でメソッド名が違っています.
} else {
System.out.println("誰も居なかった");
}
break;
//case 2 も上と同様の為省略
(略)
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
インスタンス化の仕方、カプセル化の使い方、継承のやりかた……等々。
しかしながら「こういったプログラムを作る場合にどういうやり方がセオリーであるのか」ということが全く分からず、
ここだけにアドバイスしますと、
「デザインパターン」を学ぶと良いと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.32%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
jimbe
2019/07/10 11:15
「MainクラスとTaroクラスのそれぞれで好感度パラメーターを受け取ろう」というのは, 何をしようとして何が問題で出来ないのでしょう. やろうとしたコードをご提示願えますか.
Neru_K
2019/07/10 12:32
ありがとうございます。
少し長くなりましたがコードを追記しました。
プログラミング初心者ゆえめちゃくちゃなことをしているかもしれないと思いお恥ずかしいのですが……
なにかアドバイスいただけたら嬉しいです!