リナザウのソフトウェア開発


○ 第4章 画面にペイントしてみる「スプライトでキャラクターを表示」






前回作成したRPGマップにキャラクターを表示させてみましょう。また、キーボードでそれを動かしてみましょう。
また、ここでは「条件(switch-case)」についても触れています。また、壁は通り抜けできないようにもなっています。




<CPPファイル名 main.cpp>

#include <qpe/qpeapplication.h>   // 使用するクラスを指定する

#include "mainwindow.h"   // 使用するプログラムを指定する

int main(int argc, char *argv[])
{
	QPEApplication a(argc,argv);
	Mainwindow *mw = new Mainwindow();
	a.showMainWidget(mw);
	return a.exec();
}


(解説は、かきかけ)



<ヘッダーファイル名 mainwindow.h>

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <qmainwindow.h>   // 使用するクラスを指定する
#include <qapplication.h>
#include <qcanvas.h>
#include <qtextcodec.h>
#include <qfont.h>
#include <qpixmap.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qstring.h>

class Mainwindow : public QWidget{
	Q_OBJECT

public:
	Mainwindow(QWidget *parent = 0, const char *name = 0);

protected:
    void paintEvent( QPaintEvent * );  // キャンバス描画時に用いる
	virtual void keyPressEvent( QKeyEvent *e );  // キー入力時に用いる

private:
	
	int cx;  // 数値「cx」の作成⇒キャラクターのx座標を入れる
	int cy;  // 数値「cx」の作成⇒キャラクターのy座標を入れる
	int c;  // 数値「c」の作成⇒キャラクターのいる位置に配置されているパネルを入れる
	
	int wallthrough;  // 数値「wallthrough」の作成⇒壁通り抜けモードの設定
	
	QTextCodec *codec; // テキストコーデック
	QCanvas *qs;  // 簡単にいえば絵を描くところ。絵画のキャンバスといっしょ。
	QCanvasView *qcv;  // QCanvas を表示させるもの。額みたいな。
	
	QCanvasPixmapArray *qcpa;  // 「キャラクター」のスプライトを載せる紙(?)を用意
	QCanvasSprite *qcsp;  // 「キャラクター」のスプライトに用いるために用意
	QCanvasText *qct;  // 画面上に文字を表示するために用意
	
	void readAreaMap( QString MapFile );  // CSV形式のマップファイルを読み込む機能を作成。MapFileで指定したファイルを読み込む
};

#endif //MAINWINDOW_H


(解説は、かきかけ)



<CPPファイル名 mainwindow.cpp>

#include "mainwindow.h"  // mainwindow.cpp のヘッダーファイル mainwindow.h を読み込み

Mainwindow::Mainwindow(QWidget *parent, const char *name)
		: QWidget(parent, name)
{
	// テキストコーデック「codec」を作成
	// 以降、codec->toUnicode("ここに書いたことは日本語で表示できる")
	codec = QTextCodec::codecForName("ShiftJIS");

	// ウィンドウのタイトルを設定
	setCaption(codec->toUnicode("サンプル7「キャラクターを動かそう!」"));

	// 使用するフォントを設定
	QFont f("lcfont",18);
	setFont(f);
	
	cx = 512;  // キャラクターが最初にいるx座標を設定
	cy = 1514;  // キャラクターが最初にいるy座標を設定
	wallthrough = 0;  // 壁通り抜けモードの初期値を「0」に設定(0なら通り抜け不可、1なら可)
	
	qs = new QCanvas(this);  // キャンバスを作成
    qs -> resize(2000,2000);  // キャンバスのサイズを縦2000、横2000に設定
    qcv = new QCanvasView(qs,this);  // キャンバスの額を作成
    qcv -> setGeometry(0, 0, 640, 420);  // キャンバスの額の位置を設定(縦420ドットは、これくらいにしないと水平スクロールバーがツールバーに隠れてしまうため)
    qcv -> setVScrollBarMode( QScrollView::AlwaysOff );  // V=vertical 垂直のスクロールバーを常にOFF
    qcv -> setHScrollBarMode( QScrollView::AlwaysOff );  // H=horizontal 水平のスクロールバーを常にOFF
    
    QPixmap pixmap;  // Pixmap(画像を読み込む場所?)を作成
    if ( pixmap.load("/mnt/card/panel_x125.gif") ){              // <条件>「/mnt/card/panel.gif」を「pixmap」に読み込む⇒成功したら中身を実行
    	qs -> QCanvas::setTiles(pixmap, 50, 50, 40, 40);  // キャンバス「qs」に(RPGのマップになる)タイルを「pixmap」から作成(横50マスX縦50マス、1マスは横40ドットX縦40ドット)
    	readAreaMap( "/mnt/card/torimann.map" );  // /mnt/card/torimann.map をマップファイルとしてreadAreaMapに渡して実行
    }
    
    qcpa = new QCanvasPixmapArray ( "/mnt/card/chara000f.gif", 0);  // キャラクター画像「/mnt/card/chara000f.gif」を「qcpa」に読み込む
    qcsp = new QCanvasSprite(qcpa, qs);  // qcpa をキャンバス「qs」にスプライト「qcsp」として配置(これでキャラクタースプライトが完成)
    qct = new QCanvasText(qs);  // 画面上に表示される文字「qct」を作成
    
    qs -> setUpdatePeriod( 100 );  // 100ミリ秒=0.1秒ごとに画面をupdate()する(⇒画面を更新)
}


