シューティングゲームの作り方5


1. 画像を表示する
2. 方向キーで画像を移動する
3. 自機クラスを作る
4. シーンクラスを作る

5. 弾を撃つ
6. 敵を作る
7. 当たり判定を作る

8. 敵に弾を撃たせる
9. 耐久力を持たせる
10. 敵を爆発させる
11. スコアを表示する

12. 背景を表示する
13. 表示優先順位を決める
14. 背景をスクロールさせる
15. 背景を多重スクロールさせる
16. 地面に当たり判定を付ける

17. タイトル画面を作る
18. スコアランキング画面を作る
19. ネームエントリー画面を作る
20. ランキングデータを読み書きする


17. タイトル画面を作る

久々に新しいシーンクラスですね。
タイトル画面はタイトル絵を表示して、キーが押されたらゲーム画面へ移動する。
という機能さえあれば十分です。

まずはタイトル画像を用意します。
title.png
手抜きですねー。

次にシーンクラスをちゃちゃっと仕上げましょう。
class Scene_title
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    title = Sprite.new
    title.bitmap = RPG::Cache.picture("title") 
    #文字表示
    press = Sprite.new
    press.bitmap = Bitmap.new(120,32)
    press.bitmap.draw_text(0, 0, 120, 24, "press Z key")
    press.x = 264
    press.y = 220
    #フレームカウントの初期化
    Graphics.frame_count = 0
    
    # メインループ
    loop do
      #ボタンが押されたらシーンを移動
      if Input.trigger?(Input::A)
        title.dispose
        press.dispose
        $scene = Scene_stg.new
        break
      end
      #文字の点滅
      press.flash(nil, 25) if Graphics.frame_count % 50 == 0
      press.update
      Input.update 
      Graphics.update
    end
  end
end

ただの静止画では面白くないので"press Z key"の文字を点滅させてみました。

それから実行部も修正しましょう。
$scene = Scene_title.new
$scene.main while(1)

どのクラスからでも呼び出せるようにsceneをグローバル変数にしました。
while(1)で永遠に繰り返すようになります。
これで$sceneに代入されたシーンクラスのmainメソッドを呼び出し続けます。

