「入力を受け取る」(2009/04/17 (金) 23:09:55) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
入門編・9
シューティングゲームもどきを作る
*入力を受け取る
さて、今回はいよいよ外部からの入力を受け取ります。
**シーンのupdateの中身を追加する
入力を受け取る方法に入る前に、以前解説したゲームの流れ
開始処理
メインループ(表示・入力・計算)
終了処理
の流れをもう少し完成型に近づけましょう。
今回、入力によって自機の位置を移動させますが、この自機の位置が常にスプライトに
反映されるようにしないと、画面上で自機が移動しません。
Scene_Shootingのupdateメソッドに以下の内容を追加してください。
> #--------------------------------------------------------------------------
> # ● フレーム更新
> #--------------------------------------------------------------------------
> def update
> @myMachine.update
> @s_myMachine.update
> end
ゲームオブジェクト、及びスプライトを、update、フレーム更新のたびに更新します。
前回やったように、@s_myMachine.update、つまりスプライトのupdateを入れないと、
自機を動かしてもスプライトの位置に反映されません。
@myMachine.updateは今のところ何もありませんが、今回から処理を追加していきます。
** 自機にspeedのパラメータを追加する
入力によって自機が移動するようになる前に、自機のスピードを、パラメータとして決めておきましょう。
新たにパラメータを追加する場合は、自機のクラスであるGame_MyMachineに変数を追加します。
これはx座標、y座標の値をx,yとして決めた時と同様、
変数の宣言の所に、
> attr_accessor :speed # 自機移動速度
を、また、初期の値として、initializeメソッドに
> def initialize
> @x=120
> @y=200
> @speed=3 # この行を追加
> end
と行を加えて初期化しましょう。なお、この値は好きに決めて構いません。
これで、Game_MyMachineクラスのインスタンス変数speedが追加されました。
** 自機のフレーム更新に、入力による移動を追加する
> #--------------------------------------------------------------------------
> # ● 更新
> #--------------------------------------------------------------------------
> def update
> move_by_input
> end
Game_MyMachineクラスのupdateに、入力を受け取って自機を動かすメソッドmove_by_inputを追加します。
そして、その内容を次のように定義します。
> #--------------------------------------------------------------------------
> # ● 方向ボタン入力による移動処理
> #--------------------------------------------------------------------------
> def move_by_input
> case Input.dir8
> when 1; move_downleft
> when 2; move_down
> when 3; move_downright
> when 4; move_left
> when 6; move_right
> when 7; move_upleft
> when 8; move_up
> when 9; move_upright
> end
> check_position
> end
ここでいったん区切ります。
まず見て欲しいのが、定義開始(def)の次の行。
Input.dir8というのがありますね。
これは、方向キーで、どの方向のキーが押されているかを、テンキー(キーボードの右側にある数字キー)の位置1~9に対応した
値に返す、Inputモジュール(RGSS内部)の、dir8というメソッドです。
例えば、左上を押していると7、右を押していると6、というような値を返します。
そして、そのメソッドから返ってきた値が、case~whenで評価されます。
case~whenはRubyの文法で、caseの後ろの値(ここでは、dir8のメソッドが返した値)によって処理を分岐し、
whenの後ろの値と等しい処理を実行するというものです。
例えば、左上、7という値がdir8によって返されたら、when 7の右のmove_upleftが実行されます。
move_○○の内容はまだ定義していません。
下から3行目のendが、case~whenの流れがここで終わっている、という意味のendです。
move_○○と最後から2行目のcheck_positionについては、下に載せます。
> #--------------------------------------------------------------------------
> # ● 実際の移動
> #--------------------------------------------------------------------------
> def move_down
> self.y+=speed
> end
> def move_up
> self.y-=speed
> end
> def move_right
> self.x+=speed
> end
> def move_left
> self.x-=speed
> end
> def move_downleft
> self.x-=speed*5/7
> self.y+=speed*5/7
> end
> def move_downright
> self.x+=speed*5/7
> self.y+=speed*5/7
> end
> def move_upleft
> self.x-=speed*5/7
> self.y-=speed*5/7
> end
> def move_upright
> self.x+=speed*5/7
> self.y-=speed*5/7
> end
長いですが、似たような文が続いているだけです。
+=とか-=というのは、あるパラメータの元の値に値を足したり引いたりという意味で、例えば
> self.y+=speed
は、self.y(自機のy座標)の値にspeedの値(先ほど定めたもの)を足せ、という意味です。
つまり、自機のy座標がspeedの値だけ加算され、自機は下方向に移動します。
方向キーと同じ方向に自機がspeedの値だけ移動するように定義しています。
なお、*5/7というのは、斜めに動く際、斜め移動の距離を調整するためにかけたり割ったりして調整している計算です。
縦と横にspeedだけ動かすと、直線距離ではspeedより大きな距離を移動してしまうためです。
数学が得意な方なら、およそ√2で割っていると言った方がいいでしょうか。
ところで、self.speedとしなくていいんでしょうかね?
打ってから気づいたんですが、これでも動いてるのでしなくてもいいんでしょう。
式の右辺のパラメータのselfは省略できる気がします。
** 画面からはみ出さないようにする
さて、これによって入力を受け取って移動したわけですが、
このままだと画面を飛び出してどこまでも移動できてしまいます。
まあ多少飛び出てもエラーにはならないんですが、あまりxやyが大きくなると変数の取れる値をオーバーして
強制終了とかになってしまう気がします。そこで、次のメソッドcheck_positionで値を画面内に納めます。
> #--------------------------------------------------------------------------
> # ● 画面からはみ出てないかのチェック
> #--------------------------------------------------------------------------
> def check_position
> self.x = [[@x, 0].max, WND_X-SIZE_X].min
> self.y = [[@y, 0].max, WND_Y-SIZE_Y].min
> end
ややこしい文です。この文は、
[@x, 0].max
でまず一区切り、このmaxというのは、[]内の値の大きい方を返す、というメソッドです。
これもRubyの文法です。続いて、返された大きい方の値を使って、
[(大きい方の値), WND_X-SIZE_X].min
今度は、小さい方の値を返すメソッドを使っています。
WND_X-SIZE_Xは、定数の引き算で、WND_Xは画面サイズ、SIZE_Xは自機サイズです。
なぜSIZE_Xを引くのか分からない人は、引かないとどうなるか試してみましょう。自機のサイズ分はみ出ます。
で、このmaxとminを使って、何をしているんでしょうか?
これは、xの値を、0からWND_X-SIZE_Xの値の範囲になるように、はみ出ていたら最小値または最大値に等しくなるように
修正する役割をしています。
例えば、自機のx座標が-120だとしましょう。すると、最初の[@x, 0].maxでは、-120と0の大きい方、つまり0が返されます。
次に、0とWND_X-SIZE_Xの小さい方、0が返され、この値がself.xに代入されます。
つまり、-120という位置が0に修正されます。
大きい方も同様です。考えてみましょう。
この手法は、RPG内でも所持金が変な値にならないように決めたりする際に使われています。
** Input.dir8は、『入力を受け取る』ではない
細かい話になりますが、以前メインループは表示・入力・更新というループで動いていると言いました。
今回のInput.dir8は、あたかも入力に相当するかのようですが、実は入力ではなく更新に含まれます
(update内に入っているので、立場的に『更新』なのは明らかです)。
入力、に相当するのは、あくまでInput.updateの部分。ここで受け取った入力を使って、Input.dir8が
どんな値になるのかを計算しています。
なぜこんな細かい話をするかというと、updateの間にInput.dir8の値が変わったら困る! と考える人が
いるかも知れないからです。
一度Input.updateをしたら、次のInput.updateまでInput.dir8他Input関連の値は変わりません。
なので、まあ、そういった部分の記述に気を配らなくても大丈夫です。
----
[[前へ>自機を表示する]]・[[次へ>敵キャラを作成する]]
----
#comment_num2(size=40,vsize=4,num=20,logpage=コメント一覧)
入門編・9
シューティングゲームもどきを作る
*入力を受け取る
さて、今回はいよいよ外部からの入力を受け取ります。
**シーンのupdateの中身を追加する
入力を受け取る方法に入る前に、以前解説したゲームの流れ
開始処理
メインループ(表示・入力・計算)
終了処理
の流れをもう少し完成型に近づけましょう。
今回、入力によって自機の位置を移動させますが、この自機の位置が常にスプライトに
反映されるようにしないと、画面上で自機が移動しません。
Scene_Shootingのupdateメソッドに以下の内容を追加してください。
> #--------------------------------------------------------------------------
> # ● フレーム更新
> #--------------------------------------------------------------------------
> def update
> @myMachine.update
> @s_myMachine.update
> end
ゲームオブジェクト、及びスプライトを、update、フレーム更新のたびに更新します。
前回やったように、@s_myMachine.update、つまりスプライトのupdateを入れないと、
自機を動かしてもスプライトの位置に反映されません。
@myMachine.updateは今のところ何もありませんが、今回から処理を追加していきます。
** 自機にspeedのパラメータを追加する
入力によって自機が移動するようになる前に、自機のスピードを、パラメータとして決めておきましょう。
新たにパラメータを追加する場合は、自機のクラスであるGame_MyMachineに変数を追加します。
これはx座標、y座標の値をx,yとして決めた時と同様、
変数の宣言の所に、
> attr_accessor :speed # 自機移動速度
を、また、初期の値として、initializeメソッドに
> def initialize
> @x=120
> @y=200
> @speed=3 # この行を追加
> end
と行を加えて初期化しましょう。なお、この値は好きに決めて構いません。
これで、Game_MyMachineクラスのインスタンス変数speedが追加されました。
** 自機のフレーム更新に、入力による移動を追加する
> #--------------------------------------------------------------------------
> # ● 更新
> #--------------------------------------------------------------------------
> def update
> move_by_input
> end
Game_MyMachineクラスのupdateに、入力を受け取って自機を動かすメソッドmove_by_inputを追加します。
そして、その内容を次のように定義します。
> #--------------------------------------------------------------------------
> # ● 方向ボタン入力による移動処理
> #--------------------------------------------------------------------------
> def move_by_input
> case Input.dir8
> when 1; move_downleft
> when 2; move_down
> when 3; move_downright
> when 4; move_left
> when 6; move_right
> when 7; move_upleft
> when 8; move_up
> when 9; move_upright
> end
> check_position
> end
ここでいったん区切ります。
まず見て欲しいのが、定義開始(def)の次の行。
Input.dir8というのがありますね。
これは、方向キーで、どの方向のキーが押されているかを、テンキー(キーボードの右側にある数字キー)の位置1~9に対応した
値に返す、Inputモジュール(RGSS内部)の、dir8というメソッドです。
例えば、左上を押していると7、右を押していると6、というような値を返します。
そして、そのメソッドから返ってきた値が、case~whenで評価されます。
case~whenはRubyの文法で、caseの後ろの値(ここでは、dir8のメソッドが返した値)によって処理を分岐し、
whenの後ろの値と等しい処理を実行するというものです。
例えば、左上、7という値がdir8によって返されたら、when 7の右のmove_upleftが実行されます。
move_○○の内容はまだ定義していません。
下から3行目のendが、case~whenの流れがここで終わっている、という意味のendです。
move_○○と最後から2行目のcheck_positionについては、下に載せます。
> #--------------------------------------------------------------------------
> # ● 実際の移動
> #--------------------------------------------------------------------------
> def move_down
> self.y+=speed
> end
> def move_up
> self.y-=speed
> end
> def move_right
> self.x+=speed
> end
> def move_left
> self.x-=speed
> end
> def move_downleft
> self.x-=speed*5/7
> self.y+=speed*5/7
> end
> def move_downright
> self.x+=speed*5/7
> self.y+=speed*5/7
> end
> def move_upleft
> self.x-=speed*5/7
> self.y-=speed*5/7
> end
> def move_upright
> self.x+=speed*5/7
> self.y-=speed*5/7
> end
長いですが、似たような文が続いているだけです。
"+="とか"-="というのは、あるパラメータの元の値に値を足したり引いたりという意味で、例えば
> self.y+=speed
は、self.y(自機のy座標)の値にspeedの値(先ほど定めたもの)を足せ、という意味です。
つまり、自機のy座標がspeedの値だけ加算され、自機は下方向に移動します。
方向キーと同じ方向に自機がspeedの値だけ移動するように定義しています。
なお、*5/7というのは、斜めに動く際、斜め移動の距離を調整するためにかけたり割ったりして調整している計算です。
縦と横にspeedだけ動かすと、直線距離ではspeedより大きな距離を移動してしまうためです。
数学が得意な方なら、およそ√2で割っていると言った方がいいでしょうか。
ところで、self.speedとしなくていいんでしょうかね?
打ってから気づいたんですが、これでも動いてるのでしなくてもいいんでしょう。
式の右辺のパラメータのselfは省略できる気がします。
** 画面からはみ出さないようにする
さて、これによって入力を受け取って移動したわけですが、
このままだと画面を飛び出してどこまでも移動できてしまいます。
まあ多少飛び出てもエラーにはならないんですが、あまりxやyが大きくなると変数の取れる値をオーバーして
強制終了とかになってしまう気がします。そこで、次のメソッドcheck_positionで値を画面内に納めます。
> #--------------------------------------------------------------------------
> # ● 画面からはみ出てないかのチェック
> #--------------------------------------------------------------------------
> def check_position
> self.x = [[@x, 0].max, WND_X-SIZE_X].min
> self.y = [[@y, 0].max, WND_Y-SIZE_Y].min
> end
ややこしい文です。この文は、
[@x, 0].max
でまず一区切り、このmaxというのは、[]内の値の大きい方を返す、というメソッドです。
これもRubyの文法です。続いて、返された大きい方の値を使って、
[(大きい方の値), WND_X-SIZE_X].min
今度は、小さい方の値を返すメソッドを使っています。
WND_X-SIZE_Xは、定数の引き算で、WND_Xは画面サイズ、SIZE_Xは自機サイズです。
なぜSIZE_Xを引くのか分からない人は、引かないとどうなるか試してみましょう。自機のサイズ分はみ出ます。
で、このmaxとminを使って、何をしているんでしょうか?
これは、xの値を、0からWND_X-SIZE_Xの値の範囲になるように、はみ出ていたら最小値または最大値に等しくなるように
修正する役割をしています。
例えば、自機のx座標が-120だとしましょう。すると、最初の[@x, 0].maxでは、-120と0の大きい方、つまり0が返されます。
次に、0とWND_X-SIZE_Xの小さい方、0が返され、この値がself.xに代入されます。
つまり、-120という位置が0に修正されます。
大きい方も同様です。考えてみましょう。
この手法は、RPG内でも所持金が変な値にならないように決めたりする際に使われています。
** Input.dir8は、『入力を受け取る』ではない
細かい話になりますが、以前メインループは表示・入力・更新というループで動いていると言いました。
今回のInput.dir8は、あたかも入力に相当するかのようですが、実は入力ではなく更新に含まれます
(update内に入っているので、立場的に『更新』なのは明らかです)。
入力、に相当するのは、あくまでInput.updateの部分。ここで受け取った入力を使って、Input.dir8が
どんな値になるのかを計算しています。
なぜこんな細かい話をするかというと、updateの間にInput.dir8の値が変わったら困る! と考える人が
いるかも知れないからです。
一度Input.updateをしたら、次のInput.updateまでInput.dir8他Input関連の値は変わりません。
なので、まあ、そういった部分の記述に気を配らなくても大丈夫です。
----
[[前へ>自機を表示する]]・[[次へ>敵キャラを作成する]]
----
#comment_num2(size=40,vsize=4,num=20,logpage=コメント一覧)
表示オプション
横に並べて表示:
変化行の前後のみ表示: