熊でもわかるRGSS講座 初級編
<<前の章へ     第2章 クラスとメソッド     次の章へ>>
![]()  | 
      さて今日は、クラスとメソッドについて勉強するかの。 | 
![]()  | 
      うん。 | 
![]()  | 
       昨日も言ったが、クラスはオブジェクトの種類じゃ。具体的にどんなオブジェクトになるかは、クラスの定義で決まる。 | 
    
![]()  | 
      定義ってなに? | 
![]()  | 
      うむ。では、実際にクラスがどのように定義されておるか、見てみるかのう。スクリプトエディタを開いてみろ。 | 
![]()  | 
      うん、開いたで。 | 
![]()  | 
      今まで、セクション『Main』ばかり使ってきたが、実は『Main』以外のセクションは、すべてクラス定義なんじゃ。 | 
![]()  | 
      ほう・・・。 | 
![]()  | 
      とりあえず、上から15番目の『Game_Party』というセクションを見てみるかのう。 | 

![]()  | 
       8行目に『class Game_Party』と書いてあるじゃろ? これがクラス定義の始まりじゃな。『Game_Party』が、クラス名じゃ。 そして、一番下の358行目の『end』が、クラス定義の終わりを示す。 つまり、classとendの間に書かれた部分が、クラス定義とみなされるようになっておるわけじゃ。  | 
    
![]()  | 
      ふうん・・・。 | 
![]()  | 
       ということはまあ、一番単純なクラスの定義は、下記のようなものじゃの。もちろんこれでは中身が無いから、まったく意味が無いが。 | 
    
| 1 2 3  | 
      class Game_Party end  | 
    
![]()  | 
       しかし、中身が無くとも、一応これでクラスが定義できるし、オブジェクトを作ることもできる。もちろん、役に立たぬオブジェクトじゃがな。 | 
    
![]()  | 
      中身には、どんなことを書けばええの? | 
![]()  | 
       クラスの中身は、主にメソッドの定義じゃのう。 上の画像の18行目の『def initialize』とか、32行目の『def setup_starting_members』などが、メソッドの定義じゃ。  | 
    
![]()  | 
      さては、メソッドの定義は、defからendまでやな? | 
![]()  | 
       そのとおりじゃ。defとendの間に書かれた部分が、メソッドの定義とみなされる。 def の右に書いてあるのが、メソッド名じゃの。  | 
    
![]()  | 
      メソッド定義の中には何を書くの? | 
![]()  | 
      そこには、普通にプログラムを書くぞい。 | 
![]()  | 
      なるほど。 | 
![]()  | 
      では、簡単なクラスを作って、実際に使ってみることにしよう。 | 
![]()  | 
      うん。 | 
![]()  | 
      では、スクリプトエディタを開いて、セクション『Main』を右クリックするんじゃ。そうすると、下図のようにメニューが出るから、挿入をクリックせい。 | 

![]()  | 
      お、なんか空欄が出来たで。 | 

![]()  | 
      うむ。新しいセクションが出来たんじゃ。名前の欄をクリックして、セクション名を書け。 | 
![]()  | 
      なんて名前にすんの? | 
![]()  | 
       セクション名は、適当でいい。自分の名前でも書いておけ。 名前をつけたら、クラスの定義を書くぞ。こんな感じじゃ。  | 
    
| 1 2 3  | 
      class Test end  | 
    
![]()  | 
      こんでええか? | 

![]()  | 
      うむ、ええぞ。この場合、クラス名は、Test なわけじゃな。ちなみに、クラス名は、必ずアルファベットの大文字で始まるようにせねばならん。そういう決まりじゃ。 | 
![]()  | 
      うん。 | 
![]()  | 
      次は、メソッドを書いてみるかのう。こんな感じでどうかのう。 | 
| 1 2 3  | 
      class Test def speak p "もふもふ" end end  | 
    
![]()  | 
      もふもふて・・・。 | 