ところでScene_stgにて自機がやられたらタイトル画面に戻るようにしないといけませんね。
Scene_stgを一気に改造しますよ。
class Scene_stg
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #各種変数の初期設定
    @shot = Array.new          #自機の弾を格納
    @enemy = Array.new         #敵を格納
    @enemyshot = Array.new     #敵の弾を格納
    @burst = Array.new         #爆発アニメーションを格納
    @shot_interval = 3         #弾の発射間隔(フレーム)
    @shot_count = 0            #弾の発射間隔をカウントする変数
    @score = 0                 #スコア
    @prescore = 0              #スコアの変化を監視するため前回のスコアを記録
    @prelife = 0               #ライフの変化を監視するため前回のライフを記録
    Graphics.frame_count = 0   #フレームカウントの初期化
    
    #背景表示
    @background1 = Stg_background.new(0, 0, 10, 2, "back")
    @background2 = Stg_background.new(640, 0, 10, 2, "back")
    @background3 = Stg_background.new(640, 320, 15, 4, "front")
    
    #自機表示
    @player = Stg_player.new
    
    #スコア、ライフの表示
    @menuview = Sprite.new
    @menuview.bitmap = Bitmap.new(640,32)
    @menuview.bitmap.draw_text(0, 0, 96, 32, "Score")
    @menuview.bitmap.draw_text(200, 0, 96, 32, "Life")
    @menuview.z = 200
    @scoreview = Sprite.new
    @scoreview.bitmap = Bitmap.new(96,32)
    @scoreview.bitmap.draw_text(0, 0, 96, 32, "0")
    @scoreview.x = 64
    @scoreview.z = 200
    @lifeview = Sprite.new
    @lifeview.bitmap = Bitmap.new(96,32)
    @lifeview.bitmap.draw_text(0, 0, 96, 32, "★★★★★")
    @lifeview.x = 240
    @lifeview.z = 200

    #メインループ
    loop do
      #自機の操作
      @player.move
      
      #自機の弾を発射
      player_shot()
      
      #敵キャラの生成
      make_enemy()
      
      #弾と敵の接触処理
      enemy_crash()
      
      #敵のショット
      enemy_shot()
      
      #敵の弾と自機の接触処理
      player_crash()
      
      #背景スクロール
      background_move()
      
      #地形と自機の接触処理
      player_land_crash()
      
      #スコア書き換え
      change_score()
      
      #ライフ書き換え
      change_life()
      
      #ライフが0になるとシーンを移動
      if @player.life == 0
        #自機消滅
        gameover()
        #全画像開放
        allclear()
        #タイトル画面へ
        $scene = Scene_title.new
        return
      end
      
      #各種更新
      Input.update 
      Graphics.update
    end
  end
  
  #--------------------------------------------------------------------------
  # ● 自機のショット
  #--------------------------------------------------------------------------
  def player_shot
    if Input.press?(Input::A) and @shot.size < 10
      @shot_count += 1
      if @shot_count == @shot_interval
        @shot_count = 0
        @shot.push Stg_bullet.new(@player.x + 32, @player.y)
      end
    end
    #弾の移動&削除
    @shot.reject!{|i|i.move}
  end
  
  #--------------------------------------------------------------------------
  # ● 敵キャラの生成
  #--------------------------------------------------------------------------
  def make_enemy
    if Graphics.frame_count % 100 == 0
      @enemy.push Stg_enemy.new(672, rand(480),1)
    end
    if Graphics.frame_count % 250 == 0
      @enemy.push Stg_enemy.new(672, rand(480),2)
    end
    if Graphics.frame_count % 550 == 0
      @enemy.push Stg_enemy.new(672, rand(280)+100,3)
    end
    @enemy.reject!{|i|i.move}
  end
  
  #--------------------------------------------------------------------------
  # ● 弾と敵の接触処理
  #--------------------------------------------------------------------------
  def enemy_crash
    @shot.each{|i|
      @enemy.each{|j|
        if crash?(i, j)
          i.dispose
          if j.damage
            @score += j.score
            @burst.push Stg_burst.new(j.x, j.y)
            j.dispose
            @enemy.delete(j)
          end
          break
        end
      }
      #背景と敵の当たり判定
      unless i.disposed?
        if @background3.crash(i.x - @background3.x, i.y - @background3.y)
          i.dispose
        end
      end
    }
    @shot.reject!{|i|i.disposed?}
    @burst.reject!{|i|i.move}
  end
  
  #--------------------------------------------------------------------------
  # ● 当たり判定
  #--------------------------------------------------------------------------
  def crash?(obj1, obj2)
    if (obj1.x - obj2.x).abs < obj1.dx + obj2.dx and 
      (obj1.y - obj2.y).abs < obj1.dy + obj2.dy
      return true 
    else
      return false
    end
  end
  
  #--------------------------------------------------------------------------
  # ● 敵のショット
  #--------------------------------------------------------------------------
  def enemy_shot
    @enemy.each{|i|
      type = i.attack
      case type
      when 1
        @enemyshot.push Stg_bullet.new(i.x, i.y, 1)
      when 2
        @enemyshot.push Stg_bullet.new(i.x, i.y, 2,@player.x, @player.y)
      when 3
        @enemyshot.push Stg_bullet.new(i.x, i.y, 3, @player.x, @player.y, -0.1)
        @enemyshot.push Stg_bullet.new(i.x, i.y, 3, @player.x, @player.y, 0)
        @enemyshot.push Stg_bullet.new(i.x, i.y, 3, @player.x, @player.y, 0.1)
      when 4
        for rot in 0..11
          @enemyshot.push Stg_bullet.new(i.x, i.y, 4, 0,0,0,rot*30)
        end
      end
    }
    @enemyshot.reject!{|i|i.move}
  end
  
  #--------------------------------------------------------------------------
  # ● 敵の弾と自機の接触処理
  #--------------------------------------------------------------------------
  def player_crash
    @enemyshot.each{|i|
      if crash?(i, @player)
        @player.damage
        i.dispose
      #背景と敵の弾の当たり判定
      elsif @background3.crash(i.x - @background3.x, i.y - @background3.y)
        i.dispose
      end
    }
    @enemyshot.reject!{|i|i.disposed?}
    @player.update
  end
  
  #--------------------------------------------------------------------------
  # ● 背景スクロール
  #--------------------------------------------------------------------------
  def background_move
    @background1.move
    @background2.move
    @background3.move
  end
  
  #--------------------------------------------------------------------------
  # ● 地形と自機の接触処理
  #--------------------------------------------------------------------------
  def player_land_crash
    if @background3.crash(@player.x - @background3.x, @player.y - @background3.y)
      @player.damage
    end
  end
  
  #--------------------------------------------------------------------------
  # ● スコア書き換え
  #--------------------------------------------------------------------------
  def change_score
    if @score != @prescore
      @scoreview.bitmap.clear
      @scoreview.bitmap.draw_text(0, 0, 96, 32, "#{@score}" ,2)
      @prescore = @score
    end
  end
  
  #--------------------------------------------------------------------------
  # ● ライフ書き換え
  #--------------------------------------------------------------------------
  def change_life
    if @player.life != @prelife
      @lifeview.bitmap.clear
      @lifeview.bitmap.draw_text(0, 0, 96, 32, "★"*@player.life)
      @prelife = @player.life
    end
  end
  
  #--------------------------------------------------------------------------
  # ● ゲームオーバー
  #--------------------------------------------------------------------------
  def gameover
    #自機の消滅
    @burst.push Stg_burst.new(@player.x, @player.y)
    @player.dispose
    #100フレーム停滞
    100.times{
      @burst.reject!{|i|i.move}
      Graphics.update
    }
  end
  
  #--------------------------------------------------------------------------
  # ● 全画像を開放
  #--------------------------------------------------------------------------
  def allclear
    @shot.each{|i|i.dispose}
    @enemyshot.each{|i|i.dispose}
    @enemy.each{|i|i.dispose}
    @background1.dispose
    @background2.dispose
    @background3.dispose
    @menuview.dispose
    @scoreview.dispose
    @lifeview.dispose
  end
