サンプルプログラムにて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
夏天

サンプルプログラムにて

#1

投稿記事 by 夏天 » 18年前

サンプルプログラムのサウンドノベル風文字列描画、テキストバッファ使用バージョンが
自分には難解です。
こんな初歩的なところでつまずいている自分のために
改行の他にmainで読み込んだ文字列を別の関数で表示などといった
ユーザ関数を多用した同じことができるプログラムが欲しいです。
どなたか作ってください!
お願いします!お願いします!

管理人

Re:サンプルプログラムにて

#2

投稿記事 by 管理人 » 18年前

>どなたか作ってください!

いやいや、誰かに作ってもらってたんじゃ夏天さんのスキルが上がりませんよ^^
少しずつ作ってみませんか?

まず、半角が無いテキストデータだとして考えましょう。


char txt[128]="今日からサウンドノベル風文字列表示の勉強をします";

これを時間差で表示させて見ます。

まず、時間差で表示させるには、

1、1文字格納、表示
2、2文字格納、表示
3、3文字格納、表示

これを延々と繰り返せばいいですね。
また繰り返すまでの区間は、配列に\0が見つかるまでです。

txt2というもともとの配列のほかにtxt2という描画用の配列を用意します。
txt2にtxtから必要な分だけコピーして、常にtxt2を表示するようにしてみます。

まず、
txt[0],txt[1]をtxt2[0],txt[1]にコピーし、txt2[2]に\0を格納します。
つまり
txt2[0] = txt[0];
txt2[1] = txt[1];
txt2[2]='\0';
こういうことです。
すると%sでtxt2を表示させれば「今」が表示できますね。
どうように、
txt2[0] = txt[0];
txt2[1] = txt[1];
txt2[2] = txt[2];
txt2[3] = txt[3];
txt2[4]='\0';
としてやり、同様に表示すると今度は「今日」が表示できます。
txt2[0] = txt[0];
txt2[1] = txt[1];
txt2[2] = txt[2];
txt2[3] = txt[3];
txt2[4] = txt[4];
txt2[5] = txt[5];
txt2[6]='\0';
とすると「今日は」になります。
常にtxt2を表示させれば段々1文字ずつ増えていきますね?
このコピーをコピー元の配列の中身が\0になるまでしていけば、サウンドノベル風になりますね?
つまり2要素ずつコピーしては、終端記号をいれていけばいいわけです。

ただこれを毎回2ずつ増やしていると早すぎるので、特定ターンに一回処理をするようにプログラムするとよいでしょう。

やり方つかめてきましたかね?

管理人

Re:サンプルプログラムにて

#3

投稿記事 by 管理人 » 18年前

txt[p2][p1]で管理しています。
int i,p1=0,p2=0,counter=0;
char txt2,txt[10][128]={
"今日はサウンドノベル風文字列表示法を勉強しています。",
"色々人の書いたプログラムを理解するのは難しいですが",
"わからなくとも、どんなプログラムでもいいので試行錯誤しながら自分で",
"いろんなプログラムを書いてみることで",
"自分の力となります。",
"がんばってください。",
};

if(エンターが今の瞬間押されたら){
    p2++; p1=0;//次の文章へ
}

if(counter%3==0)//3周に1回処理をする
    if( /*次の要素が\0でなければ*/ )
        p1+=2;//表示する文字を全角1つ増やす

for(i=0;i<p1;i++){
    txt2=txt[p2]//コピー
/*もし用意した配列よりp1が大きければブレイク*/
}
txt2='\0';//終端記号格納

DrawFormatString( /* txt2を表示 */  );


counter++;


 
こんな感じでどうでしょうか?
人のプログラムを読むのになれていらっしゃらないようなので、極力コードの直接記述はさけました。
/* */の部分は自分で作ってください。
無駄な部分もありますが、わかりやすさ最優先で書きました。

半角が混ざるともうちっとテクが必要です。
次はそのテクの話をします。

管理人

Re:サンプルプログラムにて

#4

投稿記事 by 管理人 » 18年前

まず、

char txt_a[3]="AB";
char txt_b[3]="あ";

において、


printf("%d\n",txt_a[0]);
printf("%d\n",txt_b[0]);

をしてみてください。何か違いに気づくはずです。
全角はsignedでは1バイト目がかならずマイナスになります。
半角はプラスになります。
以下サンプルを書いてみました。
#include<stdio.h> 

void main(){
	int i;
	char ta[11]="abcdeABCDE";
	char tb[11]="あイ言○Z";
	for(i=0;i<10;i+=2)
		printf("ta[%d]=%d\tta[%d]=%d\ttb[%d]=%d\ttb[%d]=%d\t\n",i,ta,i+1,ta[i+1],i,tb,i+1,tb[i+1]);
}

実行結果

ta[0]=97        ta[1]=98        tb[0]=-126      tb[1]=-96
ta[2]=99        ta[3]=100       tb[2]=-125      tb[3]=67
ta[4]=101       ta[5]=65        tb[4]=-116      tb[5]=-66
ta[6]=66        ta[7]=67        tb[6]=-127      tb[7]=-101
ta[8]=68        ta[9]=69        tb[8]=-126      tb[9]=121
 
 
 