![]()  | 
      もふもふは、どうでもええわい。これで、Testというクラスに、speakというメソッドが定義されたのは、分かるな。 | 
![]()  | 
      うん。 | 
![]()  | 
      メソッドの内容は、「もふもふ」と表示するだけのものじゃ。 | 
![]()  | 
      うん。 | 
![]()  | 
      これで、Testクラスを元にオブジェクトを生成し、speakメソッドを実行して、「もふもふ」と表示させることが出来るはずじゃな。 | 
![]()  | 
      うん、早速やってみよ。 | 
![]()  | 
      では、その命令を、いつもの通りセクション『Main』に書くぞい。こうじゃ。 | 
| 7 8 9  | 
      begin test = Test.new test.speak  | 
    
![]()  | 
      オブジェクトを作るときは、Test.newのように、クラス名の後に、ピリオド、そしてnewと書く。 | 
![]()  | 
      左のtestは? | 
![]()  | 
      変数じゃ。オブジェクトを作るときは、このように作ったオブジェクトを変数に代入して使うんじゃ。 | 
![]()  | 
      ふうん・・・。Testいうクラスやったら、testいう変数にせなあかんの? | 
![]()  | 
      いや、そんなことはないぞ。分かりやすいように、同じ名前にしとるだけじゃ。別に、変数名はなんでもよいぞ。 | 
![]()  | 
      なるほど・・・。 | 
![]()  | 
      そのあとの、test.speakで、speakというメソッドを呼び出すわけじゃな。 | 
![]()  | 
      よし、ならやってみよ。 | 

![]()  | 
      お、ちゃんと動いたで。 | 
![]()  | 
       うむ。これが、基本じゃからのう。よく覚えておけ。 オブジェクトを作るときは、newを使ってオブジェクトを生成し、変数に代入して使う。 そして、変数名の後にピリオドで区切ってメソッド名を書けば、メソッドが呼び出せるんじゃ。  | 
    
![]()  | 
      うん、そやけどな。昨日、数値と文字列でやったときは、変数に代入したり、newとかやらんかったやんか。あれは、なんでなん? | 
![]()  | 
      うむ、実はな。数値や文字のように、値をそのまま書くだけでいいオブジェクトもあるんじゃ。そういうものをリテラルと言うがの。 | 
![]()  | 
      リテラル・・・また専門用語が・・・。 | 
![]()  | 
      まあ、今は覚えんでもええぞ。ともかく、数値と文字列には、newは必要ないということじゃ。 | 
![]()  | 
      うん。 | 
![]()  | 
      さて、今書いたメソッドじゃが・・・ | 
| 1 2 3  | 
      class Test def speak p "もふもふ" end end  | 
    
![]()  | 
      これでは、もふもふと表示することしかできん。 | 
![]()  | 
      うん。 | 
![]()  | 
      そこで、文字列を記録しておくための変数を設定して、表示する文字列を自由に設定できるようにしたいのう。 | 
![]()  | 
      変数を扱うときは、どうすんの? | 
![]()  | 
      そういうときに使うのが、initializeというメソッドじゃ。 | 
![]()  | 
      initialize? | 
![]()  | 
      うむ、initializeという名前のメソッドを定義しておくと、newで新しくオブジェクトが生成されたとき、自動的にinitializeが実行されるのじゃ。主に、オブジェクトの初期設定をするのに使うのう。 | 
![]()  | 
      ほう・・・。 | 
![]()  | 
      実際にやってみるかのう。 | 
| 1 2 3 4 5 6 7 8 9 10 11  | 
      class Test def initialize @word = "もふもふ" end def speak p @word end end  | 
    
![]()  | 
       initializeというメソッドを付け足した。内容は「@word = "もふもふ"」だけじゃ。 @wordという変数に、"もふもふ"という文字列を代入しておるわけじゃな。つまりここで、このクラスで扱うデータを変数に設定しておるわけじゃ。 このように、そのクラスで扱うデータは、initializeというメソッドの中で、変数に代入して準備しておけば良い。  | 
    
