質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

4回答

2354閲覧

【大至急】Ruby クラスの定義

Oramun

総合スコア76

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

2クリップ

投稿2015/08/28 01:52

編集2015/08/28 16:33

/追記、コード編集/

みなさんの説明はわかりやすく、理解できたところはあります。
メソッドの定義など「こんな感じなのかな」とすこし変更してみました。
ですがやはりまだ動きはしないです…。
また ループ内 衝突判定の条件分岐をループ外に出しメソッド化というのがやはり思いつきません。
どこをどう変えるか、改善点 修正点など、いろいろとまた教えていただけると幸いです。

Ruby

1require "dxruby" 2 3#マップの定義 4#ブロックの定義 5 6 7#初期値設定 8x = 32 9y = preview = 32 10f = 1 11item = 0 12jump = false 13 14 15#対応した配列を返す 16def collition(x, y, array) 17 return array[y/32][x/32] 18end 19#すり抜け防止 20def slip 21 if y_move > 31 22 y_move = 31 23 end 24end 25#落下時 26def drop 27 if y >= 480 28 x = 32 29 y = preview = 0 30 item = 0 31 map[3][6] = 5 32 map[2][6] = 0 33 end 34end 35#移動スピード 36def speed 37 if item == 1 38 x += Input.x * 5 39 else 40 x += Input.x * 2 41 end 42end 43#SPACEキーでジャンプ 44def jump 45 if Input.key_push?(K_SPACE) and jump 46 f = -15 47 end 48end 49#マップの表示 50def draw_map(map, block) 51 Window.draw_tile(0, 0, map, block, 0, 0, 18, 15) 52end 53#キャラクターの表示 54def draw_char(x, y, character) 55 Window.draw(x, y, character) 56end 57 58 59#ゲームループ開始 60Window.loop do 61 62 63 y_move = (y - preview) + f 64 preview = y 65 y += y_move 66 f = 1 67 68 69 slip 70 drop 71 speed 72 73 74 #天井衝突判定 75 if collision(x , y, map) == 1 or 76 collision(x+31, y, map) == 1 then 77 y = y/32*32 + 32 78 end 79 #床衝突判定 80 if collision(x , y+31, map) == 1 or 81 collision(x+31, y+31, map) == 1 then 82 y = y/32*32 83 jump = true#地面に接地時ジャンプ許可 84 else 85 jump = false #不許可 86 end 87 #壁衝突判定(左側) 88 if collision(x , y , map) == 1 or 89 collision(x , y+31, map) == 1 then 90 x = x/32*32 + 32 91 end 92 #壁衝突判定(右側) 93 if collision(x+31, y , map) == 1 or 94 collision(x+31, y+31, map) == 1 then 95 x = x/32*32 96 end 97 #アイテム衝突判定 98 if collision(x , y , map) == 4 or 99 collision(x , y+31, map) == 4 then 100 x = x/32*32 + 32 101 map[2][6] = 0 102 item = 1 103 end 104 #ブロック衝突判定 105 if collision(x , y , map) == 5 or 106 collision(x+31, y , map) == 5 then 107 y = y/32*32 + 32 108 map[2][6] = 4 109 map[3][6] = 1 110 end 111 if collision(x , y+31, map) == 5 or 112 collision(x+31, y+31, map) == 5 then 113 y = y/32*32 114 jump = true 115 end 116 117 118 jump 119 draw_map 120 draw 121 122 123end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

Rubyで書いた事がないのでコードが合ってる合ってないはわかりませんが、ゲームプログラミングはわかりますので回答します。まず、クラスうんぬんの前に、ゲームのロジックフローができてないですね?

ゲームループ
・キー入力のチェック(現状は左右の移動がないですよね…)
・描画
これはそれぞれ別のメソッドになっているほうがいいですよね。

つまり:

#キー入力のチェック def checkInput if Input.key_push?(K_SPACE)... ...他のキー入力は? end end #マップの表示 def drawmap(map, block) Window.draw_tile(0,0,map,block,0,0, 18, 15) end

