読者です 読者をやめる 読者になる 読者になる

ここまでの冒険を記録しますか?

長岡技大ソフトウェア開発サークルの開発ブログ

【ゲーム製作入門】C/C++で簡単なRPGを作る⑧【DXライブラリ】

書き手:肥田野

DXライブラリでRPGのベースになるマップ画面やデータ管理などのあれこれの制作に挑戦してみます。

RPGとして完成する保証はありませんが、途中経過だけでも参考になれば幸いです。

この連載は前回までの内容を理解していることを前提に進めていきます。

今回はウィンドウサイズを超えたマップの扱い方について解説します。

建物の中やワンフロアのダンジョンなどではこれまでの1画面のマップで事足りるのですが、やはりそれより広いサイズのマップも扱いたいですよね。

とはいえあまり広すぎるとcsvファイルの編集作業が大変なことになってしまうので、前回までより少し、縦横5マス分だけ拡張しました。実際には何マスでも拡張できますよ。

さて、マップを拡張するためには、csvファイルのデータの追加はもちろんですが、その他にもやらなければいけない大事な作業が生まれます。

それはカメラの移動です。主人公がウィンドウからはみ出ないように、カメラが追いかけなくてはいけません。

しかしこれまでカメラという概念は全く考えてきませんでしたよね。画像もただ座標を指定して描画していましたし。

それなら描画関数に指定する座標を操作して、あたかもカメラで追いかけているかのように描画しようというのが今回の発想です。

そのために新しいヘッダファイルを用意して、CameraDrawという関数を作成しました。

≪Function.h≫

#pragma once
#include<DxLib.h>

int viewX = 0;
int viewY = 0;

void CameraDraw(int x1,int y1,int x2,int y2,int gh,int trans){
    DrawExtendGraph(x1-viewX,y1-viewY,x2-viewX,y2-viewY,gh,trans);
}

viewXとviewYはグローバル変数です。

CameraDrawの中身はほとんどDrawExtendGraphそのままですが、座標からviewXとviewYを差し引いているのがミソです。

プレイヤーが移動するなどしてカメラを動かさなければいけない場合は、viewXとviewYをずらしてやります。

そして、プロジェクト内のマップ表示に関するすべてのDrawExtendGraphをCameraDrawに置き換えてやれば、引数の順番などはそのままなのですぐ使えるようになります。

ちなみに、Ctrl+Hキーで「検索と置換」をすることができます。これでドキュメントの中からDrawExtendGraphを全てCameraDrawに置き換えてやれば楽ちんですよ。

≪Map.h≫

#pragma once

#include<DxLib.h>
#include"Function.h"

#define CELL_WIDTH 40
#define CELL_HEIGHT 40
#define CELL_NUM_X 21
#define CELL_NUM_Y 17
#define WINDOW_Y 480
#define WINDOW_X 640

struct Cell{
    int gh;
    bool canwalk;
    int drawMode;//0:プレイヤーより奥 1:プレイヤーより手前
};

class Map{
public:
    Cell cell[CELL_NUM_X][CELL_NUM_Y];
    int chipgh[(128/16)*(1248/16)];
    int width,height;

    Map(char* add){
        LoadDivGraph("BaseChip.png",(128/16)*(1248/16),128/16,1248/16,16,16,chipgh);
        
        FILE* fp;//ファイルのポインタを宣言
        fp = fopen(add,"r");//fpを読み取り形式で開く
        if(fp == NULL){
            DebugBreak();
        }
        int c;//文字を格納する
        int retu = 0;
        int gyou = 0;
        char buf[10];//文字列を格納する
        memset(buf,0,sizeof(buf));
        bool eofFlag = false;
        while(1){
            while(1){
                c = fgetc(fp);
                if(c == EOF){
                    eofFlag = true;
                    break;
                }
                if(c != ','){//「,」が出てくるまで読み進める
                    strcat(buf,(const char*)&c);
                }else{
                    int num = atoi(buf);
                    cell[retu][gyou].gh = chipgh[num];
                    memset(buf,0,sizeof(buf));
                    break;
                }
            }
            if(eofFlag)break;
            while(1){
                c = fgetc(fp);
                if(c != ','){
                    strcat(buf,(const char*)&c);
                }else{
                    int num = atoi(buf);
                    cell[retu][gyou].canwalk = num;
                    memset(buf,0,sizeof(buf));
                    break;
                }
            }
            while(1){
                c = fgetc(fp);
                if(c != ';' && c != '\n'){
                    strcat(buf,(const char*)&c);
                }else{
                    int num = atoi(buf);
                    cell[retu][gyou].drawMode = num;
                    memset(buf,0,sizeof(buf));
                    break;
                }
            }
            //1セル分のループを抜けたら
            if(c == ';'){
                retu++;
            }
            if(c == '\n'){//改行だったら行を増やす
                gyou++;
                if(retu*CELL_WIDTH>width)width = retu*CELL_WIDTH;
                retu = 0;
            }
        }
        height = gyou*CELL_HEIGHT;
        fclose(fp);
    }