![]()  | 
      なんや、変数の頭に@(アットマーク)がついとるけど、これはなんや? | 
![]()  | 
       うむ、これはまた後で詳しくやるが、インスタンス変数という種類の変数じゃ。今は気にせんでええ。 | 
    
![]()  | 
      うん。 | 
![]()  | 
       speakメソッドも書き換えてあるぞ。p @word にしておる。 | 
    
![]()  | 
      でも、@wordの中身は"もふもふ"やから、結局"もふもふ"て表示されるな。 | 
![]()  | 
      そうじゃ。ちゃんと、オブジェクト生成時に、initializeが実行されておれば、"もふもふ"と表示されるはずじゃのう。 | 
![]()  | 
      ほなやってみよ。 | 

![]()  | 
      うん、出たで。 | 
![]()  | 
       うむ、これで文字列を記録し、そのデータを表示できるクラスが出来たのう。 | 
    
![]()  | 
      うん。でも、こんなクラス役に立ちそうも無いけど・・・。 | 
![]()  | 
       まあ、練習で作っただけじゃからのう。では、もうちょっとゲームで使えそうなものに改造してみるか。 | 
    
![]()  | 
      うん。 | 
![]()  | 
       以前、Spriteという機能を使って、画像を表示したのう。 実は、Spriteというのも組み込みクラスなんじゃが、今度はこれを使って、文字列を表示してみよう。 ちなみに、ちょっと説明しておくとじゃな、Spriteクラスは、画像を画面に表示する仕組みを持ったクラスじゃ。 もうひとつ、Bitmapというクラスも使うが、これは画像データそのものじゃな。  | 
    
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14  | 
      class Test def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end def speak @sprite.bitmap.draw_text(0, 0, 640, 30, @word) end end  | 
    
![]()  | 
      5行目の@sprite = Sprite.newで、 Spriteクラスを元にスプライトオブジェクトを生成し、@spriteという変数に代入しておる。 | 
![]()  | 
      うん。 | 
![]()  | 
      6行目の、Bitmap.newも、Bitmapクラスを元にビットマップオブジェクトを生成し、@sprite.bitmapという変数に代入しておる。ちなみに、640と480は、画像のサイズをピクセル数で表したものじゃ。 | 
![]()  | 
      @sprite.bitmapって変数なん? | 
![]()  | 
       うむ、@sprite.bitmapは、Spriteクラスの中の、bitmapという変数のことじゃ。 Spriteクラスには、bitmapという変数に値を設定するためのメソッドがあるから、このように代入できる。ま、このへんのことは後で詳しくやるぞい。  | 
    
![]()  | 
      うん。 | 
![]()  | 
       では、次にspeakメソッドについてじゃが、10行目に、@sprite.bitmap.draw_text(0, 0, 640, 30, @word) とあるのう。 draw_textは、Bitmapクラスのメソッドで、画像に文字を描画するものじゃ。 @sprite.bitmapには、ビットマップオブジェクトが入っておるから、@sprite.bitmap.draw_textと書けば、draw_textメソッドが呼び出せるわけじゃな。  | 
    
![]()  | 
      後ろについとる数字はなんや? | 
![]()  | 
       文字を描画する位置やサイズを指定する数値じゃな。 表示位置のX座標、Y座標、横幅、高さの順に指定する。最後が描画する文字列じゃ。今回は、変数@wordに記録されておる文字列を描画する。  | 
    
![]()  | 
      なるほど。@wordには、"もふもふ"が入っとるから、結局これも、もふもふて表示されるんか。 | 
![]()  | 
       うむ、しかし今回は、画面の中に表示されるからのう。やってみい。 | 
    
![]()  | 
      うん。ほんなら、やってみるでえ。 | 
