HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2009
0325
centerノベル風のメッセージ表示について30未解決


center

リンク

2009/3/25(Wed) 21:12:18|NO.24115

「ノベル風」のメッセージ(一文字ずつ表示されたり影があったり)表示をしたいのですが、
他の処理とも並列して行いたいので、ループ内に入れなければなりません。
また、レイヤー(ここでは画面バッファ)に画面を保存し、メインループで
画面のコピーをし、他のレイヤーと合成する(挙げているスクリプトにはありませんが)のですが、
どのようにすればいいでしょうか?

以下に私が作成したスクリプトを挙げますが、
見て分る通り、改行は無視されますし、半角文字はそういう処理をしてないので、文字化けしますし、
何故か文字レイヤーの背景が一部入り込んでいます。。
汚いスクリプトですが、こんな感じです。


buffer 1 color 255:boxf gsel 0 text="あいうえお\nかきくけこ\nさしすせそ\nたちつてと\nAあいうえお" color 230,230,230:boxf repeat flag++:if flag=10{ flag=0 moji = strmid(text,(cnt/10)*2,2) gsel 1 font "MS ゴシック",23 color 255,255,255:pos (cnt*2)+2,12:mes moji color 0,0,0:pos cnt*2,10:mes moji gsel 0 color 255 gmode 4,,,256 gcopy 1,0,0,640,40 } wait 1 loop

よろしくおねがいします。



この記事に返信する


check

リンク

2009/3/25(Wed) 21:25:37|NO.24117

コードが129〜159か、224〜252の範囲にある場合は、
次の1バイトと合わせて1文字の全角コードとなる。
(HSP3文字列のひみつ(中級者向け) (hsp3str.htm) より)



center

リンク

2009/3/25(Wed) 21:29:21|NO.24118

>checkさん
回答ありがとうございます。
「A」のみなら文字化けして「AA」ならひとつの全角文字として扱われると言う事でしょうか?
それは存じてますが、根本的解決にならないかと思います。。



check

リンク

2009/3/25(Wed) 21:33:32|NO.24121

だから、描画する文字を取得するときに、
1バイト文字だったら1文字、2バイト文字だったら2文字取得すれば
文字化けしない



center

リンク

2009/3/25(Wed) 21:39:16|NO.24122

>checkさん
回答ありがとうございます。
そういうことですか。失礼しました。
具体的にはどういう風に判定すればよいでしょうか?
またcntを使って位置を設定してるので、位置がだんだんずれてくると思うのですが、
対策などどのようにしたらよいでしょうか?



check

リンク

2009/3/25(Wed) 21:40:25|NO.24123

>具体的にはどういう風に判定すればよいでしょうか?
だから、コードが129〜159か、224〜252の範囲にある場合は、
次の1バイトと合わせて1文字の全角コードとなる。
peekとifを使って判定



ななし

リンク

2009/3/25(Wed) 21:42:05|NO.24124

text命令は駄目なの?



center

リンク

2009/3/25(Wed) 22:30:50|NO.24130

>text命令は駄目なの?
他の処理と並列して行う為、それは出来ない訳です。。



GENKI

リンク

2009/3/25(Wed) 23:31:29|NO.24142

今回のような文字化けは2バイト文字を途中でぶった切って表示しようとしてしまうため起こります。
回避するには2バイト文字をぶった切らないように取り扱う必要があります。
2バイト文字についてはこちらをご覧ください。判定モジュールもあります。
HSP開発wiki - String/改行
http://hspdev-wiki.net/?cmd=read&page=String%2F%B2%FE%B9%D4#o681c775


> 見て分る通り、改行は無視されますし、

改行を見つけたら、改行後の位置から表示し始めるようにpos命令のパラメータを変更してください。


> またcntを使って位置を設定してるので、位置がだんだんずれてくると思うのですが、

フォントには大きく分けて2種類あります。
等幅フォント(例:MS ゴシック)とプロポーショナルフォント(例:MS Pゴシック)です。

等幅フォントなら、1文字のサイズは固定です。
 全角1文字:高さと幅はfont命令のp1ドット。
 半角1文字:高さはfont命令のp1ドット。幅は高さの半分。