で、これらのメソッドをゲームループから呼び出すわけです。
衝突判定もゲームループの中にごちゃーっと入ってますが、全部メソッドにしちゃって、ゲームループをもっとスッキリさせましょう。

適当ですが、

Window.loop do checkInput checkCollision drawmap(map,block) end

のような感じにスッキリとしたゲームループにする事で、
バグも減りますし、やりたい事がわかりやすくなると思います。

投稿2015/08/28 08:36

Jake

総合スコア289

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Oramun

2015/08/29 01:07

Jakeさんのように少し変えてみました。こんな感じでしょうか?? またご指導頂けると助かります m(_ _)m
guest

0

さしあたりゲームループにある衝突判定は煩雑なので、
メソッドに切り出してループの外に追い出しましょう。

ただそれはすでに他の方が回答されているので、
私からはすこし違う角度から回答します。


コードをパッと見て、あるいは見ない設計段階から、
メソッドやクラスに分割する感覚を養うのが重要です。

システムの中心部ほど抽象化するのが、
オブジェクト指向設計の定石です。

ただこの感覚を最初はつかみにくいと思うので、
イメージしやすいよう、たとえで説明します。

たとえば、家でもビルでも建物をイメージしてください。
モダンな建物ほど、中心部はスッキリしていると思います。

ビルの入口や受付、あるいはリビングの中央に、
トイレやゴミ置き場は作らないと思います。
それらは周辺部にあると思います。

また、デザインパターンには「ファサード」というパターンがありますが、
これも建物の正面とか入口という意味です。

つまり、オブジェクト指向ではシステムの中心部ほど抽象化するのは、
建物の入口は人がよく通るからスッキリさせようということです。

そしてもちろん、ゲームループがこの建物の正面とか入口に相当します。


関数やメソッド(やクラス)の抽出は、
一定以上の規模のプログラミングで
最重要、必須だと思います。

もしメソッドなどに切り分けずに、
全体が一枚岩のままプログラムが大きくなると、
複雑性が高まる一方なのでいつか破たんします。

これも建物でいえば、部屋に区切るような基本的なことです。

体育館の中で百人暮らすのと、マンションで世帯ごとに暮らすのと、
どちらが快適かを考えれば、区切ることの重要さは分かると思います。

オブジェクト指向を建物で言うと、後者のマンションの方法です。

建物を部屋(クラスやメソッド)に区切って、中はプライベートにし、
逆にエレベーターホール(メインループ)などパブリックな共有部分は、
スッキリ(抽象化)させます。そうすると自然と使いやすくなります。

投稿2015/08/28 12:18

LLman

総合スコア5592

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Oramun

2015/08/29 01:11

抽象化、オブジェクト指向とかどんな物なのか、理解しやすかったです。 とても分かりやすい説明をありがとうございます! 編集したコードにまた指摘などありましたら、コメント頂けると嬉しいです m(_ _)m
guest

0

ベストアンサー

返信遅くなりました。
コーティングミスはあるものの、クラスというものの概念はなんとなく掴めていると思います。
Jakeさんが既に指摘していますが、このコードにはまだまだ「抽象化」の余地があります。何やら難しく聞こえると思いますが、実はもう、あなたはそれ実行しています。

キャラクターに対する操作は、分解すると、「この変数にこれを代入して、これはこうして、…」と、コンピューターに対する1つ1つの命令に分解できますね。それを「ジャンプして」と分かりやすく言い替えることが、抽象化なのです。

クラスからはちょっと離れますが、キーチェック、内部処理、描画、これらをウインドウループの中に直接記述せず、「関数に」切り出してみてください。
なぜ「クラスのメソッド」でないのかを説明すると、キーの入力自体は、マリオには関心がないのです。ゲームさんが、キーを押された、じゃあマリオに「こう動いて」って言わないと、と思って、実際にマリオに指示する。するとそれを聞いたマリオは、「じゃあ移動するか」と歩き出すわけです。
その後については、追って説明します。