![]()  | 
      おっと、その前に、セクション『Main』の内容も変えておけ。こんな感じじゃ。 | 
| 7 8 9 10 11 12 13  | 
      begin test = Test.new test.speak loop do Graphics.update end  | 
    
![]()  | 
      ええと、ループを加えたんやな。なんでなん? | 
![]()  | 
       今までは、p で表示させとったから、そこで処理が止まっておったが、今度は画面に描画するからのう。そのままでは、止まらずに次の処理に進んでしまうんじゃ。 そこで、ループを入れて、処理を止めるようにするぞい。  | 
    
![]()  | 
      なるほど、ほな修正してと。よし、実行してみよ。 | 

![]()  | 
      おお、表示されたで。 | 
![]()  | 
      うむ、これで文字列を記録し、画面に描画できるクラスが出来たのう。これをもう少し改造して、画面全体に文章を表示できるようにしてみるか。 | 
![]()  | 
      おお、なんやノベルゲームみたいやな。やってみよ。 | 
![]()  | 
       では、次は表示する文字列を変更できるメソッドを作るかのう。もふもふしか表示できんのでは、意味ないからのう。 | 
    
![]()  | 
      うん。 | 
![]()  | 
       メソッドを呼び出すときに任意の文字列を指定して、変数@wrodの値を、その文字列に変更する、という仕組みにするぞ。 そのために、引数(ひきすう)という仕組みを使う。  | 
    
![]()  | 
      引数? | 
![]()  | 
       うむ。引数とは、メソッドにデータを引き渡す仕組みなんじゃ。まあ、実際にやってみよう。 | 
    
![]()  | 
      うん。 | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak @sprite.bitmap.draw_text(0, 0, 640, 30, @word) end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
      change_wordというメソッドを設定したぞい。13行目じゃ。 | 
![]()  | 
      うん。でも、なんやchange_wordの後ろに、(new_word)なんていうのが、付いとるで? | 
![]()  | 
       それが、引数を受け取るための準備じゃ。 このメソッドでは、引数として文字列を受け取って、その文字列を@wordという変数に代入する、という作業をしておる。 そのために、引数を受け取る変数を指定しておるのが、(new_word)というわけじゃ。  | 
    
![]()  | 
      ふん・・・。 | 
![]()  | 
       よう分からんか? では、とりあえず実際に動かしてみるかのう。 | 
    
![]()  | 
      うん。 | 
![]()  | 
       では、実行するぞ。セクション『Main』の内容をこのように変えてみろ。 9行目に、test.change_word("こんにちは")が追加されただけじゃ  | 
    
| 7 8 9 10 11 12 13  | 
      begin test = Test.new test.change_word("こんにちは") test.speak loop do Graphics.update end  | 
    
![]()  | 
      うん。できたで。 | 
![]()  | 
       うむ、実行してみよ。 | 
    

![]()  | 
      うん。こんにちは、て表示されたで。 | 
![]()  | 
       うむ、では、解説じゃ。セクション『Main』の内容から見てみるぞ。 | 
    
| 7 8 9 10 11 12 13  | 
      begin test = Test.new test.change_word("こんにちは") test.speak loop do Graphics.update end  | 
    
![]()  | 
       9行目で、change_word というメソッドを呼び出しておるのう。このとき、後ろに括弧がついて、括弧の中に文字列が書いてある。 | 
    
![]()  | 
      うん。書いたるな。 | 
![]()  | 
       このように、メソッド名の後ろに括弧をつけて、データを書くと、そのデータがメソッドに引き渡されるのじゃ。 そして、その引き渡されるデータのことを、引数(ひきすう)と言うわけじゃ。  | 
    
![]()  | 
      ふうん・・・。 | 
![]()  | 
       では、改めて引数が渡される側を見てみるかのう。 | 
    
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak @sprite.bitmap.draw_text(0, 0, 640, 30, @word) end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
       13行目のメソッドchange_wordじゃな。 ここで指定しておるnew_wordが、引数を受け取る変数じゃ。  | 
    