    void FrontView(){
        for(int i=0;i<CELL_NUM_X;i++){
            for(int j=0;j<CELL_NUM_Y;j++){
                if(cell[i][j].drawMode == 1)CameraDraw(i*CELL_WIDTH,j*CELL_HEIGHT,(i+1)*CELL_WIDTH,(j+1)*CELL_HEIGHT,cell[i][j].gh,TRUE);
            }           
        }
    }

    void BackView(){
        for(int i=0;i<CELL_NUM_X;i++){
            for(int j=0;j<CELL_NUM_Y;j++){
                if(cell[i][j].drawMode == 0)CameraDraw(i*CELL_WIDTH,j*CELL_HEIGHT,(i+1)*CELL_WIDTH,(j+1)*CELL_HEIGHT,cell[i][j].gh,TRUE);
            }           
        }
    }

    void All(){

    }
};

ほとんど変更点はありませんが、マップのサイズが変わったのでCELL_NUM_XとCELL_NUM_Yの値を変更し、ついでにマップ全体のサイズをwidthとheightという変数に保存しました。

この二つはControl.hで使います。

≪Control.h≫

#pragma once
#include<DxLib.h>
#include"Map.h"
#include"Player.h"

class Control{
public:
    Player* pl;
    Map* map[3];
    int camX,camY;

    Control(){
        camX = camY = 0;
        pl = new Player();
        map[0] = new Map("flame1.csv");
        map[1] = new Map("flame2.csv");
        map[2] = new Map("flame3.csv");
        pl->x = pl->targetX = CELL_WIDTH;
        pl->y = pl->targetY = CELL_HEIGHT;
    }

    ~Control(){
        delete pl;
        for(int i=0;i<3;i++){
            delete map[i];
        }
    }

    void All(){
        if(pl->x>WINDOW_X/2 && pl->x<map[0]->width-WINDOW_X/2+CELL_WIDTH){
            viewX = pl->x-WINDOW_X/2;
        }
        if(pl->y>WINDOW_Y/2 && pl->y<map[0]->height-WINDOW_Y/2){
            viewY = pl->y-WINDOW_Y/2;
        }

        for(int i=0;i<3;i++)map[i]->BackView();
        pl->All(map);
        for(int i=0;i<3;i++)map[i]->FrontView();
    }
};

All関数に注目してください。

ちょっと分かりにくい式ですが、プレイヤーがカメラを動かす必要がある座標にいるときだけ、viewXやviewYを動かしています。

マップの端まで来たときに真っ黒い画面が見えては興醒めなので、ちょうどマップの端がウィンドウの端で止まるように調整しています。

この式にはいくつも変数が使われて混乱しそうになりますが、落ち着いてじっくり読めば、どう動いているのかが分かるかと思います。

何しろ私も、この式に至るまで丸1日頭を抱え続けたので……(^_^;)

それと、使っているチップ画像が違えば全く役に立たないのですが、こちらで使っていたcsvの中身はこちらになります ≪flame1.csv

2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0
2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0;2,1,0

≪flame2.csv

88,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;89,0,0;90,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;33,1,1;34,1,1;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;41,0,0;42,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;33,1,1;34,1,1;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;41,0,0;42,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;33,1,1;34,1,1;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;41,0,0;42,0,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;33,1,1;34,1,1;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;41,0,0;42,0,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
96,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;98,0,0
104,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;105,0,0;106,0,0

≪flame3.csv

62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;83,0,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0
62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0;62,1,0

Exelで開く場合は、メモ帳などで先に「;」と「,」を入れ替えてから使ってくださいね。

この時もCtrl+Hが使えますよ。

さて、上手く広いマップを動き回れたでしょうか。

段々できることが広がっていく楽しさは、RPGそのものにも通じるところがありますね。

ゲームとは、作る段階から始まっているのかもしれません。

次回もノープランなので、実現できそうな要素から実装してみたいと思います。