2.カーソル移動あれこれ


自作システムを組もうと思ったらメニューにしろ戦闘にしろカーソルの処理は
避けては通れない道です。そしてよく使う割にはなかなか面倒な作業でもあります。
そういうわけでここではRPGツクール2000(2003)で表現可能なカーソル移動テクニックを
思いつく限り紹介します。
解説だけでは分かりにくい面もあるかと思いますので、サンプルを用意しました。
講座と合わせて確認してみてください。
カーソル移動サンプル集(30kb)


目次

「何を」カーソルにするか
主人公をカーソルにする
イベントをカーソルにする
ピクチャーをカーソルにする
文章表示をカーソルにする

「どうやって」カーソルを移動するか
主人公に移動させる
「キー入力の処理」を使う
末端の処理

一歩進んだテクニック
不規則に並んだ項目間の移動
存在しないものを選ばない
「滑らかカーソル移動」の原理

(投稿テクニック)デフォルトメニュー風のカーソル処理


それでは、まず最初の問題は何をカーソルにするかです。
結論から言えばプレイヤーの意思で動かせるものなら何でもカーソルの代わりにできます。
代表として主人公、イベント、ピクチャーがそれに当たります。
とは言えそれぞれ扱い方は違いますから特徴によってそれぞれメリットとデメリットがあります。
どんなことにも共通のカーソル移動システムを作ることは難しいですのでその場その場で
一番都合の良いものを使い分ける必要があります。



★主人公をカーソルにする
これが一番簡単な方法だと思います。
キャラセットにカーソルのグラフィックを作って主人公に指定。
あとは主人公の行動範囲に「決定キーが押された時」で始まるイベントを
敷き詰めておけば、十字キーと決定キーだけで簡単に項目選択ができるようになります。

ただし主人公はキャラ単位でしか移動できませんし、カーソルの大きさも最大で24×32までと
制限が付いています。さらにこの方法ではたくさんのイベントを使用しますので
移動中にその場で呼び出して使うのには無理があります。
ですから専用のマップを作って、そこへ移動させる必要があります。



★イベントをカーソルにする
主人公の動きを封じて、代わりにイベントを移動させます。
この方法なら1つのイベントだけでなく複数のイベントを連結させることで大きなカーソルを
作ることもできます。さらに「イベントの位置を設定」が使えますので
選択項目が不規則に並んでいても対応できます。

しかし主人公カーソルよりもやや手間が掛かります。変数も扱えた方がいいです。
そしてやはりその場に呼び出すのは難しいので専用のマップへ移動させることになります。



★ピクチャーをカーソルにする
ピクチャーなら大きさや色の変更、ドット単位の移動が自由自在です。
さらにピクチャーメニューの上にピクチャーカーソルを表示させることもできるので
ドラクエのようにマップ上に直接メニューを出す場合はピクチャーにするのが一番です。

ただしドット単位で動かせるのは良いのですが、位置を確認する作業がかなり面倒です。



★文章表示をカーソルにする
文章は1つのウィンドウに4行まで表示でき、そのウィンドウも上・中・下三段階に表示できます。
ですから文章表示を使って画面上で指し示すことのできる位置は結構広いです。
これはなんとか利用できないものでしょうか。
試しに制御文字の瞬間表示と強制終了を使って断続的に文章を表示して
その間にキー入力を噛ませてみます。
↓こんな感じ
 ◆繰り返し処理
  ◆キー入力の処理:[キー受付]
  ◆文章の表示:\>⇒\^
  ◆条件分岐:変数[キー受付]が…
   …
 :以上繰り返し

結論:…はっきり言って利用価値は無いと思います。
強いて利点を挙げるならカーソル素材を用意しなくてもいいってことくらいでしょうか。
こんなこともできるんだくらいにでも。




というわけで私がパッと思いつくのはこの3パターン(+オマケ)くらいでしょうか。
それぞれのメリットとデメリットを表にするとこんなところです。

容易さ表現の豊富さ汎用性
主人公××
イベント
ピクチャー×
テキスト××




目次へ


次に問題なのはどのように動かすかです。
主人公をカーソルにした場合はそのまま主人公を動かせばいいわけですが
後の2つは主人公に動いてもらっては困ります。
そこで主人公の動きを封じた上で何らかの方法でカーソルを移動させることになります。
これより下はイベントカーソルとピクチャーカーソルについて動かし方をみていきます。