![]()  | 
      うん。 | 
![]()  | 
       セクション『Main』の9行目で、引数に"こんにちは"が設定されておるから、 new_wordという変数には、"こんにちは"という文字列が代入されるわけじゃな。  | 
    
![]()  | 
      なるほど・・・。 | 
![]()  | 
       そして、@word = new_word が実行されるわけじゃから、変数@wordに記録されておる文字列も、"こんにちは"になるわけじゃ。 これで、表示する文字列を変更できるわけじゃな。  | 
    
![]()  | 
      ふうむ、ちょっとややこしいけど、なんとなく分かったかなあ・・・。 | 
![]()  | 
       うむ、まあ引数はこれから頻繁に使っていくからのう。徐々に覚えていけばええ。 ちなみに、 @sprite.bitmap.draw_text(0, 0, 640, 30, @word) の括弧の中も引数じゃ。この場合、5つ引数がある。  | 
    
![]()  | 
      引数は何個でもええの? | 
![]()  | 
       良いぞ。引数が複数ある場合は、,(コンマ)で区切って書くぞい。 もちろんメソッド側も、受け取る変数を、,(コンマ)で区切って同じ数だけ書いておかねばならん。  | 
    
![]()  | 
      なるほどな。。 | 
![]()  | 
      さて、ノベルゲームのように文字を表示するには、もう少し改造せねばならんのう。 | 
![]()  | 
      そうなん? | 
![]()  | 
       うむ、なぜそうなのか確認するために、もっと長文を表示してみろ。 | 
    
![]()  | 
      長文か? 例えばこんなん? | 
| 7 8 9 10 11 12  | 
      begin test = Test.new test.change_word("むかしむかし、あるところに、クミちゃんとグレちゃんがいました。") test.speak  | 
    
![]()  | 
       もっとじゃ。 | 
    
![]()  | 
      もっとか。なら、こんなんでどお? | 
| 7 8 9 10 11 12  | 
      begin test = Test.new test.change_word("むかしむかし、あるところに、クミちゃんとグレちゃんがいました。クミちゃんとグレちゃんは、魔王退治に行きました。魔王の名前は、ウェハースといいました。") test.speak  | 
    
![]()  | 
       なにやら、事実が歪曲されておるようだが、まあいい。表示してみろ。 | 
    
![]()  | 
      うん。 | 

![]()  | 
      あれ? なんかおかしなっとるで? | 
![]()  | 
       うむ、どうなっておる? | 
    
![]()  | 
      あんな、文字が全部表示されとらん。それから、字が縮んどる。 | 
![]()  | 
       そうじゃな。実は、draw_textというメソッドは、1行にしか文字を描画できん。複数行に分けて描画する機能は無いんじゃ。 そのため、描画幅に入りきらん分は、はみ出て切れてしまう。  | 
    
![]()  | 
      縮んだんは? | 
![]()  | 
      うむ、これはdraw_textの仕様でな、描画幅に入りきらん場合、可能な限り文字幅を縮小して表示するんじゃ。 | 
![]()  | 
      なるほど。 | 
![]()  | 
      さて問題じゃ。では、文字が画面からはみ出んように、複数行に分けて描画するには、どうしたらええかのう? | 
![]()  | 
      う〜ん・・・。 | 
![]()  | 
       ではちょっと、Bitmapクラスの仕様を見てみるかのう。ヘルプからの抜粋じゃ。とりあえず、使えそうなメソッドだけ書いておくぞ。必要なさそうな部分は削除してある。 | 
    