投稿2015/08/28 11:41

majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Oramun

2015/08/29 01:20

majiponiさん 今回も回答ありがとうございます! 抽象化 ということを少し試して見ました。どうでしょうか?? 何度も申し訳ないですが また回答頂けると幸いです m(_ _)m
majiponi

2015/08/29 01:54

あー、私の説明の仕方が悪かったかな。キャラクターをクラスにまとめた状態で、さらに、衝突判定とかをループの外に出してみよう、って意味だったんだけど…。 つまり、こんな感じのコード。 キャラクタークラス定義(以前のコードで大体ok) マリオというキャラ(オブジェクト)を定義(グローバル) ウインドウループ{ キー入力処理関数呼び出し 内部処理関数呼び出し 表示関数呼び出し } キー入力処理関数定義{ if スペースが押されていたら{ マリオにジャンプするよう指示 } if スティックが倒れていたら{ マリオに歩くよう指示 } … } 内部処理関数定義{ if 天井にぶつかっていたら{ 位置を修正するよう指示 } … } 表示関数定義{ 背景表示関数呼び出し マリオに自分を表示するよう指示 } 全然Rubyのコードじゃないですが。例えばウインドウループを書くとき、マリオが天井にぶつかっているかとか、意識しないでいいのです。 ループは、キーの処理、内部処理、表示をする、といった大まかな処理を考えればいいのです。天井にぶつかっているかは、下請け(内部処理)に任せればいいのです。もちろん、歩けといった指示も同じ。マリオに任せればいいのです。 これが、抽象化です。まだ慣れていないようですが、ぜひ、プログラムを機能単位に分割するという思考を身につけてみてください。 説明に分かりにくいとこがあれば、またいつでも答えます。
guest

0

処理を抽象化するとはどういうことか、平たく言えば「ザックリ表現する」ということです。

プログラムを動かすには色々な処理が必要で、その処理を実行する担当者が必要です。今回のコードで登場する(登場しそうな)処理の担当者は、以下のようになると思います。
・キャラクター(飛んだり歩いたりする)
・マップ(壁や背景を表現する)
・コントローラ(ユーザーの操作に従って、キャラクターに命令)
・マップ表示装置(マップを表示する)
・条件判定装置(キャラクターが壁や天井にぶつかっていないか教える)
・ゲーム本体

()内はそれぞれの担当者の役割です。xの値をいくらにするとか、if判定にどんな変数や関数を用いるとか、具体的なことは何も書いてません。でも、それぞれの担当者に必要な能力(機能)を「ザックリ表現」すれば上記のようになるでしょう。

では、これらの担当者を使ってゲームを「ザックリ表現する」と、どうなるでしょうか

ゲーム「マップ表示しろ」
マップ表示装置「ラジャー」
ゲーム「入力きたらキャラクターに命令しろ。入力来るまでは待機」
コントローラ「ラジャー」
コントローラ「Spaceキー押された、ジャンプしろ」
キャラクター「ラジャー、ジャンプする」
キャラクター「今、天井にぶつかってる?」
条件判定装置「ぶつかってないよ」
キャラクター「じゃあまだ上がれるな、ぶつかってる?」
条件判定装置「ぶつかってるよ」
キャラクター「ラジャー、落下する」

このように表現すると、各担当者がそれぞれどんな関わりと役割を持っているかが分かりやすくなります。関わりと役割がわかってくると、後々に各担当者をクラスとして表現する際に、キャラクタークラスはどんなメソッドを持ち、どんなフィールドを持つべきかが分かってきます。

上記は一例ですが、一度こんな風にゲーム全体を「ザックリと表現」し直してみて、必要な担当者と、各担当者が持つべき役割を分析してみてはいかがでしょう。

ちなみに、上記のように役割分担をした場合、ゲームのメインループはこの程度になると思います。
Window.loop do
マップ表示装置.表示
コントローラ.入力待機
end

投稿2015/08/29 05:26

philomagi

総合スコア267

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問