★主人公に移動させる
主人公を透明にし、主人公の周囲四方に透明で移動不可のイベントを
開始条件「主人公から触れたとき」で設置する方法です。(サンプルではあえて見えるようにしました)
イベントカーソルなら触れたイベントに応じて「キャラクターの動作指定」で動かすか、
変数で縦と横の座標を指定して「イベント位置を設定」によって動かします。
それから、決定キーで項目の決定をするためにはそれぞれのイベントの最初に条件分岐の
「決定キーが押された時」で処理を分ける必要があります。
例として主人公の上に設置したイベントなら

(透明グラフィック、主人公から触れたとき)
 ◆条件分岐:決定キーでこのイベントを開始した
   〜項目決定の処理〜
  ◆イベント処理の中断
 :分岐終了
 ◆キャラクターの動作指定:カーソル,上へ移動
と、いった具合です。


「イベント位置を設定」を使う場合は最初にカーソルの初期位置を
X軸とY軸に分けて指定する必要があります。
ちなみに画面上の座標はエディターの一番下(ステータスバー)のところに表示される
(00x,00y)という数字の部分で確認できます。
カーソルを最初に置きたい場所をクリックして、出てきた(00x,00y)の数字を2つの変数に代入します。

 ◆変数の操作:[0005:カーソルのX座標]代入,00x
 ◆変数の操作:[0006:カーソルのY座標]代入,00y

あとは主人公の上下左右にある各イベントに「イベント位置を設定」を加えます。
例として主人公の上に設置したイベントなら

(透明グラフィック、主人公から触れたとき)
 ◆条件分岐:決定キーでこのイベントを開始した
   〜項目決定の処理〜
  ◆イベント処理の中断
 :分岐終了
 ◆変数の操作:[0006:カーソルのY座標]減算,1
 ◆イベント位置を設定:カーソル,(V[0005],V[0006])
と、いった具合です。


それからピクチャーカーソルなら変数に画面x,画面yを指定して動かします。
画面x,画面yは座標とは別物で、ゲームプレイ中に表示されている画面のドット単位の位置のことです。
主人公がどこにいようとも画面の一番左上が(0,0)で、一番右下が(320,240)になります。
この画面の位置は自分で計算したり実際に表示させてみて調節するしかありません。



★「キー入力の処理」を使う。
開始条件を「自動的に始まる」などにして主人公の動きを完全に封じた状態で
「キー入力の処理」を使います。
慣れないうちは「キーが押されるまで待つ」にもチェックを入れておきましょう。
入力したキーと取得される数字の関係は以下の通りです。
1:下,2:左,3:右,4:上,5:決定,6:キャンセル

これを踏まえたうえでイベントを組んでみましょう。

1ページ目
(自動的に始まる)
 ◆キー入力の処理:[0001:キー受付]
 ◆条件分岐:変数[0001:キー受付]が1
  ◆変数の操作:[0006:カーソルのY座標]減算,1
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が2
  ◆変数の操作:[0005:カーソルのX座標]減算,1
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が3
  ◆変数の操作:[0005:カーソルのX座標]加算,1
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が4
  ◆変数の操作:[0006:カーソルのY座標]加算,1
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が5
  ◆スイッチ[0001]をONにする
  ◆
 :分岐終了
 ◆イベント位置を設定:カーソル,(V[0005],V[0006])
 ◆

2ページ目
(スイッチ[0001]がON)
内容無し

そしてスイッチ[0001]がONの時に項目決定の処理をするわけです。


★末端の処理
これで確かにカーソルは動くようになりました。
しかしそのままではボタンを押し続ける限り画面外の彼方にまで移動してしまいます。
カーソルが項目の端まで来たらそれ以上移動しないようにしなければいけません。

項目の表示位置がはっきりと決まっているならカーソルの座標で判断します。
例えば項目が3×3に並んでいて左上が(10,10)で右上が(12,12)という配置なら
上記のイベントを以下のように書き換えます。

 ◆キー入力の処理:[0001:キー受付]
 ◆条件分岐:変数[0001:キー受付]が1
  ◆条件分岐:[0006:カーソルのY座標]が10より大きい
   ◆変数の操作:[0006:カーソルのY座標]減算,1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が2
  ◆条件分岐:[0005:カーソルのX座標]が10より大きい
   ◆変数の操作:[0005:カーソルのX座標]減算,1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が3
  ◆条件分岐:[0005:カーソルのX座標]が12より小さい
   ◆変数の操作:[0005:カーソルのX座標]加算,1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆条件分岐:変数[0001:キー受付]が4
  ◆条件分岐:[0006:カーソルのY座標]が12より小さい
   ◆変数の操作:[0006:カーソルのY座標]加算,1
   ◆
  :分岐終了
  ◆
 :分岐終了