// QCanvas を使うときにはなくてはいけない?update()実行時にこの中身が実行され画面中に描画される
void Mainwindow::paintEvent( QPaintEvent * )
{
	qcsp -> move(cx,cy);  // キャラクタースプライト「qcsp」をx座標cx,y座標cyに設定(画面の左上からではなくキャンバスの左上から)
    qcsp -> show();  // キャラクタースプライト「qcsp」を表示
    
    QString z;
    QString z1;
    QString z2;
    QString z3;
    int sx, sy;
    sx = qcv -> QScrollView::contentsX();  // sx に額「qcv」の水平スクロールバーの位置を入れる
    sy = qcv -> QScrollView::contentsY();  // sy に額「qcv」の垂直スクロールバーの位置を入れる
    z1.setNum(cx, 10);  // 文字列「z1」に数値「cx」を10進数で文字列に変換して入れる
    z2.setNum(cy, 10);
    z3.setNum(c, 10);
    z = "cx : " + z1 + "   cy : " + z2 + "   c : " + z3;  // 現在位置情報
    if(wallthrough == 1) z = z + "  wallthrough";  // <条件>もし「wallthrough」の値が1なら文字列「z」の最後に「wallthrough」を追加
    qct -> setText(z);  // 画面上に表示する文字「qct」の表示する文字を「z」に設定
	qct -> setColor(QColor::QColor(200,0,0));  // 画面上に表示する文字「qct」の文字色を赤色(Red 200,Green 0,Blue 0)に設定
	qct -> move(sx,sy);  // 画面上に表示する文字「qct」をx座標sx,y座標syに設定(画面の左上からではなくキャンバスの左上から)
	qct -> show();  // 画面上に表示する文字「qct」を表示
	
	qcv -> setContentsPos(cx-320,cy-210);  // 額「qcv」のスクロールバーの位置を水平「cx-320」垂直「cy-210」に設定
}



// キー操作を受け付ける
void Mainwindow::keyPressEvent( QKeyEvent *e )
{
	int v=0, w=0;  // 数値「v」を「0」を、数値「w」を「0」を入れて作成(vはx方向移動量、wはy方向移動量)
	int ws = 4;  // 数値「ws」を「4」を入れて作成(⇒移動速度)
	
	switch (e->key()) {  // <条件−場合分け−>入力したキーが
		case Qt::Key_Right :  // 右方向キーの場合
			v = ws;
			break;  // この場合を終了
		case Qt::Key_Left :  // 左方向キーなら
			v = ws * (-1);
			break;
		case Qt::Key_Up :  // 上方向キーなら
			w = ws * (-1);
			break;
		case Qt::Key_Down :  // 下方向キーなら
			w = ws;
			break;
		case Qt::Key_M :  // Mキーなら
			if(wallthrough == 0){  // <条件>もし「wallthrough」の値が0なら
				wallthrough = 1;
			} else {  // そうでなければ
				wallthrough = 0;
			}
			break;
	}  // 場合分け終了

	int x, y;
	x = (cx+v+9)/40;  // 計算して現在キャラクターのいるマスのX座標を「x」に入れる
	y = (cy+w+15)/40;  // 計算して現在キャラクターのいるマスのY座標を「y」に入れる
	c = qs -> QCanvas::tile(x,y);  // x列y行のタイルを取得して「c」に入れる
	if((c >= 300) || (wallthrough == 1)){  // <条件>『「c」の値が300以上』または『「wallthrough」の値が1(壁通り抜けモード)』なら(300より下なら壁など移動不可のタイルとする)
		cx = cx + v;  // これはキャラクターをX方向にvだけ移動するということ
		cy = cy + w;  // これはキャラクターをY方向にwだけ移動するということ
	}
	update();  // 画面の更新(=書き換え)
}



