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

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

ただいまの
回答率

90.49%

  • Ruby

    7912questions

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

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 969

Oramun

score 68


/**追記、コード編集**/

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


require "dxruby"

#マップの定義
#ブロックの定義


#初期値設定
x = 32
y = preview = 32
f = 1
item = 0
jump = false


#対応した配列を返す
def collition(x, y, array)
  return array[y/32][x/32]
end
#すり抜け防止
def slip
  if y_move > 31
    y_move = 31
  end
end
#落下時
def drop
  if y >= 480
    x = 32
    y = preview = 0
    item = 0
    map[3][6] = 5
    map[2][6] = 0
  end
end
#移動スピード
def speed
  if item == 1
    x += Input.x * 5
  else
    x += Input.x * 2
  end
end
#SPACEキーでジャンプ
def jump
  if Input.key_push?(K_SPACE) and jump
    f = -15
  end
end
#マップの表示
def draw_map(map, block)
  Window.draw_tile(0, 0, map, block, 0, 0, 18, 15)
end
#キャラクターの表示
def draw_char(x, y, character)
  Window.draw(x, y, character)
end


#ゲームループ開始
Window.loop do 


  y_move = (y - preview) + f
  preview = y
  y += y_move
  f = 1


  slip
  drop
  speed


  #天井衝突判定
  if collision(x   , y, map) == 1 or 
     collision(x+31, y, map) == 1 then 
     y = y/32*32 + 32
  end
  #床衝突判定
  if collision(x   , y+31, map) == 1 or 
     collision(x+31, y+31, map) == 1 then
     y = y/32*32 
     jump = true#地面に接地時ジャンプ許可
  else
     jump = false #不許可
  end
  #壁衝突判定(左側)
  if collision(x   , y   , map) == 1 or
     collision(x   , y+31, map) == 1 then
     x = x/32*32 + 32
  end
  #壁衝突判定(右側)
  if collision(x+31, y   , map) == 1 or 
     collision(x+31, y+31, map) == 1 then
     x = x/32*32
  end
  #アイテム衝突判定
  if collision(x   , y   , map) == 4 or 
     collision(x   , y+31, map) == 4 then
     x = x/32*32 + 32
     map[2][6] = 0
     item = 1
  end
  #ブロック衝突判定
  if collision(x   , y   , map) == 5 or 
     collision(x+31, y   , map) == 5 then 
     y = y/32*32 + 32
     map[2][6] = 4
     map[3][6] = 1
  end
  if collision(x   , y+31, map) == 5 or 
     collision(x+31, y+31, map) == 5 then
     y = y/32*32
     jump = true
  end


  jump
  draw_map
  draw


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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

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/29 10:07

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

    キャンセル

+2

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

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




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

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

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


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

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

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


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

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




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

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


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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/29 10:11

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

    キャンセル

checkベストアンサー

+1

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/29 10:20

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

    キャンセル

  • 2015/08/29 10:54

    あー、私の説明の仕方が悪かったかな。キャラクターをクラスにまとめた状態で、さらに、衝突判定とかをループの外に出してみよう、って意味だったんだけど…。

    つまり、こんな感じのコード。


    キャラクタークラス定義(以前のコードで大体ok)

    マリオというキャラ(オブジェクト)を定義(グローバル)

    ウインドウループ{
    キー入力処理関数呼び出し
    内部処理関数呼び出し
    表示関数呼び出し
    }

    キー入力処理関数定義{
    if スペースが押されていたら{
    マリオにジャンプするよう指示
    }
    if スティックが倒れていたら{
    マリオに歩くよう指示
    }

    }

    内部処理関数定義{
    if 天井にぶつかっていたら{
    位置を修正するよう指示
    }

    }

    表示関数定義{
    背景表示関数呼び出し
    マリオに自分を表示するよう指示
    }


    全然Rubyのコードじゃないですが。例えばウインドウループを書くとき、マリオが天井にぶつかっているかとか、意識しないでいいのです。
    ループは、キーの処理、内部処理、表示をする、といった大まかな処理を考えればいいのです。天井にぶつかっているかは、下請け(内部処理)に任せればいいのです。もちろん、歩けといった指示も同じ。マリオに任せればいいのです。

    これが、抽象化です。まだ慣れていないようですが、ぜひ、プログラムを機能単位に分割するという思考を身につけてみてください。

    説明に分かりにくいとこがあれば、またいつでも答えます。

    キャンセル

0

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

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

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

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

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    Rubyで配列の数字を足していきたい

    Arrayに累積配列?を作成したいですがよい実装方法を教えてください 例 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]から [1, 3, 6, 10, 15,

  • 解決済

    多次元配列について(その2)

    CSVを読み込んで2次元配列に読み込んだ内容を保存したのですが、箇所によってnilが存在し、そのnilを' 'にしたいのですが、どうしたらいいのでしょうか、知恵をお貸しください b

  • 解決済

    Ruby コード修正

    今書いているコードを1つ上の段階へとグレードアップするため色々と質問させていただきました。 質問① 質問② ですがやはりうまくいかず苦戦していました。 あまり答えを聞くような形でよ

  • 解決済

    2個ずつ追加

    rubyを使って2こずつ追加して比較したいと考えています。 現在のコードだと [[[1, 2], [3, 4]], [[3, 4], [5, 6]], [[5, 6], [7,

  • 解決済

    暇つぶしにどうぞ

    概要 $hrtというサイズ11の配列があります。 それぞれの項目には数値が入り $hrt[0] と $hrt[10] は0固定です。 やりたい事は 項目が0と0で囲ま

  • 解決済

    書いたコードのどこが間違っているのか分かりません

    num = gets.chomp.split("").map(&:to_i) while 1 flag = true (0..num.size-2).each do |i

  • 受付中

    ruby とある問題での回答例。関数やクラス使えそうか?

    失礼します。 とある問題を説いていたら次のようなコードになりました。(問題の内容は拡散禁止されているため個人的な回答内容から読み取ってください。) ちなみに入力される値はこ

  • 解決済

    Ruby 標準入力から二次元配列を作る方法

    実現したいこと 4 10 3 2 1.2 2 0.4 255 423 56 9988 266 432 50 6542 こういった標準入力がある場合にこれを [[4,10,3],

同じタグがついた質問を見る

  • Ruby

    7912questions

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