※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

RPG

RPGの開発とかいろいろ(現在ここから移動中)


基礎技術関連


キー入力、カーソル関連


文字列表示関連



変数について


RPGだけではないですが、ゲームを制作するならあらかじめ企画段階で変数名のつけ方に関するルールのような物を決めておくべきです。

C言語などのあらかじめ変数を定義しなければいけない言語ならともかく、HSPの場合はいきなり変数を使用できてしまうので、あらかじめ「これは変数だ」と分かるようにしておいたほうがいいと思われます。

ちなみにAHDでは、商人物語さんと同じような感じの変数名で統一しています。
例えばアイテムなら「DT_item(アイテムID,インデックス)」、アイテム名は「DT_item_name(アイテムID)」など。
ほかにセーブデータなら「DT_save(インデックス)」などを使うのもいいかもしれません。

HSPでは構造体が使えない分、このように工夫すると見やすいし後々の管理もしやすいと思います。
モジュール変数なるものも存在しますが、分からなければこちらのほうがいいでしょう。

キー入力の状態を詳しく検知するためのテクニック


ゲームのコマンド入力などで「ボタン(キー)が押された瞬間」や「ボタン(キー)が離された瞬間」を検知する簡単な方法です。
「getkey命令」を普通に使っても「そのときに押されているかそうでないか」しか取得できないのでその応用ということで。

キー入力はメインループ内で最初に行っていけばいいと思いますが、上記のような場合どうすればいいのか?
今回は「getkey命令」を使ってやってみます。

まず、1つのキー入力につき2つの変数を用意します。配列を使うと便利かもしれません。
それぞれを「現在のキー入力の状態を保存する変数」、「1ループ前(直前)のキー入力の状態を保存する変数」とします。
あらかじめ両方の変数の内容を0(「getkey命令」でいう押されていない状態)にしておきます。

メインループ内の最初で「getkey命令」を使います。この時に「現在のキー入力の状態を保存する変数」を使います。
そしてゲームの処理が終わったあと、ループの最後のところでに「現在のキー入力の状態を保存する変数」の内容を
「1ループ前(直前)のキー入力の状態を保存する変数」に移します。そのあとにメインループ内の最初に戻ると...

メインループ内でゲームの処理をするときに両方の変数にそれぞれ「現在と1ループ前のキー入力の状態」が入っています。
するとどういったことが分かるのか、表で説明します。
現在のキー入力の状態 1ループ前のキー入力の状態 キーの状態
0(押されていない) 0(押されていない) 離されたまま
1(押されている) 0(押されていない) 押された瞬間
1(押されている) 1(押されている) 押されたまま
0(押されていない) 1(押されている) 離された瞬間


「getkey命令」では検知できない「ボタン(キー)が押された瞬間」や「ボタン(キー)が離された瞬間」を検知することができます。
ちょっと説明が分かりづらいかもしれませんが、これで「ボタン(キー)が押された瞬間」だけ処理を行ったり出来ると思います。


ゲーム中の選択カーソルを「ピッ、ピピピピピ...」にするテクニック


TVゲームをプレイしたことのある方なら分かると思いますが、選択カーソルを動かした時に「ピッ、ピピピピピ...」のように
最初に1度カーソルが動いたあと間をおいてから連続でカーソルが動くといった経験があると思います。

あれをHSPで実装する方法です。
あと仕様用上、メインループ内でしか実装できないかもしれません。

「getkey命令」を使って実装しますが、今回は「現在のキー入力の状態を保存する変数」、
「1ループ前(直前)のキー入力の状態を保存する変数」ともうひとつ、
「カーソルを動かすためのタイマーとなるカウンタ用の変数」(中身は0にしておく)も用意します。

もちろんこれ以外に「カーソル位置を保存しておく変数」も必要になってくると思います。
これがないとカーソルを動かせませんから注意です。

ちなみに今回は具体的な処理の流れを主に書いて行きます。

まずメインループ内に処理を書いていくのは同じです、というか基本中の基本です。
最初に、「カウンタ用の変数」の内容が0だった場合は「キー入力の状態を詳しく検知するためのテクニック」を使います。

1.「押された瞬間」だった場合はカーソルを動かすので「カウンタ用の変数」の内容を
適度な数値(10とか20とか、ループのウェイトに応じて調節する)にします。
それと同時に「カーソル位置を保存しておく変数」も一度だけ操作しておきます。
2. 「押されたまま」だった場合はカーソルを動かすので「カウンタ用の変数」の内容を
適度な数値(「押された瞬間」の時の5分の1~10分の1、ループのウェイトに応じて調節する)にします。
それと同時に「カーソル位置を保存しておく変数」も一度だけ操作しておきます。
3.上記以外なら「カウンタ用の変数」の内容は0に初期化にしておきます。