プロポーショナルフォントなら、1文字のサイズは文字によって違いますので別途取得する必要があります。
出力文字のサイズを取得するにはginfo_mesx,ginfo_mesyを使います。
また別の方法として、mesで出力前に取得する方法もあります。
http://hspdev-wiki.net/?cmd=read&page=String%2F%B6%EB%B7%C1#g095da3b


ちなみに蛇足ですが、これらを上手く使えばこういうことも可能です。
http://homepage3.nifty.com/ghpk/dl/dl16.htm



>>NO.24115
ループ内にfont命令必要ないですよ。あれはウィンドウごとに1回設定すればいいものです。



center

リンク

2009/3/25(Wed) 23:31:38|NO.24143

>checkさん
すみません。ありがとうございます。
ひとまずその問題は大丈夫だと思います。



center

リンク

2009/3/25(Wed) 23:41:44|NO.24145

>GENKIさん
回答ありがとうございます。
 >改行を見つけたら、改行後の位置から表示し始めるようにpos命令のパラメータを変更してください。
やはり、その方法しかないでしょうか・・・?

>フォントには大きく分けて2種類あります。...
それは知りませんでした! なるほど。。

>ループ内にfont命令必要ないですよ。
おっと・・・間違ってましたね。。
確か、これが指定される度にフォントが用意されるのですよね。。(汗)

もっと合理的な方法は無いのでしょうか?

あと、メッセージレイヤーの背景色(コピーされない設定)がコピー先にもコピーされている問題は、
どのようにしたら解決できるでしょうか?

複数の質問ですみませんが、よろしくお願いします。



GENKI

リンク

2009/3/26(Thu) 01:26:40|NO.24147

> もっと合理的な方法は無いのでしょうか?

何を持って合理的とするのか…。
モジュール化してしまえば、実際に使用するときのスクリプトはすっきりすると思います。

少しひねってこういうカラオケ的な表示もありかと。

screen 1 font msgothic,32 mes {"あいうえお かきくけこ"} gsel 0,1 sx(0)=0,0 *main redraw 1 : await 16 : redraw 0 : color 0,0, 255 : boxf : color : pos 0,0 sx(0)+=3 : sx(0) = limit(sx(0),0,32*5) gcopy 1, 0,0, sx,32 if sx(0)>=32*5 { sx(1)+=3 : sx(1) = limit(sx(1),0,32*5) pos 0,32 gcopy 1, 0,32, sx(1),32 } goto *main
最近のゲームだと1文字ずつ表示するタイプとは別に、このタイプの表示も見かけます。
(個人的には、1文字ずつよりこのタイプの方が好き。)


> あと、メッセージレイヤーの背景色(コピーされない設定)がコピー先にもコピーされている問題は、
> どのようにしたら解決できるでしょうか?

文字にアンチエイリアスがかかっているため背景と文字との中間色が作られ、コピーされています。
font命令のマニュアルには「(WindowsXPでは、常にアンチエイリアスが有効になります。)」とあるため
これが原因と考えられます。私にはこの回避方法は分かりません。
とりあえず出来うる対処法としては、背景色を輪郭が残っても目立たないような色にすることです。
今回の場合、文字が黒と白なので、背景色を赤ではなく白、または黒、その中間の灰色、コピー先
ウィンドウの背景色、このあたりにすれば目立たなくなると思います。

ちゃんとした解決方法は他の方よろしくお願いします。



center

リンク

2009/3/26(Thu) 01:57:42|NO.24148

>GENKIさん
回答ありがとうございます。

>何を持って合理的とするのか…。
説明不足でした…「他に方法は無いのか?」と言う事です。

>モジュール化してしまえば、実際に使用するときのスクリプトはすっきりすると思います。
モジュール化については見当していますが、実際やった事が無いのでよく分りません。
教えていただけますでしょうか?(本当、初心者ですみません。。)

>文字にアンチエイリアスがかかっているため背景と文字との中間色が作られ、コピーされています。
なるほど…確かに類似色を使えば誤魔化す事はできますね。
ただ、やっぱりすっきりしませんね。。

誰かこの問題の対処法を知っている方、お願いしますっ!



check

リンク

2009/3/26(Thu) 02:06:49|NO.24149