tbの偶数配列要素というのは、文字の1バイト目を表しています。赤字の部分です。
つまり、全角は1バイト目がマイナスであることを利用すれば
半角か、全角かが判定できます。
ですから調べた要素がプラスなら1つ配列要素をずらせばよく、
調べた要素がマイナスなら2つ要素をずらせばいいわけですね。
わかります?

管理人

Re:サンプルプログラムにて

#5

投稿記事 by 管理人 » 18年前

文字コードはこちらにこれでもかと載っているので
http://ash.jp/code/

参考にしてください。
半角の文字コードはこちらが見やすいかな?
http://e-words.jp/p/r-ascii.html

Justy

Re:サンプルプログラムにて

#6

投稿記事 by Justy » 18年前

 一応念の為捕捉を。

 char型は singedなのか unsignedのどちらかになりますが、どちらになると決められないので
負になるかどうかのチェックは必ず signedにキャストしてから行って下さい。

 次にシフト JISにおける2バイト文字の判定は 負であるかだけのテストだけでは
半角カタカナを誤認するので不十分です。
 半角カタカナを外して判定する必要があります。

管理人

Re:サンプルプログラムにて

#7

投稿記事 by 管理人 » 18年前

そういえば昔、文字コードがどうなっているのかかたっぱしから出力してみたことがあり、
半角カタカナも負であることを知りました。

半角カタカナを使うとバグがおきるとよくいわれるのはこのためなんですかね?
半角カタカナを想定したエラー処理をしていないシステムがあるということでしょうか。

Justy

Re:サンプルプログラムにて

#8

投稿記事 by Justy » 18年前

半角カタカナを使うとバグがおきるとよくいわれるのはこのためなんですかね
 まぁそうですね。
 昔はデータ量を減らす為に1バイトで表現できるカタカナということで、重宝されたのですが
今では過去との互換の為だけに存在する、本来は不要な文字です。

 インターネットとかだと使われる文字コードは非常に多いので
半角カタカナを使用されると文字コードの判定が難しくなって文字化け発生率が高くなりますし、
昔のメールでは 7bitしか扱わないので即文字化けでした。

 とはいえ、最近は UnicodeとかMIMEとか ESMTPとかで回避できるので、大分半角カタカナの
トラブルも減りましたよね。

管理人

Re:サンプルプログラムにて

#9

投稿記事 by 管理人 » 18年前

不要な文字ですかぁ、と言う事は将来なくなる可能性も?
でも結構顔文字に使ったり、コメントとか突っ込みに半角カタカナって結構重宝しますよねw
昔のメールは7bitですかぁ、、残りの1bitは何かのフラグだったんですか?

Justy

Re:サンプルプログラムにて

#10

投稿記事 by Justy » 18年前

と言う事は将来なくなる可能性も
 もうここまで来てしまうと、その可能性は大幅な改訂でもない限りいですね。
 Unicodeにもちゃっかり入ってますし。


残りの1bitは何かのフラグだったんですか?
 いえ、もともとメールのプロトコル(SMTP)は 7bitしか扱わない(1バイトが 8ビットとは限らない)ので、
どうするかはサーバー次第です。
 8bitのメールを送ってしまった場合、経由する全てのメールサーバーが 8bitを通すものなら
大丈夫かもしれませんが、8bit目を削除してしまう仕様のものが1つでもあれば
データは破損します。

 日本語をメールで送る場合、本文なら ISO-2022-JPに、ヘッダなら Base64とかのコードに
変換して 7bitで収まるようにしてから送っているので日本語がメールで扱えているわけです。


 でも半角カナは ISO-2022-JPには入っていないんですよね。だからそのまま流すと
どうなるかは状況次第です。
 半角カナをどう扱うかはメーラーによって対応が違っていて、うちのメーラーから
半角カナメールを送るとメーラー側で半角カナを判定して全角に直してから
送っているようです。


 今は ESMTPという 8bitを扱えるプロトコルがあり、大分普及してきているので
8bitで送ってしまっても大丈夫な確率は高くなっているのですが、
それでも半角カナは使わないのがマナーというものですね。

夏天

Re:サンプルプログラムにて

#11

投稿記事 by 夏天 » 18年前

管理人様のソースのコメント欄を考えて見ました
しかしコンパイルエラーが出てきます
どこが間違っているのでしょうか

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
//ChangeWindowMode( TRUE ) ;
int i,p1=0,p2=0,counter=0;
int Cr;
char txt2,txt[10][128]={
"今日はサウンドノベル風文字列表示法を勉強しています。",
"色々人の書いたプログラムを理解するのは難しいですが",
"わからなくとも、どんなプログラムでもいいので試行錯誤しながら自分で",
"いろんなプログラムを書いてみることで",
"自分の力となります。",
"がんばってください。",
};