end

まずはスコアとライフの画面表示を整理しました。
スコアと同じようにライフも前回の値を記録しておいて、変わったときだけ表示を更新しています。
表示のところで"★"*player.lifeとやっているのは★の文字をライフの数だけ繰り返すというものです。
結構便利ですね。

そして自機のlifeが0になったら100フレームの間画面を見せてからタイトルに戻ります。
このとき画像をすべてdisposeするのを忘れないようにしましょう。

これでゲームとしては一通り完成しました!



メニューへ


18. スコアランキング画面を作る

まずはランキング情報を保存する配列を用意します。
シーンクラスを超えて保持しておきたいのでグローバル変数を使います。
$ranking = Array.new(10,0)

こんな風に(10,0)とやると10個の要素に最初から0を代入した配列が出来上がります。
とりあえずトップ10だけを保存することにしました。

次にランキングデータの作り方です。
scoreを受け取って数字の大きい方から順番に並べてみましょう。
    $ranking[10] = score
    $ranking.sort!
    $ranking.reverse!

10個のランキングを作る場合には新しいスコアを11番目の要素に代入するのがミソです。
次のsort!は数字を小さい方から並べ換えるメソッドです。
さらにreverse!は配列を逆順に並べ替えます。これでスコアが大きい順に並びました。

それではランキングクラスを作りましょう。
class Scene_ranking
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    background = Sprite.new
    background.bitmap = RPG::Cache.picture("back") 
    #ランキングデータを書くためのスプライト表示
    rankingview = Sprite.new
    rankingview.bitmap = Bitmap.new(640,480)
    rankingview.bitmap.draw_text(0, 32, 640, 32, "Ranking", 1)
    #ランキングデータ10個の書き出し
    for i in 0..9
      y = i * 32 + 100
      rankingview.bitmap.draw_text(220, y, 32, 24, "#{i + 1}", 2)
      rankingview.bitmap.draw_text(220, y, 120, 24, "#{$ranking[i]}", 2)
    end
    
    # メインループ
    loop do
      #ボタンが押されたらシーンを移動
      if Input.trigger?(Input::A)
        background.dispose
        rankingview.dispose
        Input.update 
        $scene = Scene_title.new
        break
      end
      Input.update 
      Graphics.update
    end
  end
end