| width  ビットマップの幅を取得します。 height ビットマップの高さを取得します。 clear ビットマップ全体をクリアします。 draw_text(x, y, width, height, str[, align]) このビットマップの矩形 (x, y, width, height) に文字列 str を描画します。 テキストの長さが矩形の幅を超える場合は、幅を 60% まで自動的に縮小して描画します。 水平方向はデフォルトで左揃えですが、align に 1 を指定すると中央揃え、2 を指定すると右揃えになります。垂直方向は常に中央揃えです。 この処理には時間がかかるため、1 フレームごとに文字列を再描画するような使い方は推奨されません。 text_size(str) draw_text メソッドで文字列 str を描画したときの矩形 (Rect) を取得します(文字の幅や高さが分かる)。ただし、イタリックの場合の傾き分は含みません。  | 
    
![]()  | 
      うーん、まずdraw_textは使うわな。text_sizeも使いそうやな。文字幅が分かれば、画面からはみ出んようにできるもんな。 | 
![]()  | 
      うむ、そうじゃな。 | 
![]()  | 
      うーん、でもどうやったらええか分からんな。 | 
![]()  | 
      そうじゃのう。では、もうひとつ教えてやるわい。 | 
| 7 8 9 10 11 12 13 14 15  | 
      begin text = "こんにちは" loop do c = text.slice!(/./m) if c == nil break end p c end  | 
    
![]()  | 
      なんやこれ? | 
![]()  | 
       slice!というのは、Stringクラス(文字列クラス)のメソッドで、指定された文字を抜き出すものじゃ。まあ、実際に動かしてみればどうなるか分かるわい。 | 
    
![]()  | 
      うんなら、実行してみるで。 | 





![]()  | 
      お・・・一文字ずつ表示された・・・。 | 
![]()  | 
      そうじゃ。これは、文字列を、一文字ずつ分解して処理するときのやりかたじゃ。 | 
![]()  | 
      ほう・・・。 | 
![]()  | 
       slice!(/./m)と書くと、先頭の一文字を抜き出す。元の文字列の抜き出された文字は削除される。 textという変数には、"こんにちは"という文字列が入っておるから、c = text.slice!(/./m)とすれば、"こんにちは"から"こ"が抜き出されて、cという変数に代入され、textは"んにちは"になる。 ループで繰り返し処理されるから、順番に文字が抜き出され、最後には抜き出す文字が無くなる。 抜き出す文字がなくなると、slice!は、nilを返すから、11行目の条件分岐の条件を満たすので、breakされるわけじゃ。 ちなみに、nilはデータが無いことをあらわす特別なオブジェクトじゃ。  | 
    
![]()  | 
      breakってなに? | 
![]()  | 
      おお、まだbreakを教えてなかったかのう。breakは、強制的にループを抜け出す命令じゃ。 | 
![]()  | 
       なるほど。つまり、文字列から一文字ずつ抜き出して、空っぽになるまで続けるわけやな。 ほんで空っぽになったら、breakしてループを抜けると。  | 
    
![]()  | 
       そのとおりじゃ。これを利用して、ノベルゲーム風の表示をしてみい。 | 
    
![]()  | 
      うーんと、メソッドspeakを改造すればええな。ええと、@wordの文字を一文字ずつ抜き出して表示すればええんかな。 | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak loop do c = @word.slice!(/./m) if c == nil break end @sprite.bitmap.draw_text(0, 0, 640, 30, c) end end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
      こんで、どおや? | 
![]()  | 
       うむ、とりあえず実行してみい。 | 
    
![]()  | 
      うん、ほんなら、実行・・・と。 | 

![]()  | 
      な、なんやこれ? 変な四角いのが表示されたで! | 
![]()  | 
       それはな、表示される文字が、全部重なって表示されたものじゃ。 | 
    
![]()  | 
      なるほど・・・。 | 
![]()  | 
       表示位置が、全部同じじゃから、重なって表示されるんじゃ。 | 
    
![]()  | 
      うーん、そしたら、一文字表示されるごとに、表示位置を横にずらしていかなあかんのやな。でも、一文字当たりどんだけずらせばええんやろ? | 
