「敵キャラを動かす」の編集履歴(バックアップ)一覧に戻る

敵キャラを動かす - (2009/05/04 (月) 09:52:31) のソース

入門編・12
シューティングゲームもどきを作る
*敵キャラを動かす

せっかく敵キャラを作ったのに、動かないのでは面白くありません。
敵キャラが動くようにしましょう。
それぞれが独立して斜め方向に動き、画面端で反射して方向を変えるようにします。
なお、当たり判定はまだ作りません。

** 敵キャラに必要な要素
斜め方向に動く、ということで、『動く方向』と『スピード』を決めてやる必要があります。
Game_Enemyクラスの持つ変数に、下の二つを追加します。
>  attr_accessor   :direct                   # 移動方向。数字キーの位置
>  attr_accessor   :speed                    # 移動スピード。
移動方向のようなものも、普通は数字で管理します("左上"というような文字列ではなく)。
ここでは、数字キーと方向を合わせるようにしましょう。つまり、
左上:7、右上:9、左下:1、右下:3
と決めます。別に0,1,2,3と決めてやってもいいのですが、こうしておくと後でちょっと便利です。
そして、初期値を決めてやるために、initializeメソッド内に以下の行を追加します。
>    tmp = rand(3)
>    case tmp
>    when 0
>      @direct = 7
>    when 1
>      @direct = 9
>    when 2
>      @direct = 1
>    when 3
>      @direct = 3   
>    end
>    @speed = 3 + rand(2)
tmpは、一時的に使う変数によく使う名前で、この名前である必要はありません。
場合にもよりますが、通常直後のcase文や複雑な計算式で一瞬答えを置いておきたい時などに使います。
tmp = rand(3)によって、tmpには0,1,2,3のいずれかの数値が入ります。
そして、そのあとcase~whenによって、数値によって方向を決めています(文法はヘルプを参照)。例えば、tmpが0なら方向は7(左上)というように。
乱数で1,3,7,9のどれか、というような決め方は出来ないので、一旦別の変数に乱数を使ってからその変数の値で飛び飛びの値を割り振っています。まあ、RPGのイベントとかでもよく使う手ですかね?
最後の行でspeedを決めています。こちらも乱数で、ちょっと動きが読みづらくしています。speedの値は3,4,5のいずれかになります。

** 敵キャラを動かす
では、動かしてみましょう。自機の移動をupdate内に書いたのと同様、敵キャラの移動もGame_Enemyのupdate内に記述します。
>  #--------------------------------------------------------------------------
>  # ● 更新
>  #--------------------------------------------------------------------------
>  def update
>    if @alive == true then 
>      move                                    # 移動
>      check_wall                              # 壁に当たった場合の判定
>    end
>  end
moveという移動メソッド、check_wallという壁反射についてのメソッドを追加します。
生きていなければ移動もしなくていいので、if文で生きている時だけ移動するようにしています。
それぞれのメソッドの中身はこんな感じです。
>  #--------------------------------------------------------------------------
>  # ● 移動
>  #--------------------------------------------------------------------------
>  def move
>    case @direct
>    when 1
>      @x -= @speed
>      @y += @speed
>    when 3
>      @x += @speed
>      @y += @speed    
>    when 7
>      @x -= @speed
>      @y -= @speed
>    when 9
>      @x += @speed
>      @y -= @speed
>    end
>  end
>
>  #--------------------------------------------------------------------------
>  # ● 壁に当たった場合を判定。
>  #--------------------------------------------------------------------------
>  def check_wall
>    if @x < 0 then
>      @direct += 2
>    end
>    if @x > (WND_X-SIZE_X) then
>      @direct -= 2
>    end
>    if @y < 0 then
>      @direct -= 6
>    end
>    if @y > (WND_Y-SIZE_Y) then
>      @direct += 6
>    end        
>  end
moveの方は、@directの値によって移動を行っているだけです。これだけだと、画面のはるか遠くまでぶっ飛んで行ってしまいます。
check_wallでそうならないようにしているわけですが、こちらは少し複雑です。
if文四つで出来ていますが、まず最初のif文を見てみましょう。
>    if @x < 0 then
>      @direct += 2
>    end
敵キャラのx座標が0より小さい時、つまり左端からはみ出している時、方向の値に2を加えます。
2を加えるって何でしょうか?
想像してみましょう。左にぶつかりうるのは、左下に移動中(1)か左上に移動中(7)です。そして、左下に移動中なら反射して右下に移動(3)、左上なら右上(9)に方向転換します。
つまり、1→3、7→9と変化するわけです。どちらも2増えています。これが+2というわけです。
他のif文も同様、これにより壁による反射が実現します。
実行してみましょう。画面を5機のUFOが跳ね回ったら成功です。意外とよけるの難しいですが、当たっても何も起こりません。

** 実は……
シューティングゲームもどきとは言え、この方法による反射は結構ずさんです。
速度が変わるようなことが起こると、壁にめり込んでしまったりします。
まあ、目標はシューティングゲームではなくRGSSの習得なので、ご容赦を……。
穴のないプログラムを作成されたい方は、別途ゲームのアルゴリズムを扱った本やサイトを参照して下さい。

----
[[前へ>敵キャラを作成する2]]・[[次へ>当たり判定をつける]]
----
#comment_num2(size=40,vsize=4,num=20,logpage=コメント一覧)
目安箱バナー