if(CheckHitKey( KEY_INPUT_RETURN )){
p2++; p1=0;//次の文章へ
}

if(counter%3==0){//3周に1回処理をする
if( txt[p2][p1+1] != '\0' ){
p1+=2;//表示する文字を全角1つ増やす
}
}

for(i=0;i<p1;i++){
txt2=txt[p2];//コピー
/*もし用意した配列よりp1が大きければブレイク*/
if(txt2 < p1){
break;
}
}
txt2='\0';//終端記号格納

Cr = GetColor( 255 , 255 , 255 );

DrawFormatString( 0, 0, Cr, "%s", txt2);


counter++;
}


c:\program files\microsoft visual studio 8\vc\platformsdk\include\mmreg.h : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
c:\documents and settings\tenka\デスクトップ\vcqma\dxlib.h(1529) : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
c:\documents and settings\tenka\デスクトップ\vcqma\str.cpp(32) : error C2109: 配列または、ポインタでない変数に添字が使われました。
c:\documents and settings\tenka\デスクトップ\vcqma\str.cpp(34) : error C2109: 配列または、ポインタでない変数に添字が使われました。
c:\documents and settings\tenka\デスクトップ\vcqma\str.cpp(38) : error C2109: 配列または、ポインタでない変数に添字が使われました。
ビルドログは "file://c:\Documents and Settings\Tenka\デスクトップ\vcqma\Debug\BuildLog.htm" に保存されました。
vcqma - エラー 3、警告 2
========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ==========

box

Re:サンプルプログラムにて

#12

投稿記事 by box » 18年前

> 管理人様のソースのコメント欄を考えて見ました
> しかしコンパイルエラーが出てきます
> どこが間違っているのでしょうか

Unicode形式云々の件は、よくわかりません。
他の件は、

> 	char txt2,txt[10][128]={

txt2が配列ではないのに

> 		txt2=txt[p2];//コピー
> 		if(txt2 < p1){
> 	txt2='\0';//終端記号格納

配列のごとく扱っているためです。

管理人

Re:サンプルプログラムにて

#13

投稿記事 by 管理人 » 18年前

あらら・・すみません、txt2は配列のコピー先の配列なので、配列でなくてはなりません。
txtの一番低い次元の要素数用意してください。
つまり、今は

txt2[128]ということになります。
#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
        SetDrawScreen( DX_SCREEN_BACK );

	int i,p1=0,p2=0,counter=0; 
	int Cr; 
	char Key[256],oldKey[256]={},txt2[128],txt[10][128]={ 
		"今日はサウンドノベル風文字列表示法を勉強しています。", 
		"色々人の書いたプログラムを理解するのは難しいですが", 
		"わからなくとも、どんなプログラムでもいいので試行錯誤しながら自分で", 
		"いろんなプログラムを書いてみることで", 
		"自分の力となります。", 
		"がんばってください。", 
	}; 

	Cr = GetColor( 255 , 255 , 255 ); 

	while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && Key[KEY_INPUT_ESCAPE]==0){

			if( oldKey[KEY_INPUT_RETURN]==0 && Key[KEY_INPUT_RETURN]==1 ){//1回前の時入力してなくて、今入力していたら
				p2++; p1=0;//次の文章へ 
			}

			if(counter%3==0){//3周に1回処理をする 
				if( txt[p2][p1+1] != '\0' ){ 
					p1+=2;//表示する文字を全角1つ増やす 
				} 
			} 

			for(i=0;i<p1;i++){
				txt2=txt[p2];//コピー 
			/*もし用意した配列よりiが大きければブレイク*/ 
				if(128-1 <= i){ 
					break; 
				} 
			} 
			txt2='\0';//終端記号格納
			DrawFormatString( 0, 0, Cr, "%s", txt2); 

			for(i=0;i<256;i++)//今の入力情報を記憶
				oldKey=Key;

			counter++;
			ScreenFlip();
        }
        DxLib_End();
        return 0;
}

 
 
これでどうですか?

管理人

Re:サンプルプログラムにて

#14

投稿記事 by 管理人 » 18年前

極力おかきになったプログラムをそのまま使いましたが、どこかわからないところありますか?

夏天

Re:サンプルプログラムにて

#15

投稿記事 by 夏天 » 18年前

なんとか理解できそうです
いろいろわかりやすき教えていただきありがたく思っています
最初に誰か作ってくださいとわがままを言ったにもかかわらず
こんなにわかりやすく教えていただき本当にありがたいです
コレで野望にまた一歩近づいたような気がします
ありがとうございました!

管理人

Re:サンプルプログラムにて

#16

投稿記事 by 管理人 » 18年前

夏天さん、
人の書いたプログラムって理解するのは難しいものですよね。
だからこそ、ゲームプログラミングの館では、直接コードを見ることを目的とせず、概念を理解する事を目的としてご利用下さい。
頑張ってくださいね☆

Justyさん、
逆に私が質問したような形になってしまい、すみません^^;
なるほど、7というと中途半端な数字に見えますけど、特に8である必要はないですものね。
ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る