![]()  | 
       Bitmapクラスのメソッドを思い出してみい。 | 
    
![]()  | 
      そうか。text_sizeや。これで文字幅が分かるから、その分ずらせばええねんな。 | 
![]()  | 
       うむ、文字幅は、@sprite.bitmap.text_size(c).widthで分かるぞ。 | 
    
![]()  | 
      よし、ならこうや。描画位置を、変数xで指定するようにしたで。ほんで、描画するたんびに文字幅を、xに加算するんや。 | 
| 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  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak x = 0 loop do c = @word.slice!(/./m) if c == nil break end @sprite.bitmap.draw_text( x, 0, 640, 30, c) x += @sprite.bitmap.text_size(c).width end end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
       うむ、実行してみろ。 | 
    
![]()  | 
      よしゃ、これでどうや! | 

![]()  | 
      おお、表示されたで。 | 
![]()  | 
       うむ、しかしはみ出ておるのう。 | 
    
![]()  | 
      そ、それはこれからやんか。ええと、はみ出さんためには、変数xの値が、画面の幅より大きゅうなったら、表示位置を下の行にすればええな。 | 
![]()  | 
       それなら、画面の幅を基準にするより、ビットマップの幅を基準にしたほうがええのう。描画するのは、ビットマップに対してじゃからのう。 | 
    
![]()  | 
      ビットマップの幅は、ええと、@sprite.bitmap.widthやな。ようし。 | 
| 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  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak x = 0 y = 0 loop do c = @word.slice!(/./m) if c == nil break end @sprite.bitmap.draw_text( x, y, 640, 30, c) x += @sprite.bitmap.text_size(c).width if x >= @sprite.bitmap.width x = 0 y += 30 end end end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
      行の高さは、とりあえず30でええな。draw_textの高さが30になってるからな。 | 
![]()  | 
       うむ、ええじゃろう。 | 
    
![]()  | 
      ようし、こんどこそ、うまくいくはずやで。 | 

![]()  | 
      やったで! 成功や! | 
![]()  | 
       うむ、まずまずじゃのう。 | 
    
![]()  | 
      なんやねん、まずまずて。ちょっと不満があるみたいやんか。 | 
![]()  | 
      うむ、今回はたまたまうまくいっておるがのう。実は、これでは駄目なんじゃ。 | 
![]()  | 
      何が、だめやねん・・・。 | 
![]()  | 
      では、6行目の@sprite.bitmap = Bitmap.new(640,480)の640を630にしてやってみい。描画するビットマップのサイズをちょっと狭めるわけじゃな。 | 
![]()  | 
      なんやねん、630にしたらどやっちゅうねんうん・・・。 | 

![]()  | 
      あれ? 右端が切れとる! | 
![]()  | 
       うむ、問題は、19行目の、x >= @sprite.bitmap.widthじゃのう。 これだと、仮にxが639で、@sprite.bitmap.widthが640の場合でも、条件に当てはまらんから、次の行へ送られずに同じ行に描画してしまう。 残りは、たった1ピクセルしかないのにのう。  | 
    
![]()  | 
      そっか、xに次の文字の幅を足した値が、@sprite.bitmap.widthを超えんようにせなあかんのやな。 | 
![]()  | 
       そうじゃな。そのためには、次の文字の幅も取得せんとな。 | 
    
![]()  | 
      ええと、もう一回、c = @word.slice!(/./m)をやったらええんかな? | 
![]()  | 
       いや、slice!をすると、次の文字が@wordから削除されてしまうから駄目じゃのう。そういうときは、sliceを使うといいぞ。 | 
    
![]()  | 
      ん? ! が無くなっただけか? | 
![]()  | 
      そうじゃ、sliceのほうは、抜き出した文字を元の文字列から削除せんのじゃ。 | 
![]()  | 
      そうなんか。なら、これでええな。 | 