ピクチャーカーソルなら画面X,Yで条件分岐をします。
もちろんイベントカーソルでも画面位置を変数に代入して利用することができます。

さらにカーソルが一番下にあるときに下キーを押したら一番上に移動するようにしたいなら
それ以外の場合で分岐して一番上の座標を直接代入することで実現できます。

 ◆条件分岐:変数[0001:キー受付]が1
  ◆条件分岐:[0006:カーソルのY座標]が10より大きい
   ◆変数の操作:[0006:カーソルのY座標]減算,1
   ◆
  :それ以外の場合
   ◆変数の操作:[0006:カーソルのY座標]代入,10
   ◆
  :分岐終了
  ◆
 :分岐終了




目次へ


カーソルを移動させる方法の解説はここまでです。以下は一歩進めて技術的な話になります。



★不規則に並んだ項目間の移動
これまでに解説してきた方法では長方形に規則正しく並んだ項目の選択しかできません。
ところが地図を開いて移動先を選択させるような場面では、町や洞窟を規則正しく
配置しているのでは不自然です。
この場合はキーを押した時にカーソルを一定数動かすやり方ではなく
選択可能な項目に直接移動させるようにしましょう。

やり方としては項目がある地点すべてにイベントを設置して、そのイベントの座標、または
画面位置を変数に代入します。
イベントカーソルなら座標X,Yを代入して、その場所にカーソルの位置を設定します。
ピクチャーカーソルなら画面X,Yを代入します。

と、これだけならいいのですが、この方法では選択した位置によって移動できる方向が
違いますので処理を個別に分けなければならずやや面倒です。
それを避けたいならキーによって移動できる順番を予め決めておくという方法もあります。
そのためには各項目にナンバーを付けて、座標とは別の「現在の項目数」なる変数で
カーソルの位置を管理します。
そして例えば「上」キーを押すたびにこの変数を「1」→「2」→「3」→「1」と移るように
指定して、その変数が示す位置にカーソルを移動させれば項目ごとに考える必要がなくなります。
選択項目を決定する時も、この変数の値で条件分岐すると楽になります。



★存在しないものを選ばない
戦闘で戦う敵を選ぶ時にカーソルが何も無い空間を指すのはやや間抜けです。
一度倒した敵が画面上からいなくなったら、その場所を選択できないようにしなくてはいけません。
そのためには存在しているかどうかをスイッチによってチェックします。

処理が複雑になりますので詳しくはサンプルを開いていただくとしまして、
ここでは概要だけお話します。
仮に敵が3匹いたなら「1匹目が存在する」、「2匹目が存在する」、「3匹目が存在する」ことを
表すスイッチをそれぞれONにします。
仮に2匹目の敵を倒したら「2匹目が存在する」スイッチをOFFにします。
これで項目の存在が確認できます。

最大で1〜3の選択項目があるとしまして、
必ず存在する項目を選択するには以下のようにします。

 ◆条件分岐:スイッチ[0001:1個目存在]が0N
  ◆変数の操作:[0002:選択項目]代入,1
  ◆
 :それ以外の場合
  ◆条件分岐:スイッチ[0002:2個目存在]が0N
   ◆変数の操作:[0002:選択項目]代入,2
   ◆
  :それ以外の場合
   ◆条件分岐:スイッチ[0003:3個目存在]が0N
    ◆変数の操作:[0002:選択項目]代入,3
    ◆
   :それ以外の場合
    ◆イベント処理の中断
    ◆

そして選んだ項目の場所にカーソルを表示するには条件分岐で
項目の位置情報とイベントの位置を関連付けます。

 ◆条件分岐:変数[0002:選択項目]が1
  ◆イベント位置を設定:カーソル,(1個目の座標)
 :分岐終了
 ◆条件分岐:変数[0002:選択項目]が2
  ◆イベント位置を設定:カーソル,(2個目の座標)
 :分岐終了
 ◆条件分岐:変数[0002:選択項目]が3
  ◆イベント位置を設定:カーソル,(3個目の座標)
 :分岐終了


