スクリプトを作れるようになろう-01

投稿者:Material 7186 1 mini ikosami 投稿日:2012/03/21 00:42

どうも。ikosamiです。

ブログなどを見ていると、
ノベルでスクリプトを組んで作るゲームを、
桁外れに難しい物だと、思い込んでしまっている人が多いようなので

今回は、できる限り簡単に、単純に迷路を作って
「あれ? こんな感じでも良いんだ?」
と、思ってもらいたいと思います。

なお、できる限り単純にしているので
今回は、画像は使いません。



①配列を使わない場合 (配列の便利さを知る)


まず、迷路なのでステージの形を作る必要があります。
とりあえず、配列を使わないで一番単純な方法で設定してみます。

迷路の形は(■=壁 ▽=自分 △=ゴール)
■■■■■
■▽■△■
■      ■
■  ■■■
■■■■■


です。(簡単すぎるのは気にしないでください。)

( 「;」を書くと、そこは改行したことになります。)



では、これでスクリプトを作ってみます。

※配列を使わないと、どういうことになるのかを知るための物ですので
 実際にこんな物は作らないでください。
 なので、詳しい説明はつけません。

b = 7#(自分の場所の設定)

loop = true #(ループの設定)
while loop #(クリアするまで無限ループ)

case speakWithSelect(4,"↑","→","←","↓", 
    "どちらに進みますか?")
  when 0
    if b == 12
      speak("進みました")
      b = 7
    elsf b == 14
      speak("ゴールです!")
      goEnding()
    elsf b == 17
      speak("進みました")
      b = 12
    else
      speak("その方向には壁があり、進めません")
    end
  when 1
    if b == 12
      speak("進みました")
      b = 13
    elsf b == 13
      speak("進みました")
      b = 14
    else
      speak("その方向には壁があり、進めません")
    end
  when 2
    if b == 13
      speak("進みました")
      b = 12
    elsf b == 14
      speak("進みました")
      b = 13
    else
      speak("その方向には壁があり、進めません")
    end
  when 3
    if b == 7
      speak("進みました")
      b = 12
    elsf b == 12
      speak("進みました")
      b = 17
    else
      speak("その方向には壁があり、進めません")
    end
end

end


と、こうなります。

まぁこの5×5程度のサイズなら、できなくはないですね。
それに、自分が入ることのできない位置は考えずに書いているので
これだけで済みます。

でも、これが20×20とかならどうなるでしょう?
配列を使わない場合、すべての可能性を書き出す必要があるので
ものすごい苦労することになります。

ちなみに、僕は本当に昔これをやっていて、
オセロの時は1000行超えてました。
http://rmake.jp/boards/2/topics/217


しかも、ステージのマップを少し変えるとなると、
このスクリプトはほとんど作り直しになります。

結論として、
配列を使わない=すべての可能性を自分で書き出す必要がある
ということです。

とりあえず、これだけでは、配列の重要性はわかりにくいと思うので、
次は配列を使ったスクリプトを書いてみます。








②配列を使ったスクリプトの作成

では、配列を使って、迷路のステージを作ってみたいと思います。

とりあえず、
http://page.rmake.jp/wikis/145
の、「配列を一気に設定する関数」を使います。

この関数は、絶対に必要なわけではありませんが、
これを使うと、すごく楽なので。



では、ステージを設定してみます。
■■■■■
■▽■△■
■      ■
■  ■■■
■■■■■

(■=壁 ▽=自分 △=ゴール)
(1=壁 2=ゴール)

s = createArray()
s[0] = Array("1,1,1,1,1")
s[1] = Array("1,0,1,2,1")
s[2] = Array("1,0,0,0,1")
s[3] = Array("1,0,1,1,1")
s[4] = Array("1,1,1,1,1")


では、スクリプトのほうを作ってみます。

まず自分の居場所を設定します。
x = 1; y = 1


配列は0から始まるので、そこは注意しましょう。

次はループの設定です。
ノベルでゲームを作る場合、
ループは、ほとんどの場合に使います。(本当のノベルゲームを除く)
loop = true
while loop

end


これだけです。


ゲームのスクリプトは
while loop

end
の間に書いていきます。


移動は、
case speakWithSelect(4,"↑","→","←","↓", 
    "どちらに進みますか?")
  when 0

  when 1

  when 2

  when 3

end

で十分です。