| 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  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak x = 0 y = 0 loop do c = @word.slice!(/./m) if c == nil break end @sprite.bitmap.draw_text( x, y, 640, 30, c) x += @sprite.bitmap.text_size(c).width c = @word.slice(/./m) cw = @sprite.bitmap.text_size(c).width if x + cw >= @sprite.bitmap.width x = 0 y += 30 end end end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
      ようし、やってみるで。 | 

![]()  | 
      あれ? エラー出た・・・。 | 
![]()  | 
      出るのう。 | 
![]()  | 
      なんでなん? | 
![]()  | 
      うむ、これは順番に文字列を処理していって、最後の文字に来たときにエラーが出ておるのじゃ。 | 
![]()  | 
      最後の文字? | 
![]()  | 
       最後の文字の次の文字は無いじゃろ? そこで、次の文字を取得する、c = @word.slice(/./m)を実行すれば、cには、nilが入る。 となれば、cw = @sprite.bitmap.text_size(c).widthで文字幅を取得しようと思っても出来んわけじゃ。  | 
    
![]()  | 
      なるほど・・・。 | 
![]()  | 
      次の文字が無い場合、cwは0にしておけばええじゃろう。 | 
![]()  | 
       なら、こんでええかな? | 
    
| 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  | 
      class Test # 初期化 def initialize @word = "もふもふ" @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640,480) end # 文字を画面に表示 def speak x = 0 y = 0 loop do c = @word.slice!(/./m) if c == nil break end @sprite.bitmap.draw_text( x, y, 640, 30, c) x += @sprite.bitmap.text_size(c).width c = @word.slice(/./m) if c == nil cw = 0 else cw = @sprite.bitmap.text_size(c).width end if x + cw >= @sprite.bitmap.width x = 0 y += 30 end end end # 表示する文字を変更 def change_word(new_word) @word = new_word end end  | 
    
![]()  | 
      うむ、ええじゃろう。 | 
![]()  | 
      よし、今度こそ、動いてくれよ・・・。 | 

![]()  | 
      おっしゃ! こんどこそ完璧や! そうやろ、じいちゃん? | 
![]()  | 
      うむ、完璧というにはまだ早いが、現時点では、こんなもんじゃろうな。 | 
![]()  | 
      なんやねん、ちょっとくらい、ほめてくれてもええのに・・・。 | 
![]()  | 
      うむ、まあよくがんばったのう。 | 
![]()  | 
      やっぱし? わし、がんばった? | 
![]()  | 
      うむ、クラスとメソッドの基本は、このくらいでええじゃろうな。 | 
![]()  | 
      おっしゃ! クラスとメソッド終わり! | 
![]()  | 
      あくまで、基本は、じゃぞ? まだ3倍くらいは勉強することが残っておるからな。 | 
![]()  | 
      まだ、3倍もあんの・・・。 | 
![]()  | 
      うむ、しかし続きは、また後じゃ。次は、変数についてやるぞ。 | 
![]()  | 
      え? 変数については、もうやったやろ? | 
![]()  | 
      基礎はな。しかし、まだ5倍くらいやることが残っておる。 | 
![]()  | 
      5倍て・・・。そら、大げさに言うとんのやろ? | 
![]()  | 
      ・・・・・・・・・。 | 
![]()  | 
      大げさやないの・・・? | 
![]()  | 
      まあ、今日これだけがんばれたんじゃ。明日もがんばれるじゃろう。 | 
![]()  | 
       うう・・・。グレちゃんピンチ・・・。 | 
    
|  本日のおさらい ・クラスは、class〜endで定義 ・メソッドは、def〜endで定義 ・オブジェクトは、変数に代入して使う ・オブジェクトを生成するときは、クラス名.new(クラス名 ピリオド new) ・メソッドinitializeは、初期値設定に使う ・メソッドに値を引き渡したいときは、引数を使う 次の章は 第3章 変数の真実 リンク >>>この講座のトップページ >>>タンクタウンのトップページ  |