次の項目にカーソルを移動させるには項目の数を1個づつ移動させながら
存在する項目を探すようにします。

 ◆ラベルの設定:1番
 ◆条件分岐:変数[0002:選択項目]が1
  ◆条件分岐:スイッチ[0001:1個目存在]が0N
   ◆イベント位置を設定:カーソル,(1個目の座標)
   ◆
  :それ以外の場合
   ◆変数の操作:[0002:選択項目]加算,1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆条件分岐:変数[0002:選択項目]が2
  ◆条件分岐:スイッチ[0002:2個目存在]が0N
   ◆イベント位置を設定:カーソル,(2個目の座標)
   ◆
  :それ以外の場合
   ◆変数の操作:[0002:選択項目]加算,1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆条件分岐:変数[0002:選択項目]が3
  ◆条件分岐:スイッチ[0003:3個目存在]が0N
   ◆イベント位置を設定:カーソル,(3個目の座標)
   ◆
  :それ以外の場合
   ◆変数の操作:[0002:選択項目]代入,1
   ◆指定ラベルへ飛ぶ:1番
   ◆
  :分岐終了
  ◆
 :分岐終了

この辺りはサンプルのやり方とは異なりますが大体の感覚はつかめるかと思います。
あとは決定キーを押した時に項目ごとの処理をするだけです。



★「滑らかカーソル移動」の原理
せっかくですので「作品・サンプル」コーナーにおいてある
「滑らかカーソル移動」について解説します。
このシステムではキーを一度だけ押すと1マス移動し、キーを押し続けると高速で
移動することが特徴です。

まずは項目間をゆっくりと移動させる方法から解説します。
このサンプルの項目配置の場合、縦方向には16ピクセル移動させることで
1項目移すことができます。ですからこの16ピクセルを細かく何回かに
分けて移動させることで途中の移動アニメが表現できるわけです。

分割移動の方法はこうです。
 ◆繰り返し処理
  ◆変数の操作:[0008:ピクチャーの画面Y]加算2
  ◆変数の操作:[0009:移動量]加算2
  ◆ピクチャーの移動:20,(V[0007],V[0008]),0.0秒(W)
  ◆条件分岐:変数[0009:移動量]が16
   ◆繰り返し処理の中断
   ◆
  :分岐終了
  ◆
 :以上繰り返し

ピクチャーを動かしたのと同じ数値を変数[移動量]に加算して、
この数値が16になった時点でピクチャーが16ピクセル移動したと判断して処理を中断しています。


次に、キーを押し続けてカーソルを加速させる方法ですが、
これは変数と「ウエイト」を使い、一種のタイマーに見立てて押し時間を計る方法を使っています。

 ◆繰り返し処理
  ◆キー入力の処理:[0001:キー受付](キー入力を待たない)
  ◆条件分岐:変数[0001:キー受付]が0
   ◆繰り返し処理の中断
   ◆
  :分岐終了
  ◆ウエイト:0.0秒
  ◆変数の操作:[0010:タイマー]加算1
  ◆条件分岐:変数[0010:タイマー]が12
   ◆スイッチの操作:[0005:カーソル加速]をON
   ◆繰り返し処理の中断
   ◆
  :分岐終了
 :以上繰り返し

「ウエイト0.0秒」は正確には1/60秒ウエイトの意味ですので
「タイマー」変数が12になったということは0.2秒経過したことを示します。
そしてスイッチ[カーソル加速]がONの時にカーソル移動を2倍速にしたいなら
先の分割移動の部分を、

  ◆条件分岐:スイッチ[0005:カーソル加速]がON
   ◆変数の操作:[0008:ピクチャーの画面Y]加算4
   ◆変数の操作:[0009:移動量]加算4
   ◆
  :それ以外のとき
   ◆変数の操作:[0008:ピクチャーの画面Y]加算2
   ◆変数の操作:[0009:移動量]加算2
   ◆
  :分岐終了
のように書き換えます。

あとは変数[キー受付]に別の数値が入ったときにスイッチ[カーソル加速]を
OFFにすれば「滑らかカーソル移動」システムの完成です。





…というわけで、最初に考えていたより随分長くなってしまいましたが
以上が、私が思いつく限り全てのカーソル移動テクニックです。
これだけできればカーソル移動については困ることはないかと思います。
まあ、もっと効率のいいやり方もあるとは思いますがそれはみなさんで研究してみてください。




目次へ