モジュール化についてはHSPマニュアルの
モジュール機能ガイド(中上級者向け) (module.htm) を読め

メッセージレイヤーの問題については、そのまま文字を描いてはいけないのか?



center

リンク

2009/3/26(Thu) 02:14:11|NO.24150

>checkさん
回答ありがとうございます。

>メッセージレイヤーの問題については、そのまま文字を描いてはいけないのか?
はい。他にレイヤーが存在しており、常時書き換えられるので、
一文字しか表示されなくなります。
また、すっきりさせる為でもあります。

構成はこうなってます。
[メッセージレイヤー]>[メニューレイヤー]>[メッセージウィンドウレイヤー]>[キャラ絵レイヤー]>[背景レイヤー]



check

リンク

2009/3/26(Thu) 02:27:53|NO.24151

自分で表示させる文字をペイントで作れば?
一色にすればアンチエイリアスの問題も起こらないけれど、見難い。



D.K

リンク

2009/3/26(Thu) 02:39:13|NO.24152

>メッセージ表示
昔載せたような…と思ったら過去ログに行ってましたか…。
過去ログを「D.K」で検索していただければ
私のつたないサンプルとcoinさんにより改良・モジュール化されたものがヒットするかと。



center

リンク

2009/3/26(Thu) 02:40:20|NO.24153

>checkさん

>自分で表示させる文字をペイントで作れば?
流石にそれは非効率だと思います。。



center

リンク

2009/3/26(Thu) 02:48:47|NO.24154

>D.Kさん
回答ありがとうございます。

私がしたい事と非常に似てますね。。
参考にします。

(質問は継続します)

一応まとめ。。

・半角文字が文字化けする(解決)
・改行が無視される(未実装だがおそらくできそう)
→メッセージレイヤーの不具合(未解決)

複数の質問になってしまい、すみません。



SYAM

リンク

2009/3/26(Thu) 03:13:18|NO.24155

文字が黒と白だけなら、それぞれ減算合成と加算合成でなんとかなりませんか?



center

リンク

2009/3/26(Thu) 03:32:48|NO.24156

>SYAMさん

>文字が黒と白だけなら、それぞれ減算合成と加算合成でなんとかなりませんか?
それらについてあまり詳しくないので、スクリプトを載せていただけませんでしょうか?



SYAM

リンク

2009/3/26(Thu) 09:27:20|NO.24157

加算も減算も、ドットごとの色の値を足したり引いたりした色になるというものです。
あとはgmode 命令のヘルプを見たらわかると思います。

gmodeにはもうひとつピクセルアルファブレンドってものもあるので、ついでにそれも入れたサンプルを示します。


screen 1,256,24,0:cls 4 font msgothic,24,17 color 64,64,64 pos 2,2 : mes "猫いじりたいなあ" color 255,255,255 pos 0,0 : mes "猫いじりたいなあ" screen 2,512,24,0:cls 4 color 255,255,255 boxf 0,0,256,24 pos 256,0 : gcopy 1,0,0,256,24 screen 0,256,72,0: repeat 500:pos rnd(256),rnd(72) color rnd(256),rnd(256),rnd(256) mes "猫" loop ;加算合成 gmode 5,,,255 pos 0,0 : gcopy 1,0,0,256,24 ;減算合成 gmode 6,,,255 pos 0,24 : gcopy 1,0,0,256,24 ;ピクセルアルファブレンド gmode 7,,,255 pos 0,48 : gcopy 2,0,0,256,24 ;以下はgmode7のコピー元にグラデーションをかけた応用例. gsel 2 repeat 24 c=cnt*10+25 color 255,c,128 line 0,cnt,255,cnt loop gsel 0 gmode 7,,,255 pos 0,48 : gcopy 2,0,0,256,24

理解しにくいのは減算かもしれませんが・・・、
色の成分ごとの明るさを引き算します。ですから、白(255,255,255)を“引く”と、結果は黒(0,0,0)になりますね。


※実際には加算も減算も検索したらわかる話ではありますが・・・理解の足しにでもなれば幸い。



SYAM

リンク

2009/3/26(Thu) 09:29:38|NO.24158

orz

gmode 7 の1つめの例を2つめの例で上書きしてますね。。。
ヘタこいたあああ。