for i in 0..9は変数iの値を0〜9で移動させながら処理を10回繰り返しているわけですが、
その中でiが3通りの使われ方をしていることにお気づきでしょうか?
まずy = i * 32 + 100で文字を書き込むY座標をずらしています。
こうすればループ1回ごとに32ドット下へ移動していきます。
次に"#{i + 1}"は順位の1〜10を表示しています。
そして最後に"#{$ranking[i]}"は配列の添字として使われています。

あとはScene_stgからシーンの切り替え先をScene_rankingに変えれば完成です。



メニューへ


19. ネームエントリー画面を作る

これもシューティングのお約束なので作ってみましたが…、はっきり言って面倒くさいです。
プレイヤーも気にしないというか逆に名前入力が鬱陶しいという人もいるくらいなので
無いなら無いで構わないと思います。

と、変な前置きをしながら解説していきたいと思います。

まずはランキング情報に名前を入れるスペースを確保しましょう。
$ranking = Array.new(10,[0,"_____"].dup)

配列の中に配列が入りました。これも10個の要素を[0,"_____"]で埋めるということですが、
末尾にdupというのが付いていますね。これは新しい配列を作るというものです。
逆にdupを付けないと同じ配列で埋まります。
と、言って意味が伝わるでしょうか…。

試しに次のようなスクリプトを実行してみてください。
a = [0,1]
b = a
a[0] = 1
p a
p b

結果にアレ?っと思った人はいませんか?
a => [1,1]
b => [1,1]
となります。
数学の代入なんかを考えてみるとbの中身は弄ってないのにbの値が
変わってしまうのは何か変だなと思いますね。
実はbに代入されたのは配列そのものではなくaが参照しているアドレスなのです。
つまりaとbは同じ配列を見ているわけですね。
そんなわけで独立した配列を渡したい時にはb = a.dupという風にする必要があります。

さて寄り道をしましたが、さっそくネームエントリークラスを作りましょう。
class Scene_name
  #--------------------------------------------------------------------------
  # ● オブジェクト初期化
  #--------------------------------------------------------------------------
  def initialize(score)
    @score = score
  end
  
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    background = Sprite.new
    background.bitmap = RPG::Cache.picture("back") 
    #文字表示
    scoreview = Sprite.new
    scoreview.bitmap = Bitmap.new(640,24)
    scoreview.bitmap.draw_text(0, 0, 640, 24, "Score " + "#{@score}", 1)
    scoreview.y = 120

    #メインループ
    loop do
      #ボタンが押されたらシーンを移動
      if Input.trigger?(Input::A)
        $ranking[10] = [@score,"name"]
        $ranking.sort!
        $ranking.reverse!
        Input.update 
        background.dispose
        scoreview.dispose
        $scene = Scene_ranking.new
        break
      end
      Input.update 
      Graphics.update
    end
  end
end

とりあえず引数にscoreを受け取るようにしました。
今はまだスコアが表示されるだけです。
ついでにランキング作成のスクリプトをこちらに移動させてきました。

これに合わせてScene_stgのシーン切り替えの部分を書き換えましょう。
    if $ranking[9][0] < @score
      $scene = Scene_name.new(@score)
    else
      $scene = Scene_ranking.new
    end

獲得した点数がランキングの10個目より大きければネームエントリーに移動し、
小さければ直接ランキング画面に飛ぶようにしました。