そして次の処理、「カウンタ用の変数」が0より大きい場合はその数値を1減らします。
これはメインループ内でその処理が行われるごとに1ずつ減っていくので時間が経てばいつかは0になります。

上記の処理がメインループ内で実行されると選択カーソルを動かした時に「ピッ、ピピピピピ...」と動くはずです。
もし分かりにくい場合は「カーソル位置を保存しておく変数」を操作する所で効果音を鳴らすといいと思います。

+sample1.hsp
////////////////////////////////////////////////////////////
// サンプルスクリプト1(HSP 3.x用)
// 
// ゲーム中の選択カーソルを「ピッ、ピピピピピ...」に
// するテクニック
// 
// (C)2007 AHD
 
////////////////////////////////////////////////////////////
// 変数の定義
 
; ゲーム終了フラグ
QUIT_FLAG=0
 
; カーソル位置
CS_FLAG=0
 
; 項目の最大値
CS_MAX=10
 
; タイマー用
CS_TIMER=0
 
; タイマー長いほう
CS_TIMERL=40
 
; タイマー短いほう
CS_TIMERS=4
 
; 項目リスト
dimtype LIST,vartype("str"),CS_MAX
 
repeat CS_MAX
	LIST(cnt)="[ リスト "+cnt+" ]"
loop
 
; キー入力用変数はこんな感じで区別します。
; 
; ○_key(0):「現在のキー入力の状態を保存する変数」
; ○_key(1):「1ループ前(直前)のキー入力の状態を
;             保存する変数」
 
; ESCキー入力用
dim esc_key, 2
 
; ↑キー入力用
dim up_key, 2
 
; ↓キー入力用
dim down_key, 2
 
 
onexit gosub *quit_on
 
////////////////////////////////////////////////////////////
// ここからスクリプト
 
title "ゲーム中の選択カーソルを「ピッ、ピピピピピ...」にするテクニック"
 
*mainloop
	redraw 0
 
	; キー入力取得
	getkey esc_key(0), 27
	getkey up_key(0), 38
	getkey down_key(0), 40
 
	; キー入力判定
	switch (up_key(0) + (down_key(0) * 2) + (esc_key(0) * 4) )
		case 1
			; up_key
			if(CS_TIMER=0){
				if(up_key(1) = 0){
					; 押した瞬間
					CS_TIMER=CS_TIMERL
				}else{
					; 押し続けている
					CS_TIMER=CS_TIMERS
				}
 
				if(CS_FLAG = 0){
					; カーソルが一番上なのでループさせる
					CS_FLAG=CS_MAX
				}
				CS_FLAG-=1
 
			}else{
				CS_TIMER-=1
			}
		swbreak
		case 2
			; down_key
			if(CS_TIMER=0){
				if(down_key(1) = 0){
					; 押した瞬間
					CS_TIMER=CS_TIMERL
				}else{
					; 押し続けている
					CS_TIMER=CS_TIMERS
				}
 
				CS_FLAG+=1
				if(CS_FLAG = CS_MAX){
					; カーソルが一番下なのでループさせる
					CS_FLAG=0
				}
 
			}else{
				CS_TIMER-=1
			}
		swbreak
		default
			CS_TIMER=0
		swbreak
	swend
 
	; 描画処理
	color 255,255,255:boxf
	color 0,0,0
	pos 10,10
 
	repeat CS_MAX
		if(cnt = CS_FLAG){
			; 選択箇所
			mes "→ "+LIST(cnt)
		}else{
			; それ以外
			mes "   "+LIST(cnt)
		}
	loop
 
	pos 150,10
 
	mes "◆ キー入力について"
	mes ""
	mes "   ↑キー :カーソルを上へ移動"
	mes "   ↓キー :カーソルを下へ移動"
	mes "   ESCキー:終了"
	mes ""
	mes "↑キーまたは↓キーを長押しすると"
	mes "「ピッ、ピピピピピ...」といった感じになります。"
 
	; 現在のキー入力判定を1つ前に移す
	up_key(1)=up_key(0)
	down_key(1)=down_key(0)
	esc_key(1)=esc_key(0)
 
	; 終了処理
	if(esc_key(0) = 1){
		; 終了フラグ立て
		QUIT_FLAG=1
	}
 
	redraw 1
	await 16
 
	if(QUIT_FLAG = 0):goto *mainloop
 
end
 
 
*quit_on
	; 終了フラグ立て
	QUIT_FLAG=1
	return
 
 