窓口

リンク

2009/3/26(Thu) 14:16:01|NO.24173

こんなのはどうですか?


#define cls_x : color 100,100,100 : boxf : color 0,0,0 ;メインループの活動を示すための画像を登録 screen 2,100,100,2 boxf 0,0,100,100 ;メッセージボックス用のウインドウ screen 1,640,100,2 gsel 0 randomize ;######################################### *hajime gosub *メッセージ表示 gosub *メインループ goto *hajime ;######################################### ;メインループとメインの処理 *メインループ gsel 0 repeat 100 title "メインループ中"+str(cnt) gosub *メインの処理 loop return ;メインループの処理 *メインの処理 color 255,255,255 : boxf ;画面更新 pos rnd(640),rnd(480) : gmode 0,100,100 : gcopy 2,0,0 wait 10 return ;######################################### ;メッセージ表示とメッセージ入力待ちの処理 *メッセージ表示 title "メッセージ表示中" gsel 1 ;半角文字のサイズを記憶 cls_x : mes "a" : cls_x mesx_x = ginfo_mesx : mesy_y = ginfo_mesy ;必要な変数の初期化 msg = "こんにちはHSPです\nhspです\n改行もできる。" cunt = 0 : mesx = 0 : mesy = 0 ;メッセージ表示のメインループ repeat a=peek(msg,cunt) ;文字コードを読みだす if a = 13 : cunt++ : mesy += mesy_y : mesx = 0 : continue ;"\n"の文字コードは二つあるため両方ともスキップ&改行の処理 if a = 10 : cunt++ : mesx = 0 : continue ; gsel 1 if (a >= 129 & a <= 159 | a >= 224 & a <= 252) { pos mesx,mesy : mes strmid(msg,cunt,2) cunt+=2 : mesx+=mesx_x * 2 ;全角文字の場合は半角文字の大きさ*2  }else{ pos mesx,mesy : mes strmid(msg,cunt,1) cunt++ : mesx+=mesx_x ;半角の場合はそのまま } gsel 0 : redraw 0 gosub *メインの処理 pos 0,0 : gmode 0,640,100 : gcopy 1,0,0 redraw 1 if strlen(msg)-1 <= cunt : break loop ;エンターキーの入力を待つ repeat getkey p1,13 if p1=1 : break redraw 0 gsel 1 : color clr,clr,clr : pos (640/2)-(ginfo_mesx/2),75 : mes "▽" gsel 0 : gosub *メインの処理 pos 0,0 : gmode 0,640,100 : gcopy 1,0,0 redraw 1 clr+=30 if clr>=255 : clr=0 : loop return



center

リンク

2009/3/27(Fri) 01:19:46|NO.24186

>SYAMさん
回答ありがとうございます。

なるほど。そんなことができるんですね。。
…でも、何か影の白が灰色になってると思うのですが、
白にはできないのでしょうか?

>窓口さん
回答ありがとうございます。

一先ずこのサンプルを少し弄って使わせて頂きます。



e

リンク

2009/3/27(Fri) 04:07:40|NO.24187

>…でも、何か影の白が灰色になってると思うのですが、
そうなってる理由を自分で考えようと思わないのか?



SYAM

リンク

2009/3/27(Fri) 11:27:34|NO.24192

問題は中間色を使ったアンチエイリアシングのせいで背景色が混じってしまうことですよね。それの代わりとして、中間色である灰色を文字の近くに意図的に混ぜ込んだのが影の灰色です。
影の灰色が 灰色に見えないように 自然に背景に混ざりこんでいればOKだったわけですが、前回のスクリプトでは確かにそのことがわかりにくかったかもしれません。
影が灰色っぽくても、失敗には見えませんからね。

なので、今度は失敗が失敗らしく見えるよう、本来の問題が実際に発生するサンプルを示します。