// エリアマップの呼び出し(CSVファイル)
// マップファイルの数値はそのまま配置するタイル番号となっている。50行、50列までという制限はしない。
void Mainwindow::readAreaMap( QString MapFile )
{
	QFile textfile( MapFile );  // MapFile(マップファイル)をファイル名として、textfile に入れる
	if ( textfile.open(IO_ReadOnly) ){  // textfile(=MapFile)を開く(読み込み準備)
		QTextStream t( &textfile );  // textfile を読み込んだ中身が流れる道(t)を作る
		t.setCodec( codec );  // t の文字コードをcodec(=Shift-JIS) に設定する
		QString s;  // 文字列変数s の作成(読み込んだ1行をここに入れる)
		QStringList p;  // 文字列配列p の作成(,(カンマ)で区切って並べたリストを入れる)
		QString pl;  // 文字列変数pl の作成(plで並べたリストから取り出した1つ(=配置するタイル番号)を入れる)
		int px = 0;  // 数値変数px の作成(設定するマップのマスの横列の位置を入れる)
		int py = 0;  // 数値変数py の作成(設定するマップのマスの縦列の位置を入れる)
		int pxy;  // 数値変数pxy の作成(pl を文字列から数値に変換したものを入れる)
		
		while ( !t.eof() ) {  // ファイルの最後の行を読み込み終えるまで繰り返す(1行ずつ読み込んでいく)
			s = t.readLine();  // s に読み込んだ行を入れる
			p = QStringList::split(',', s, TRUE);  // リスト「p」に「s」を「,(カンマ)」で区切って1成分ずつ並べる
			px = 0;  // px の値を0にする(左端にもどる)
			
			for ( QStringList::Iterator it = p.begin(); it != p.end(); ++it ) {  // リスト「p」の最初から「it」に入れていき、最後になるまで繰り返す
				pl = *it;  // pl に取り出した成分を入れる
				pxy = pl.toInt(0,10);  // pl を10進数で数値に変換し、「pxy」に入れる
				qs -> QCanvas::setTile(px,py,pxy);  // キャンバス「qs」の横「px」、縦「py」の位置のタイルを「pxy」に設定する
				
				px++;  // 「px」の値を1増やす(横に1ずれる)
			}
			
			py++;  // 「py」の値を1増やす(下に1ずれる)
		}
		textfile.close();  // ファイル「textfile(=MapFile)」を閉じる
	}
}


(解説は、かきかけ)




というわけで、さっそくコンパイルして実行してみましょう。
ここでは、「~/SLZaurus/」以下に「sample0007」フォルダを作成し、その中にソースがあることを前提にしています。


Cygwinを起動して、次のコマンドを実行してください。



. ~/SLZaurus/bin/dev-arm-qpe.sh
cd ~/SLZaurus/sample0007
progen -o sample0007.pro
tmake -o Makefile sample0007.pro
make



これでエラーが出なければ、「sample0007」というファイルがソースと同一のフォルダに作成されているので、それをリナザウに移してターミナルから実行してみてください。
エラーが出た場合は、もう一度ソースを見直して、問題のある個所を修正しましょう。問題のある個所は、「make」後のエラー情報でも最低限のことは提供されます。




実行する場合は、マップファイル、タイル画像ファイルを「/mnt/card/」においてください。
よりRPGっぽくなりました。初期座標を変更したり、新しい機能をキーにつけたりしてみてください。




<ソース>

sample0007.tar.gz

First Seed Material, REFMAP 様の画像を利用させていただきました。
http://www.tekepon.net/fsm/




前へ ○○○ 「リナザウのソフトウェア開発」 ○○○ 次へ






inserted by FC2 system