【C言語】 文字で作ったマップ上をキー入力でキャラが移動するプログラム

文字で作ったマップ上を方向キー入力で
キャラクターの「○」を移動操作ができるプログラムを作ってみたのでメモ。

最終更新日:2014/12/29

▼目次
2012005701.png

掲載しているソースコードは
「Borland C++ Compiler 5.5」のコンパイラでコンパイルして
動作確認しています。
そのため、他のコンパイラではコンパイルエラーが発生したり、
操作が出来ない等があるかもしれませんので注意。


▼ソースコード

操作方法:
キャラクター操作:
方向キー上下左右
終了:
Escキー
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

int KEY(int *Kn,int *Y,int *X);

int main(void)
{
    //数値格納
    int  kn;         //入力キー
    int  sty,stx;    //座標
    int  fy,fx;      //マップ範囲
    int  jm[25][40]; //移動可不判定
    char mapc[3]={0};//複写されたマップ構成情報

    //カウント
    int y,x; //判定生成、座標生成・描写用


    //マップチップ
    char mc[2][3]={
/*mc[0] 移動可能*/" ",
/*mc[1] 移動不可*/"■"};

    //マップ構成 (最大値 25行x40列)
    char map[][81]={
/*00*/"■■■■■■■■■■",
/*01*/"■ ■      ■",
/*02*/"■ ■■■■ ■ ■",
/*03*/"■ ■■   ■ ■",
/*04*/"■  ■ ■■■ ■",
/*05*/"■■ ■ ■   ■",
/*06*/"■  ■ ■ ■■■",
/*07*/"■ ■■ ■   ■",
/*08*/"■    ■ ■ ■",
/*09*/"■■■■■■■■■■"};


    //キャラクター
    char st[1][3]={"○"};

    //キャラクター初期座標指定
    sty=8,stx=8;


    /* マップ範囲算出 */
    fy=sizeof(map)/81;   //行
    fx=strlen(map[0])/2; //列

    /* 判定生成 */
    for(y=0;y<fy;y++){
        for(x=0;x<fx;x++){
            strncpy(mapc ,&map[y][(x)*2] ,2 );
                 if(strncmp(mc[1],mapc,2)==0){jm[y][x]=1;} //移動不可判定
            else if(strncmp(mc[0],mapc,2)==0){jm[y][x]=0;} //移動可能判定
        }
    }

    /* 画面出力 */
    while(1){
        system("cls"); //画面消去

        /* 座標生成、描写 */
        for(y=0;y<fy;y++){
            for(x=0;x<fx;x++){
                strncpy(mapc ,&map[y][(x)*2] ,2);
                if(jm[y][x]==0){
                         if(y==sty&&x==stx)
                                    {printf("%s",st[0]);} //キャラ表示
                    else if(strncmp(mc[0],mapc,2)==0)
                                    {printf("%s",mapc );} //移動可能表示
                }
                else if    (strncmp(mc[1],mapc,2)==0)
                                    {printf("%s",mapc );} //移動不可表示
            }
            if(fx<40){printf("\n");} //fxが40未満の場合、改行
        }

        /* 入力キー、移動座標出力 */
        KEY(&kn,&sty,&stx);

        /* 壁、マップ外への侵入防止 */
        for(y=0;y<sty+1;y++){
            for(x=0;x<fx;x++){
                if((y==sty&&x==stx&&jm[y][x]==1)||(fy<=sty||fx<=stx)){
                         if(kn==0x4b){stx++;}
                    else if(kn==0x4d){stx--;}
                    else if(kn==0x48){sty++;}
                    else if(kn==0x50){sty--;}
                    break;
                }
            }
        }

        /* 終了操作 */
        if(kn==0x1b){printf("▼終了します。\n") ;break;}
    }

}

/* 入力キー、移動座標出力 */
int KEY(int *Kn,int *Y,int *X){
    while(1){
        *Kn=getch( );     //1:通常キー
        if ((*Kn==0x00)||(*Kn==0xe0)){
            *Kn=getch( ); //2:特殊キー
                 if (*Kn==0x4b){(*X)--;}// ←
            else if (*Kn==0x4d){(*X)++;}// →
            else if (*Kn==0x48){(*Y)--;}// ↑
            else if (*Kn==0x50){(*Y)++;}// ↓
          //else if (*Kn==0x  ){       }   特殊キー追加場所
            else {continue;}
            break;
        }
        else if (*Kn==0x1b){}// Esc
      //else if (*Kn==0x  ){}   通常キー追加場所
        else {continue;}
        break;
    }
    return 0;
}


▼マップとキャラクター等の変更方法

ソースコードは後からマップやキャラクターを変更しやすいよう工夫して作ってみました。
変更方法についてはソースコードの頭から順に説明します。


1. マップの変更