// gmode 0〜6用. buffer 1,48,48,0:cls 4 font msgothic,48,16 pos 0,0 : color 255,255,255:mes "猫" // gmode 7用. buffer 2,96,48,0:cls:color 0,0,0:boxf 48,0,96,48 font msgothic,48,16 pos 48,0 : color 255,255,255:mes "猫" // グラデーションのかかった背景. screen 0,48*8,112,0:cls 4:font msgothic,10 repeat 96:color 255-cnt,128,cnt+159:line 0,cnt,48*8,cnt:loop color 0,255,0:repeat 8:pos cnt*48+10,98:mes "mode "+cnt : loop color 255,255,255 ;gmode 4で透過する色. alpha=64,256 repeat 2 : n=cnt repeat 7 gmode cnt,,,alpha(n) pos cnt*48,48*n:gcopy 1,0,0,48,48 loop gmode 7,,,alpha(n) pos 7*48,48*n:gcopy 2,0,0,48,48 loop
gmode 0〜7の合成がどのように行われるかを示しています。上段は不透明度を64まで下げたもの、下段は不透明(gmode2などの完全な透過はする)です。
mode2だと、コピー元の背景である黒と、文字の白が混じった灰色が出てきてしまっています。
その部分が、mode5 や mode7では灰色ではなく ちゃんと薄い白として貼り付けられているのがわかるでしょうか?

※参考までに…
半透明合成について、mode5,6は加減算だけで済み、mode3,4,7では加減算と割り算を使います。割り算は加減算より重いため、処理はmode5,6のほうがずっと速いです。
しかしmode5の場合は単純な加算なので、合成先がもともと明るいと真っ白になりやすいのです。実際、サンプルでもmode7よりも強い白になってエイリアシングが目立っていますね。



center

リンク

2009/3/27(Fri) 14:35:46|NO.24201

>SYAMさん
回答ありがとうございます。おぉ。確かにきれいに白い文字がでてますね。。

ちょっとサンプルを弄って目的の結果にしたのですが、
こんな感じで良いんでしょうか?
画面コピー等についてはついこの間に手を出したばかりなので、非効率な編集をしてるかもしれませんが、
「ここをこうした方が良い」などありましたらご指摘して下さると幸いです。
	// gmode 0〜6用.
buffer 1,48,48,0:cls 4 font msgothic,48,16 pos 0,0 : color 255,255,255:mes "猫" // gmode 7用. buffer 2,96,48,0:cls:color 0,0,0:boxf 48,0,96,48 font msgothic,48,16 pos 48,0 : color 255,255,255:mes "猫" // グラデーションのかかった背景. screen 0,48*8,112,0:cls 4:font msgothic,10 repeat 96:color 255-cnt,128,cnt+159:line 0,cnt,48*8,cnt:loop alpha=64,256 ///// ここから編集 ///// ;影(白)描画 gmode 7,,,alpha(1) pos 12,12:gcopy 2,0,0,48,48 ;文字(黒)描写 gmode 6,,,alpha(1) pos 10,10:gcopy 1,0,0,48,48 ///// ここまで編集 /////



SYAM

リンク

2009/3/27(Fri) 15:14:42|NO.24203

gmode 5 はコピー先が明るいと白飛びしますが、gmode 6 は同じ理由でコピー先が暗いと黒くつぶれてやっぱりギザがめだつようになります。
それを避けるために gmode 7 を使うのであれば、白以外の文字を出すには コピー元の左半分の真っ白の部分を別の色で塗りつぶすことになります。
色自体はなんでもよく、たとえばグラデーションをかけたりとかもできるというのは 先に示したほうのサンプルからわかると思います。



Sucret

リンク

2009/3/27(Fri) 18:17:33|NO.24208

グラデーションの話をしている中突然すいません。
何かの処理をしながら文字を表示するモジュールを作ってみました。
こんな感じでどうですか?