では、「↑」を選んだ場合のスクリプトを作っていきましょう。

まず、進んだ先が壁かどうかの判定をします。
if s[y-1][x] == 1
  speak("その方向には壁があり、進めません")
end


xとyに位置情報が入っているので、それで判定できます。
なお、xとyの順番を間違えると、正常に動作しません。
僕もしょっちゅう間違えるので、注意しましょう。

このスクリプトに、壁でなかった場合とゴールの時も付け足せば、
移動は完璧です。
if s[y-1][x] == 1
  speak("その方向には壁があり、進めません。")
elsif s[y-1][x] == 2
  speak("ゴールです。")
  goEnding()
else
  speak("進みました。")
  y = y - 1
end



では、これをすべての移動に当てはめてみましょう。


case speakWithSelect(4,"↑","→","←","↓", 
    "どちらに進みますか?")
  when 0
    
    if s[y-1][x] == 1
      speak("その方向には壁があり、進めません。")
    elsif s[y-1][x] == 2
      speak("ゴールです。")
      goEnding()
    else
      speak("進みました。")
      y = y - 1
    end
  when 1
    if s[y][x+1] == 1
      speak("その方向には壁があり、進めません。")
    elsif s[y][x+1] == 2
      speak("ゴールです。")
      goEnding()
    else
      speak("進みました。")
      x = x + 1
    end
  when 2
    if s[y][x-1] == 1
      speak("その方向には壁があり、進めません。")
    elsif s[y][x-1] == 2
      speak("ゴールです。")
      goEnding()
    else
      speak("進みました。")
      x = x - 1
    end
  when 3
    if s[y+1][x] == 1
      speak("その方向には壁があり、進めません。")
    elsif s[y+1][x] == 2
      speak("ゴールです。")
      goEnding()
    else
      speak("進みました。")
      y = y + 1
    end
end


それぞれどこが違うわかりますか?

↑の場合は y-1
→の場合は x+1
←の場合は x-1
↓の場合は y+1
となっています。

でも、これはほとんど同じですよね?
違う場所が1箇所や2箇所なら、もっとまとめることができます。


こんな感じで。
case speakWithSelect(4,"↑","→","←","↓", 
    "どちらに進みますか?")
  when 0
    xi =  0;yi = -1
  when 1
    xi =  1;yi =  0
  when 2
    xi = -1;yi =  0
  when 3
    xi =  0;yi =  1
end

if s[y+yi][x+xi] == 1
  speak("その方向には壁があり、進めません。")
elsif s[y+yi][x+xi] == 2
  speak("ゴールです。")
  goEnding()
else
  speak("進みました。")
  x = x + xi;y = y + yi
end



何をしたかわかりますか?

それぞれのどこがどう違うのかがはっきりしている場合は、
その違いを別の変数に入れて、
その変数を足す ということをすれば
だいぶ楽になります。

でも、これは少しわかりづらいだけで、
ほとんどの人が使っている方法です。

例えば、こんな感じ

case speakWithSelect(3,"100円","200円","300円", 
    "いくらの物を買いますか?")
  when 0
    cost = 100
  when 1
    cost = 200
  when 2
    cost = 300
end

money = money - cost

って感じで。

ああ、あとついでに、エラー時の対応もしておきましょう。
if s[y+yi][x+xi] == 1
  speak("その方向には壁があり、進めません。")
elsif s[y+yi][x+xi] == 2
  speak("ゴールです。")
  goEnding()
else
  speak("進みました。")
  x = x + xi;y = y + yi
end

これだと、もしステージの設定ミスで
外周に壁を作り忘れた場合どうなると思いますか?

設定の外に出てしまうので
[y+yi][x+xi] = null
となります。(null=「何も示さないもの」)

s[y+yi][x+xi] == 1 にも
s[y+yi][x+xi] == 2 にも当てはまらないので、
else の処理が行われて、永遠に進み続けることになります。

市販のゲームなどのすり抜けバグは、
これが理由で、永遠に進むことができてしまうのです。

なので、
if s[y+yi][x+xi] == 0
  speak("進みました。")
  x = x + xi;y = y + yi
elsif s[y+yi][x+xi] == 2
  speak("ゴールです。")
  goEnding()
else
  s[y+yi][x+xi] == 1
  speak("その方向には壁があり、進めません。")
end