マップは「移動可能な領域」と「移動不可能な領域」を設定された
2種類の文字を組み合わせ、
画面上に最大縦25文字(行)、横40文字(列)の広さまで
作れるようになっています。

説明のため、マップを下記のように作り変えてみます。

木木木木木木木木木木木木木木
木木木木木木ww木木木木木木
木木wwwwwwwwww木木
木木木木木木ww木木木木木木
木木木木wwwwww木木木木
木木木ww木ww木ww木木木
木木ww木木ww木木ww木木
木ww木木木ww木木木ww木
木木木木木木木木木木木木木木

マップの広さは縦9文字横14文字で、
キャラクターが移動可能な領域は全角英字の
移動不可能な領域は漢字の としています。

また、マップを作る際、移動しない領域でもすべて
移動可能、不可能どちらかの文字で埋めて行の長さ(文字数)を揃え
マップの外周を四角に整えないと表示の際にマップが崩れてしまいます。
下記はダメな例。

      木木
  木木木木ww木木木木
 木wwwwwwwwww木
  木木木木ww木木木木
   木wwwwww木
  木ww木ww木ww木
 木ww木木ww木木ww木
木ww木 木ww木 木ww木
 木木   木木   木木


まず、「マップチップ」ではマップに使う文字を設定します。

移動可能、不可能にそれぞれ全角文字を1文字だけを設定、
2文字以上は設定しないでください。
また、両方に同じ文字は使えません。

 は全角のスペース

021
022
023
024

    //マップチップ
    char mc[2][3]={
/*mc[0] 移動可能*/" ",
/*mc[1] 移動不可*/""};


021
022
023
024

    //マップチップ
    char mc[2][3]={
/*mc[0] 移動可能*/"",
/*mc[1] 移動不可*/""};

続いて「マップ構成 」では表示したいマップに変更します。
char map[][81] = { から }; の間にあるマップを
先に考えておいたマップに変更します。

", の付け方に注意。

026
027
028
029
030
031
032
033
034
035
036
037

    //マップ構成 (最大値 25行x40列)
    char map[][81]={
/*00*/"■■■■■■■■■■",
/*01*/"■ ■      ■",
/*02*/"■ ■■■■ ■ ■",
/*03*/"■ ■■   ■ ■",
/*04*/"■  ■ ■■■ ■",
/*05*/"■■ ■ ■   ■",
/*06*/"■  ■ ■ ■■■",
/*07*/"■ ■■ ■   ■",
/*08*/"■    ■ ■ ■",
/*09*/"■■■■■■■■■■"};


026
027
028
029
030
031
032
033
034
035
036
037

    //マップ構成 (最大値 25行x40列)
    char map[][81]={
/*00*/"木木木木木木木木木木木木木木",
/*01*/"木木木木木木ww木木木木木木",
/*02*/"木木wwwwwwwwww木木",
/*03*/"木木木木木木ww木木木木木木",
/*04*/"木木木木wwwwww木木木木",
/*05*/"木木木ww木ww木ww木木木",
/*06*/"木木ww木木ww木木ww木木",
/*07*/"木ww木木木ww木木木ww木",
/*08*/"木木木木木木木木木木木木木木"};


左側の縦に /*00*/ /*01*/ /*02*/... とあるのは
行数が分かりやすいようにしているだけなので無くても大丈夫です。


2. キャラクターの変更

キャラクターは全角1文字だけ設定できます。

元のソースでは全角の記号 でキャラクターを表示していました。
これを漢字の に変えてみます。

040
041

    //キャラクター
    char  st[1][3]={""};


040
041

    //キャラクター
    char  st[1][3]={""};


3. キャラクターの初期位置の変更

「キャラクター初期座標指定」の stystx の値を変更することで
キャラクターの初期位置を調整できます。

説明のためキャラクターの初期位置は
下記の移動可能な場所の上にしてみます。

初期位置は移動可能な場所になるようにしないと
移動させるキャラクターが消えたりします。

木木木木木木木木木木木木木木
木木木木木木ww木木木木木木
木木wwwwwwwww木木
木木木木木木ww木木木木木木
木木木木wwwwww木木木木
木木木ww木ww木ww木木木
木木ww木木ww木木ww木木
木ww木木木ww木木木ww木
木木木木木木木木木木木木木木

キャラクターの位置は上から3(sty=2)、左から3(stx=2)になります。

sty が縦(行)、 stx が横(列)になっていて
マップの左上を基準に値が縦は下へ、横は右へ増えていきます。
値は0から始まるので左上を1として順に数えていくと
想定していた位置からずれるので注意。


043
044

    //キャラクター初期座標指定
    sty=8,stx=8;


043
044

    //キャラクター初期座標指定
    sty=2,stx=2;


▼変更後のソースコード

マップとキャラクター等変更後のソースコードです。

2012005702.png
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

int KEY(int *Kn,int *Y,int *X);