#module #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" #deffunc mes_set str ms_message,int ms_time,int ms_shade //mes_timeで↑内容を使えるようにする mt_message=ms_message mt_time=ms_time //影の色 mt_shade=ms_shade dim mt_color,3 dim shade,3 shade.0=ginfo_r,ginfo_g,ginfo_b //カウント開始 now=timegettime() mt_before=0 //カレントポジションの取得 ms_beforeX=ginfo(22) ms_beforeY=ginfo(23) //フォントのX,Yサイズの取得 mes" " ms_X=ginfo(14) ms_Y=ginfo(15) //カレントポジションを戻す pos ms_beforeX,ms_beforeY return #deffunc mes_time //タイマーから表示する文字数を算出 mt_word=0 mt_len=(timegettime()-now)/mt_time repeat mt_len if peek(mt_message,mt_word)>=129 & peek(mt_message,mt_word)<=159:mt_word+ if peek(mt_message,mt_word)>=224 & peek(mt_message,mt_word)<=252:mt_word+ mt_word+ if mt_word>strlen(mt_message):mt_word=strlen(mt_message):break loop //カレントポジションの取得 mt_beforeX=ginfo(22) mt_beforeY=ginfo(23) //影を表示する場合の処理 if mt_shade=1 { //現在のカラーコードを記憶 mt_color.0=ginfo_r,ginfo_g,ginfo_b //影の色を選択 color shade.0,shade.1,shade.2 //影の表示 pos ms_beforeX+ms_Y/10,ms_beforeY+ms_Y/10 mes strmid(mt_message,0,mt_word) //カラーコードを戻す color mt_color.0,mt_color.1,mt_color.2 } //mes_set時のカレントポジションに文字を表示 pos ms_beforeX,ms_beforeY mes strmid(mt_message,0,mt_word) //全ての文字が表示されていれば0を返す。 if mt_word=strlen(mt_message):return 0 //カレントポジションを戻す pos mt_beforeX,mt_beforeY return 1 #global //▼▼▼サンプル▼▼▼ color:boxf font msgothic,20 color 128,128,128 //mes_set命令で表示する文字、表示速度、影の有無を設定します。 mes_set"サンプルの文字列です。\n改行に対応していて、\n[ABC]や[def]、[\\\"]などの1バイト文字にも対応しています。\n文字を表示しながら別の処理を行うことも可能ですが、\nmes_time命令を入れ忘れると文字は表示されません。\nこのサンプルでは、はじめにawait10で300ループさせた後、\nマウスポインタの位置に円が表示されます。\n300ループ中はcntの内容をtitle命令で表示しているため、\nPCのスペックによって完了まで誤差が生じます。",100,1 color 255,255,255 //試しに300ループ待ってみます。 repeat 300 title""+cnt+"ループ目" //mes_time命令でmes_setが実行されてから経過した時間分の文字を表示します。 mes_time await 10 loop title"ここからは別の処理、マウスポインタの位置に文字が表示されます。" repeat redraw 0 color:boxf //mes_time命令では現在のカラーコードが適用されるので、途中で変更すると文字色も変わります。 color 255,255,255 mes_time //別の処理。マウスポインタの位置に円が表示されるだけです。 circle mousex-5,mousey-5,mousex+5,mousey+5 redraw 1 if stat=0:break wait 1 loop mes"終了" dialog"文字が完全に表示されました。" //▼▼▼命令の解説▼▼▼ /* ・mes_set命令 mes_set "strings",p1,p2 "strings" : 表示する文字列 p1 : 1文字を表示するのにかかる時間。1000で1秒 p2 : 影の表示。1で影を表示します。 この命令が実行された瞬間から時間を計測していきます。 影の色は、この命令が実行された時のカラーコードが適用されます。 ・mes_time命令 mes_time パラメータはありません。 この命令が実行されると[mes_set]命令が実行されてから現在までの経過時間分の文字が表示されます。 全ての文字が表示し終わるとstatに0が代入され、それ以外では1が代入されます。 全ての文字が表示し終わっている時間でこの命令を実行した場合のみ、カレントポジションが変更されます。 */



Sucret

リンク

2009/3/28(Sat) 12:38:01|NO.24227

ノベルゲームということはEnterキーを押したら文字をすぐに表示できなければ
いけませんでしたね。一応それも出来るようにしておきました。
No.24208の
#global

の1行上に
#deffunc mes_end
	now=timegettime()-strlen(mt_message)*mt_time
return
を入れてください。

・mes_end命令
mes_end
mes_timeに同じくパラメータはありません。
この命令が実行されるとタイマーを変更して全文字を表示する時間まで変更します。
つまり、現在経過した時間にかかわらずmes_setで設定してあった文字を全て表示できるようにします。
時間を変更するだけなので、この命令実行後にmes_time命令を再度実行しなければ文字は表示されません。



ONION software Copyright 1997-2021(c) All rights reserved.