文字列のうち、最初からn番目までを表示するテクニック


新しくサンプルスクリプトを作成したのでアップします。

+sample2.hsp
////////////////////////////////////////////////////////////
// サンプルモジュール&スクリプト2(HSP 3.x用)
// 
// 文字列のうち、最初からn番目までを表示するテクニック
// 
// (C)2007-2008 AHD
 
////////////////////////////////////////////////////////////
// モジュールの定義
 
 
 
#module

#deffunc pmes str _strings,int numcnt
	; pmes 文章を最初から指定文字数のみ表示
	; 
	; 文章を最初から指定文字数のみ表示します。
	; しかも何気に日本語SJIS対応となってます。
	; numcnt を0から順に1ずつ増やして呼び出すと、
	; 1文字ずつ表示できるはずです。(^^;)
	; 
	; 呼出し後、statには制御フラグが入ります。
	; これを利用して、再度呼び出すかそうでないかを決めます。
	; また、refstrには出力文字列が入ります。
 
	; 返り値用
	mref ret,64
	mref retstr,65
 
	; エラー回避のため別の変数に
	strings=_strings
 
	if(numcnt<0){
		; 指定文字数が0未満のときはそのまま出力、stat-1にする
 
		ret=-1
		retstr=""+strings
	}else{
		; 指定文字数が0以上のときは・・・
 
		; 文字数カウント用内部変数
		bytecnt=0
 
		; バイト数計算時に使う文字コード用内部変数
		bytecode=0x00
 
		; 出力文字列用内部変数
		outstr=""
 
		; 指定文字数の時のバイト数計算
		repeat numcnt
			; この位置(bytecnt目)の文字コードは?
			bytecode=peek(strings,bytecnt)
 
			if((bytecode>=0x81)&(bytecode<=0x9F))|((bytecode>=0xE0)&(bytecode<=0xEF)){
				; 全角文字なら2バイト分
				bytecnt+=2
			}else{
				; 半角文字なら1バイト分
				bytecnt+=1
			}
 
			if(bytecnt>strlen(strings)){
				bytecnt=cnt
				break
			}
		loop
 
		; 出力文字列は?
		outstr=strmid(strings,0,bytecnt)
 
		if(strlen(outstr)<strlen(strings)){
			; 出力文字列が指定文字列未満のときは出力文字列を出力、stat0にする
			; stat0なので指定文字列を全部表示していない段階です。
			; なのでnumcntを1加算して再度呼び出しましょう。
			ret=0
			retstr=""+outstr
		}else:if(strlen(outstr)=strlen(strings)){
			; 出力文字列が指定文字列未満のときは指定文字列を出力、stat0にする
			; stat1なので指定文字列を全部表示しました。
			; これ以上呼び出す必要はありません。
			ret=1
			retstr=""+strings
		}else{
			; 出力文字列が指定文字列以上のときは指定文字列を出力、stat-1にする
			ret=-1
			retstr=""+strings
		}
	}
 
	; mes命令で画面に表示する
	mes retstr
 
	return ret
 
#global

////////////////////////////////////////////////////////////
// サンプルスクリプト
 
 
 
title "文字列のうち、最初からn番目までを表示するテクニック"
 
; 表示したい文字列
strings1="文字列のうち、最初からn番目までを表示するテクニック"
strings1+="\n文章を最初から指定文字数のみ表示します。\nしかも何気に日本語SJIS対応となってます。"
strings2="サンプル:abc123あかさたな"
 
wait 100
 
repeat
	; pmes命令を使用する前に必ずpos命令で指定しておく
	; 修飾できないけれどemes命令のように使うことも出来ます・
	pos 0,0
	pmes strings1,cnt
 
	if(stat=1){
		; 全部表示したからループ脱出
		break
	}
 
	wait 10
 
loop
 
; 見やすいように1行あけただけです。
mes ""
 
wait 100
 
; キャッシュしているだけなのであまり気にしないでください。
x=ginfo(22)
y=ginfo(23)
 
repeat
	; 表示中に色をだんだん変えたりも出来るはず。
	; 例えば今回はよく見ると赤から青に変化しています。
	color 255-(255/16*cnt),0,255/16*cnt
 
	; pmes命令を使用する前に必ずpos命令で指定しておく
	; 修飾できないけれどemes命令のように使うことも出来ます・
	pos x,y
	pmes strings2,cnt
 
	if(stat=1){
		; 全部表示したからループ脱出
		break
	}
 
	wait 20
 
loop
 
wait 100
 
; 見やすいように1行あけただけです。
mes ""
 
color 0,0,0
mes "表示完了しました。"