として、nullの場合は進めないようにしましょう。

(※RPGなどのゲームでこうしてしまうと、万が一すり抜けバグが起きた時に
まったく動けなくなるので、帰れなくなります・・・
移動が中心のゲームでない場合は、こういう設定はやめましょう。)



ところで、今、どれくらいできていると思いますか?

実はもう全部できてるんです。

「ループの中を書くと」とか書いてたので、
わかりにくいかもしれませんが、
これだけです。

#////////この関数は、コピーしてきてください////////////
def Array(a)
  a = splitString(a, ",")
  i = 0
  while i < getArrayLength(a)
    a[i] = toNumber(a[i])
    i = i + 1
  end
return a
end
#///////////////////////////////

s = createArray()
s[0] = Array("1,1,1,1,1")
s[1] = Array("1,0,1,2,1")
s[2] = Array("1,0,0,0,1")
s[3] = Array("1,0,1,1,1")
s[4] = Array("1,1,1,1,1")

x = 1; y = 1

loop = true
  while loop
  case speakWithSelect(4,"↑","→","←","↓", 
      "どちらに進みますか?")
    when 0
      xi =  0;yi = -1
    when 1
      xi =  1;yi =  0
    when 2
      xi = -1;yi =  0
    when 3
      xi =  0;yi =  1
  end

  if s[y+yi][x+xi] == 0
    speak("進みました。")
    x = x + xi;y = y + yi
  elsif s[y+yi][x+xi] == 2
    speak("ゴールです。")
    goEnding()
  else
    s[y+yi][x+xi] == 1
    speak("その方向には壁があり、進めません。")
  end
end


画像を表示しないとなると、
これで、全部なんです。

すごく単純ですよね?


ちなみに

s = createArray()
s[0] = Array("1,1,1,1,1")
s[1] = Array("1,0,1,1,0,1")
s[2] = Array("1,0,0,0,0,2,1")
s[3] = Array("1,0,1,1,0,1")
s[4] = Array("1,1,1,1,1")



設定の部分をこんな風に変えても
完全に対応でき、色々なステージを簡単に作ることができます。


暗闇迷路 - 【迷路ゲーム】

今回は、ここまでにします。
わからない部分が、少しでもあったらどんどんコメントしてください。

コメントする

コメントするには、ログインする必要があります。

コメント一覧

User icon mini 退会したユーザー(投稿日:2012/03/21 21:55, 履歴)

移動する=座標の変化

という概念を、今のうちに頭に入れておきたいものです。
Material 7186 1 mini ikosami(投稿日:2012/03/21 22:25, 履歴)
それが一番重要かもしれません。
Kako cnphiicefg6eavij mini machio(投稿日:2012/03/21 19:22, 履歴)
ikosami先生のスクリプト講座サイコーですね!

落ちこぼれ生徒ですが、必死に理解に努めましたー。
Material 7186 1 mini ikosami(投稿日:2012/03/21 20:35, 履歴)
ありがとうございます(^^)

質問があったら、どんどん書いてください。
Images 3    mini sekirin(投稿日:2012/03/21 14:03, 履歴)
分かりやすいです!
続きを楽しみに待ってます^^
Material 7186 1 mini ikosami(投稿日:2012/03/21 14:25, 履歴)
ありがとうございます(^^)
Material 71926 1 mini なとおとき(投稿日:2012/03/21 00:56, 履歴)
てゆーかdef勉強してからまた来ますわ(^^;ゞ
Material 7186 1 mini ikosami(投稿日:2012/03/21 01:00, 履歴)
そこは全然重要でないのですが・・・

defの解説は、ここにのってます。
http://rmake.jp/document/script_manual
Material 71926 1 mini なとおとき(投稿日:2012/03/21 01:11, 履歴)
理解できていないのがdef出ないことに気づく。
そしてあまり重要じゃないと。w
Material 7186 1 mini ikosami(投稿日:2012/03/21 13:39, 履歴)
どこがわからないのかがわからないと、厳しいですね・・・
Material 71926 1 mini なとおとき(投稿日:2012/03/21 00:48, 履歴)
こんなんでいいんだ!
Arrayってどうやって使うんですか?(∀)
Material 7186 1 mini ikosami(投稿日:2012/03/21 00:54, 履歴)
それについては、Wikiのほうを見てください。
http://page.rmake.jp/wikis/145