★デフォルトメニュー風のカーソル処理
このテクニックはトックさんからの投稿です。トックさん、ありがとうございました。
キーを一度だけ押すと1マス移動し、キーを押し続けると高速で移動する、
と言えば「滑らかカーソル移動」と同じですが、こちらはよりデフォルトメニューの
カーソルの動きに忠実です。

以下はトックさんの投稿からの引用です。

>コモンイベント「キー高速移動」 開始条件:呼び出された時のみ
>◆繰り返し処理
> ◆キー入力の処理:[0004:キー押し判定]
> ◆条件分岐:変数[0004:キー押し判定]が0
>  ◆変数の操作:[0005:加算変数]代入0
>  ◆繰り返し処理の中断
>  ◆
> :分岐終了
> ◆ウェイト0.0秒
> ◆キー入力の処理:[0004:キー押し判定]
> ◆条件分岐:変数[0004:キー押し判定]が0
>  ◆変数の操作:[0005:加算変数]代入0
>  ◆繰り返し処理の中断
>  ◆
> :分岐終了
> ◆条件分岐:変数[0005:加算変数]が30より小さい
>  ◆変数の操作:[0005:加算変数]加算1
>  ◆
> :それ以外の場合
>  ◆条件分岐:変数[0005:加算変数]が30以上
>   ◆繰り返し処理の中断
>   ◆
>  :分岐終了
>  ◆
> :分岐終了
> ◆
>:以上繰り返し
>◆
>
>マップイベント(カーソル移動)
>◆ラベルの設定1
>◆キー入力の処理:[0001:キー入力]
>◆条件分岐:変数[0001:キー入力]が1
> ◆変数の操作:[0003:カーソル位置縦]加算16
> ◆ウェイト0.0秒
> ◆ウェイト0.0秒
> ◆ピクチャーの移動[V0002 V0003]0.0秒 (W)
> ◆効果音の演奏(カーソル1)
> ◆コモンイベント「キー高速移動」の呼び出し
> ◆指定ラベルへ飛ぶ1
>便宜上、カーソル末端の処理等は省かせて頂きました。

言うまでもなく下方向のみの処理部分です。
マップイベントがメインで、コモンイベントがサブルーチンとして使われています。
まずマップイベント(カーソル移動)でキー入力があるとカーソルを一つ移動し、
「キー高速移動」を呼び出します。そこで1/2秒間キーが離されなければ
変数[0005:加算変数]の値が30となり繰り返しを抜けます。
そしてそのままキーが離されなければ変数[0005:加算変数]の値が30のままで
素通りするためにカーソルが高速で動くわけです。
これを元にサンプルにはデフォルトメニューと照らした処理を収録しました。

さて、特筆すべきは時間コントロールです。ウエイトをうまく使って
デフォルトメニューとほぼ同等の移動時間と待ち時間を実現しています。
「キー高速移動」でキー判定を2回行っていることを疑問に思うかもしれません。
(というか私は疑問に思いました)
中間の◆ウェイト0.0秒が曲者で、上の判定は長押し中にきっちり1/2秒を
計るためで、下の判定は高速移動中にカーソルが末端に来たとき、
キーを離した瞬間に変数[0005:加算変数]がリセットされるようにするためです。
ちょっとした違いですのでこだわらなければ上の一個は外しても問題ありません。

ただ1つ気になったのはこのままだと例えば下を押したままの状態から
他のキーに持ち返ると高速移動が継承されることです。
操作性の面ではこれでも問題ないとは思いますが、気になる人はキー入力の数値を
他の変数に記録しておいて食い違いが合った時に処理を中断する部分を
追加することで解決します。



基礎講座
第一回:RPGツクールでハローワールド(04' 4/10)
第二回:トラブル対処法(04' 4/17)
第三回:オープニングを作ろう(04' 4/24)

自作システム講座
第一回:マップイベントとコモンイベント(04' 1/10)
第二回:カーソル移動あれこれ(04' 1/10)
第三回:RPG式自作戦闘の下準備(スイッチ・変数の管理)(03' 6/15)
第四回:RPG式自作戦闘(行動順の決め方)(03' 6/15)
第五回:変数の値を画面上に表現(03' 7/6)
第六回:アイテムメニューを作る(04' 1/10)
講座一覧へ戻る
トップへ戻る



公開日時:03' 3/17 23:00
更新日時:04' 1/10 10:00
管理人:すっぴぃ ◆ADGYPSYxII