さてScene_nameの続きを作りましょう。
名前の入力欄と名前入力に使える文字を表示します。
ここでは入力欄は5文字まで、使う文字はアルファベットのA〜Zと".","_"の28個とします。
class Scene_name
  #--------------------------------------------------------------------------
  # ● オブジェクト初期化
  #--------------------------------------------------------------------------
  def initialize(score)
    @score = score
  end
  
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    background = Sprite.new
    background.bitmap = RPG::Cache.picture("back") 
    #文字表示
    scoreview = Sprite.new
    scoreview.bitmap = Bitmap.new(640,24)
    scoreview.bitmap.draw_text(0, 0, 640, 24, "Score " + "#{@score}", 1)
    scoreview.y = 120
    #名前表示欄作成
    name =  Array.new(5, "_")
    nameview = Array.new(name.size)
    x = 280
    y = 160
    for i in 0...nameview.size
      nameview[i] = Sprite.new
      nameview[i].bitmap = Bitmap.new(24,24)
      nameview[i].bitmap.draw_text(0, 0, 24, 24, "_")
      nameview[i].x = x
      nameview[i].y = y
      x += 16
    end
    #文字セット作成
    charaset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ._"
    charaview = Array.new(charaset.size)
    width = 7
    height = charaset.size / width
    x = 240
    y = 200
    for i in 0...charaset.size
      charaview[i] = Sprite.new
      charaview[i].bitmap = Bitmap.new(24,24)
      charaview[i].bitmap.draw_text(0, 0, 24, 24, charaset[i].chr)
      charaview[i].x = x
      charaview[i].y = y
      x += 24
      if x > 240 + 24 * (width - 1)
        x = 240
        y += 24
      end
    end
    
    #メインループ
    loop do
      #ボタンが押されたらシーンを移動
      if Input.trigger?(Input::A)
        $ranking[10] = [@score,"name"]
        $ranking.sort!
        $ranking.reverse!
        Input.update
        background.dispose
        scoreview.dispose
        nameview.each{|i|i.dispose}
        charaview.each{|i|i.dispose}
        $scene = Scene_ranking.new
        break
      end
      Input.update 
      Graphics.update
    end
  end
end

配列nameviewには"_"が書かれたスプライト5枚を作り、配列charaviewには
28個の文字が書かれたスプライトを作って表示しました。
そのまま横につなげると長くなってしまうので、7個表示したら下の段に
折り返すように座標を操作しています。
まあ、文字セットの方はスプライトに分割する必要もなかったのですが…。

最後に文字の選択処理を作って完成させましょう。
class Scene_name
  #--------------------------------------------------------------------------
  # ● オブジェクト初期化
  #--------------------------------------------------------------------------
  def initialize(score)
    @score = score
  end
  
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    background = Sprite.new
    background.bitmap = RPG::Cache.picture("back") 
    #文字表示
    scoreview = Sprite.new
    scoreview.bitmap = Bitmap.new(640,24)
    scoreview.bitmap.draw_text(0, 0, 640, 24, "Score " + "#{@score}", 1)
    scoreview.y = 120
    #名前表示欄作成
    name =  Array.new(5, "_")
    nameview = Array.new(name.size)
    x = 280
    y = 160
    for i in 0...nameview.size
      nameview[i] = Sprite.new
      nameview[i].bitmap = Bitmap.new(24,24)
      nameview[i].bitmap.draw_text(0, 0, 24, 24, "_")
      nameview[i].x = x
      nameview[i].y = y
      x += 16
    end
    #文字セット作成
    charaset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ._"
    charaview = Array.new(charaset.size)
    width = 7
    height = charaset.size / width
    x = 240
    y = 200
    for i in 0...charaset.size
      charaview[i] = Sprite.new
      charaview[i].bitmap = Bitmap.new(24,24)
      charaview[i].bitmap.draw_text(0, 0, 24, 24, charaset[i].chr)
      charaview[i].x = x
      charaview[i].y = y
      x += 24
      if x > 240 + 24 * (width - 1)
        x = 240
        y += 24
      end
    end
    
    #メインループ
    number = 0
    c_position = 0
    loop do
      #ボタンAが押されたら名前欄の文字を1つ進める
      if Input.trigger?(Input::A)
        #名前欄の最後まできていたらランキングを更新してシーン移動
        if number == name.size
          #ランキング更新
          $ranking[10] = [@score,name.join]
          $ranking.sort!
          $ranking.reverse!
          Input.update 
          #全画像の開放
          background.dispose
          scoreview.dispose
          nameview.each{|i|i.dispose}
          charaview.each{|i|i.dispose}
          #ランキング画面へ移動
          $scene = Scene_ranking.new
          break
        end
        #選択された文字を名前欄に書き込む
        name[number] = charaset[c_position].chr
        nameview[number].bitmap.clear
        nameview[number].bitmap.draw_text(0, 0, 24, 24, name[number])
        number += 1
      end
      #ボタンBが押されたら名前欄の文字を1つ後退する
      if Input.trigger?(Input::B)
        if number > 0
          number -= 1
        end
      end
      #各方向キーに合わせて文字セットの位置を変更する
      if Input.trigger?(Input::DOWN)
        c_position += width
        if charaview[c_position] == nil
          c_position -= width * height
        end
      end
      if Input.trigger?(Input::LEFT) 
        c_position -= 1
        if charaview[c_position] == nil
          c_position = charaview.size - 1
        end
      end
      if Input.trigger?(Input::RIGHT) 
        c_position += 1
        if charaview[c_position] == nil
          c_position = 0
        end
      end
      if Input.trigger?(Input::UP) 
        c_position -= width
        if charaview[c_position] == nil
          c_position += width * height
        end
      end
      #名前欄の文字を点滅
      if Graphics.frame_count % 20 == 0
        nameview[number].flash(nil, 10) if nameview[number] != nil
      end
      nameview.each{|i|i.update}
      #文字セットのうち選択中の物の色を変更
      charaview.each{|i|i.color = Color.new(255, 255, 255, 255)}
      charaview[c_position].color = Color.new(0, 255, 255, 255)
      #各種更新
      Input.update 
      Graphics.update
    end
  end