int main(void)
{
    //数値格納
    int  kn;         //入力キー
    int  sty,stx;    //座標
    int  fy,fx;      //マップ範囲
    int  jm[25][40]; //移動可不判定
    char mapc[3]={0};//複写されたマップ構成情報

    //カウント
    int y,x; //判定生成、座標生成・描写用


    //マップチップ
    char mc[2][3]={
/*mc[0] 移動可能*/"",
/*mc[1] 移動不可*/""};

    //マップ構成 (最大値 25行x40列)
    char map[][81]={
/*00*/"木木木木木木木木木木木木木木",
/*01*/"木木木木木木ww木木木木木木",
/*02*/"木木wwwwwwwwww木木",
/*03*/"木木木木木木ww木木木木木木",
/*04*/"木木木木wwwwww木木木木",
/*05*/"木木木ww木ww木ww木木木",
/*06*/"木木ww木木ww木木ww木木",
/*07*/"木ww木木木ww木木木ww木",
/*08*/"木木木木木木木木木木木木木木"};



    //キャラクター
    char  st[1][3]={""};

    //キャラクター初期座標指定
    sty=2,stx=2;


    /* マップ範囲算出 */
    fy=sizeof(map)/81;   //行
    fx=strlen(map[0])/2; //列

    /* 判定生成 */
    for(y=0;y<fy;y++){
        for(x=0;x<fx;x++){
            strncpy(mapc ,&map[y][(x)*2] ,2 );
                 if(strncmp(mc[1],mapc,2)==0){jm[y][x]=1;} //移動不可判定
            else if(strncmp(mc[0],mapc,2)==0){jm[y][x]=0;} //移動可能判定
        }
    }

    /* 画面出力 */
    while(1){
        system("cls"); //画面消去

        /* 座標生成、描写 */
        for(y=0;y<fy;y++){
            for(x=0;x<fx;x++){
                strncpy(mapc ,&map[y][(x)*2] ,2);
                if(jm[y][x]==0){
                         if(y==sty&&x==stx)
                                    {printf("%s",st[0]);} //キャラ表示
                    else if(strncmp(mc[0],mapc,2)==0)
                                    {printf("%s",mapc );} //移動可能表示
                }
                else if    (strncmp(mc[1],mapc,2)==0)
                                    {printf("%s",mapc );} //移動不可表示
            }
            if(fx<40){printf("\n");} //fxが40未満の場合、改行
        }

        /* 入力キー、移動座標出力 */
        KEY(&kn,&sty,&stx);

        /* 壁、マップ外への侵入防止 */
        for(y=0;y<sty+1;y++){
            for(x=0;x<fx;x++){
                if((y==sty&&x==stx&&jm[y][x]==1)||(fy<=sty||fx<=stx)){
                         if(kn==0x4b){stx++;}
                    else if(kn==0x4d){stx--;}
                    else if(kn==0x48){sty++;}
                    else if(kn==0x50){sty--;}
                    break;
                }
            }
        }

        /* 終了操作 */
        if(kn==0x1b){printf("▼終了します。\n") ;break;}
    }

}

/* 入力キー、移動座標出力 */
int KEY(int *Kn,int *Y,int *X){
    while(1){
        *Kn=getch( );     //1:通常キー
        if ((*Kn==0x00)||(*Kn==0xe0)){
            *Kn=getch( ); //2:特殊キー
                 if (*Kn==0x4b){(*X)--;}// ←
            else if (*Kn==0x4d){(*X)++;}// →
            else if (*Kn==0x48){(*Y)--;}// ↑
            else if (*Kn==0x50){(*Y)++;}// ↓
          //else if (*Kn==0x  ){       }   特殊キー追加場所
            else {continue;}
            break;
        }
        else if (*Kn==0x1b){}// Esc
      //else if (*Kn==0x  ){}   通常キー追加場所
        else {continue;}
        break;
    }
    return 0;
}


▼更新履歴

2014/12/29_ver2.1
方向キーをgetchで読み取った場合、始めに返ってくる値が
「Borland C++ Compiler 5.5」だと 0 で
「Microsoft Visual Studio」系では e0 のため
Visual Studio系でコンパイルを行うと
方向キーでの操作が出来なかったのを対応
2013/02/02_ver2.0
ソースコード修正
  • 「マップ範囲(旧 フィールド範囲)」の算出を自動化
  • 「マップ構成(旧 マップ表示)」で1文字単位で区切るのから
    行単位で区切るのに変更
  • 「マップチップ」での変更だけで
    「判定生成」と「座標生成、表示(旧 座標生成、描写 )」の変更を可能に
  • マップ外へキャラクターが出ないように処理
2013/01/14_ver1.1
ソースコードを整理
2013/01/02_ver1.0
掲載
[ 2013/01/02 16:45 ] C言語 | TB(-) | CM(-)
SPONSORED LINK
人気ブログランキング
▲ページトップ