end

何だが複雑なことをやっているようですが、要するに押された方向キーに合わせて
配列charaviewの添字c_positionを変化させて、そこに入っている画像(文字)の色を変えて
選択しているように見せています。
ボタンAが押されたら配列nameに選択した文字を代入して添字numberを進ませます。
ボタンBは逆にnumberを1つ戻します。
そしてnumber、つまり文字数が5個になったらランキングを完成させて
ランキングクラスに飛ばしています。

ここまでよろしい…ですかね…。

名前表示が増えたのでランキングクラスもそれに合わせて修正します。
class Scene_ranking
  #--------------------------------------------------------------------------
  # ● メイン処理
  #--------------------------------------------------------------------------
  def main
    #背景の画像表示
    background = Sprite.new
    background.bitmap = RPG::Cache.picture("back") 
    #ランキングデータを書くためのスプライト表示
    rankingview = Sprite.new
    rankingview.bitmap = Bitmap.new(640,480)
    rankingview.bitmap.draw_text(0, 32, 640, 32, "Ranking", 1)
    #ランキングデータ10個の書き出し
    for i in 0..9
      y = i * 32 + 100
      rankingview.bitmap.draw_text(220, y, 32, 24, "#{i + 1}", 2)
      rankingview.bitmap.draw_text(220, y, 120, 24, "#{$ranking[i][0]}", 2)
      rankingview.bitmap.draw_text(320, y, 120, 24, "#{$ranking[i][1]}", 2)
    end

    #メインループ
    loop do
      #ボタンが押されたらシーンを移動
      if Input.trigger?(Input::A)
        background.dispose
        rankingview.dispose
        Input.update 
        $scene = Scene_title.new
        break
      end
      Input.update 
      Graphics.update
    end
  end
end

ふぅ、やっと終わった…。



メニューへ


20. ランキングデータを読み書きする

ゲームを終了してもランキングを保存できるようにしましょう。
ファイル操作についての詳細はヘルプをご覧ください。
"ヘルプ→RGSSリファレンス→標準ライブラリ→組み込みクラス→Object→IO→File"

まずはセーブです。
file = File.open("date.rxdata", "wb")
  Marshal.dump($ranking, file)
file.close

"date.rxdata"という名前のファイルを上書き書き込みモード"wb"で開いて
$rankingの内容を書き込みます。

次にロードです。
if FileTest.exist?("date.rxdata")
  file = File.open("date.rxdata", "rb")
  $ranking = Marshal.load(file)
  file.close
end

セーブのタイミングはランキング作成直後、
ロードのタイミングは起動直後(実行部の最初)が良いでしょう。




さて、以上20項目全て終了しました。
これでシューティングに最低限必要だと思うことは粗方網羅したと思います。
それでもまだ物足りないという方は他のプログラミングサイトなども訪れてみましょう。
たとえコードが読めなくても考え方は学ぶことができます。


それではRGSSシューティングの繁栄を目指して頑張りましょう!



メニューへ

前のページへ
一覧へ戻る
トップページへ戻る



更新日時:2006/12/18 18:00
管理人:すっぴぃ ◆ADGYPSYxII