===== パラメータ表示するやつ作っていきマッスル ===== まず、いつも通りsiv3Dのプロジェクトを作ります。(ここまではいいよね?)\\ それから、背景画像を用意します。\\ Siv3Dで表示できる画像形式なら、何でもいいよ。\\ (画像形式に関しては、前期に習ったよね?)\\ Siv3Dのプロジェクトフォルダ⇒ App ⇒ example ⇒ 画像ファイル(名前は半角アルファベットで何でもいいよ)\\ 今回は、background.png を置いてみました。\\ {{:game-engineer:classes:2022:game-programing-1:second-term:10:bg.png?400|}} ==== 背景を表示 ==== とりあえず、テンプレートで作ったSiv3Dのプロジェクトは余計なもんが多すぎるので、痩身させます。\\ # include // OpenSiv3D v0.6.3 void Main() { //背景画像を設定 const Texture backGroundImage{ U"example/background.png" }; // 通常のフォントを作成 | Create a new font const Font font{ 60 }; // 絵文字用フォントを作成 | Create a new emoji font const Font emojiFont{ 60, Typeface::ColorEmoji }; // `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback font.addFallback(emojiFont); while (System::Update()) { } } ついでに背景画像を読み込む設定をします。\\ こう書いておくだけで画像を呼び出すことができます。\\ そうなんだ。。。って思うかもしれないですが後でwindowsプログラミングを習うととてもすごいことだってわかります。\\ //背景画像を設定 const Texture backGroundImage{ U"example/background.png" }; === 背景を表示するよ === Rectは矩形(くけい:四角形のことです、これからよく出てくるのでタンケイとか読まないように)\\ 矩形も前にやった、いろいろな形を書く命令の一つです。\\ 形状.draw()みたいな感じで大体かけましたよねぇ。\\ //Rectの宣言(定義) Rect{左上のx座標, 左上のy座標, 幅, 高さ} //上のRectにTexture image_name(画像)を貼り付ける Rect{左上のx座標, 左上のy座標, 幅, 高さ}(image_name) //上のRectにTexture image_name(画像)を貼り付けて、画面に描画 Rect{左上のx座標, 左上のy座標, 幅, 高さ}(image_name).draw() 最終的に、読み込んだ背景画像を描画するには、以下のように書く。\\ //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); === 背景を表示するソースコード === windowのサイズをwsizeに定数として宣言しておきます。\\ //デフォルトのウィンドウサイズを表す変数 Size // メンバにxとyを持つウィンドウなどのサイズを表すのに便利な型 // wsize.x: windowの幅 // wsize.y: windowの高さ const Size wsize{ 800,600 }; んで、背景を表示するには以下のようにします。\\ 簡単よね?\\ # include // OpenSiv3D v0.6.3 void Main() { //背景画像を設定 const Texture backGroundImage{ U"example/background.png" }; // 通常のフォントを作成 | Create a new font const Font font{ 60 }; // 絵文字用フォントを作成 | Create a new emoji font const Font emojiFont{ 60, Typeface::ColorEmoji }; // `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback font.addFallback(emojiFont); const Size wsize{ 800,600 }; while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); } } ==== キャラ画像を追加 ==== 次にキャラ画像を追加します。\\ 自分でpngなどの背景を透過できる画像を探してきたり、作成してもよいです。\\ 今回は簡単にsiv3Dの機能で、「絵文字を画像として表示する」機能を使ってみます。\\ [[https://emojipedia.org/|絵文字ペディア]]にある絵文字ならどれでも読み込んで使えます。\\ 今回は猫(🐈)とドラゴン(🐉)を使ってみます。\\ === 絵文字 ⇒ Texture型 === 絵文字を画像として表示するために、絵文字を読み込んで画像型の一つであるTexture型で変数を作ります。\\ // 絵文字からテクスチャを作成 | Create a texture from an emoji const Texture neko{ U"🐈"_emoji }; const Texture dragon{ U"🐉"_emoji }; あとは、そのままTextureのメンバ関数の.draw()を呼んでしまえば画面に表示できます。\\ # include // OpenSiv3D v0.6.3 void Main() { //背景画像を設定 const Texture backGroundImage{ U"example/background.png" }; // 通常のフォントを作成 | Create a new font const Font font{ 60 }; // 絵文字用フォントを作成 | Create a new emoji font const Font emojiFont{ 60, Typeface::ColorEmoji }; // `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback font.addFallback(emojiFont); // 絵文字からテクスチャを作成 | Create a texture from an emoji const Texture neko{ U"🐈"_emoji }; const Texture dragon{ U"🐉"_emoji }; const Size wsize{ 800,600 }; while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); neko.draw(); dragon.draw(); } } * 描画結果
{{:game-engineer:classes:2022:game-programing-1:second-term:10:2022-11-01_1_.png?400|}} 絵文字の表示
=== 位置の調整 === 画像の位置は、.draw()の引数で指定できます。\\ const Font emojiFont{ 60, Typeface::ColorEmoji }; 途中で、絵文字のサイズを指定していますが、これを60にしたからと言って60x60の矩形に収まるわけではないみたい。。。\\ とりあえず、試行錯誤で以下のように位置指定してみます。\\ 位置はPoint型で指定できます。\\ Point neko_position(200, 400);//猫位置 Point dragon_position(400, 400);//龍位置 while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); neko.draw(neko_position); dragon.draw(dragon_position); } ==== メッセージウィンドウを作ってみる ==== 次は、メッセージを表示するためのウインドウを表示する関数を作ってみます。\\ 以下のようなウィンドウを表示します。\\ * 表示例
{{:game-engineer:classes:2022:game-programing-1:second-term:10:2022-11-02.png?400|}} メッセージウィンドウの表示
=== 関数を考える === とりあえず、クラスのメンバーを渡すのは後で考えるとして。。。\\ RoundRectによって、角の丸い矩形を作ることができます。\\ .drawFrameメンバ関数で枠を書くことができます。(便利だよねぇ)\\ Font& _f引数には、Mainのほうで背景の次の行で宣言しているfontを渡してあげます。\\ 渡すフォントを変えるといろいろな字体で書けるはずです。\\ [[https://zenn.dev/reputeless/books/siv3d-documentation/viewer/tutorial-font!Siv3D チュートリアル(14.4フォントの種類参照)]] void drawMessageWindow(const Font& _f, const Rect _rect) { const int bound_margine = 3; //周りの余白 const int round_size = 5; //過度の丸さの具合 RoundRect{ _rect.x, _rect.y , _rect.w, _rect.h ,round_size } .draw(Palette::Black) //ウィンドウの内部の色 .drawFrame(2, 0, Palette::White); //枠のフレームの表示と色(枠外の太さ、枠内側の太さ、色) } こんな関数を作っておいて、Mainで呼びます。\\ Rectの左上位置、幅と高さは,{Point型, Size型}と並べることでも設定できます。\\ 後々見やすくなると思うので、この形で呼び出してみます。\\ Point mw_pos{ 50,50 }; Size mw_size{ 250, 280 }; while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); drawMessageWindow(font, Rect{ mw_pos, mw_size }); neko.draw(Point(200, 400)); dragon.draw(Point(400,400)); } これで表示例の様にメッセージウィンドウを表示できます。\\ === メッセージを表示するよ === あとは、メッセージウィンドウに文字列を書いてみます。\\ 最終的には、関数の引数に、キャラクタを表すクラスのインスタンスを追加して、受け取ったインスタンスのパラメータから、\\ キャラ名、HPやMPを表示するようにします。\\ とりあえず、関数内で必要な文字描画の命令を試してみます。\\ void drawMessageWindow(const Font& _f, const Rect _rect)を以下のように変更します。\\ void drawMessageWindow(const Font& _f, const Rect _rect) { const int bound_margine = 3; //周りの余白 const int round_size = 5; //過度の丸さの具合 RoundRect{ _rect.x, _rect.y , _rect.w, _rect.h ,round_size } .draw(Palette::Black) .drawFrame(2, 0, Palette::White); std::string tmp = "もじだよ"; //std::stringをSiv3D用にUnicode変換する String cname = Unicode::Widen(tmp);//std::string => Unicode変換 _f(cname).draw(25, _rect.x + 10, _rect.y + 10, Palette::White); //読み込んだフォントで書く! int hp = 300;//intをstring => Unicodeに変換して表示 std::string str_hp = " HP:" + std::to_string(300); _f(Unicode::Widen(str_hp)).draw(25, _rect.x + 10, _rect.y + 40, Palette::White); } Main側は変更はありません。\\ * 表示例
{{:game-engineer:classes:2022:game-programing-1:second-term:10:2022-11-02_1_.png?400|}} メッセージウィンドウにメッセージを表示
=== ついでに猫位置、龍位置を変数化 === この辺でついでに、猫の位置 Point neko_position、龍の位置 Point dragon_positionを宣言して、根琴竜の位置を変数化してしまいます。\\ こうしとくと、動きを付けるときとかに、あとで変更しやすいよね。\\ Point neko_position{ 200,400 }; Point dragon_position{ 400,400 }; while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); drawMessageWindow(font, Rect{ mw_pos, mw_size }); neko.draw(neko_position); dragon.draw(dragon_position); } ==== ついにインタラクション ==== ペットの犬に、「お手!」と言うと必ず「ワン!」と鳴いて手を出す犬がいます。(いるとします)\\ このように、何か合図やメッセージを送った時に一方通行にならず、お互いに反応が返ってくることを**「相互作用的」(インタラクティブ)**である。**インタラクション(Interaction)**する。などと言います。\\ と言います。\\ 今回は、「キャラクタ(の画像)をクリックしたらメッセージウィンドウが表示される」と言うインタラクションに挑戦してみます。\\ とは言っても、Siv3Dではとても簡単に実現できて、draw()関数がシステムに返しているオブジェクト(深くは考えなくてもいいです)のメンバ関数である\\ ^  関数名 ^ 内容 ^ 戻り値 ^ | leftClicked() | 左クリックされたか? | bool | | leftPressed() | 左ボタンが押されているか? | bool | | leftReleased() | 左ボタンが離された瞬間か? | bool | | rightClicked() | 左クリックされたか? | bool | | rightPressed() | 左ボタンが押されているか? | bool | | rightReleased() | 左ボタンが離された瞬間か? | bool | で調べられます。具体的には\\ if(neko.draw(neko_position).leftPressed()) { //左ボタンが押されているときの処理 } のように書けます。\\ って訳で、ボタンを押している間メッセージウィンドウを表示してみます。\\ たぶんできるよね。。。\\ while (System::Update()) { //背景を表示 Rect{ 0,0, wsize.x,wsize.y }(backGroundImage).draw(); //drawMessageWindow(font, Rect{ mw_pos, mw_size }); if (neko.draw(neko_position).leftPressed()) { //どうすればいい? } if (dragon.draw(dragon_position).leftPressed()) { //どうすればいい? } } ==== ゲームキャラクラスの作成と、メッセージウィンドウ関数への引数の追加 ==== 最後に、やっと猫と龍のもとになるゲームキャラクラスを作ってパラメータ設定します。\\ class cGameChara { private: std::string name_; int HP_; //生命力 int MP_; //魔法力 int ATK_; //攻撃力 Vec2 Position_; //2次元ベクトルでキャラクターの位置を表す public: cGameChara() {};//引数なしコンストラクタ(未完成) メンバイニシャライザを使ってみよう! cGameChara(std::string _name, int _hp, int _mp, int _atk);//引数有コンストラクタ(未完成) //デストラクタも書いてあげよう(中身は空でもOK) void setName(std::string _name) { name_ = _name; } void setHP(int _hp) { HP_ = _hp; } void setMP(int _mp) { MP_ = _mp; } void setATK(int _atk) { ATK_ = _atk; } int getHP() { return(HP_); }; int getMP() { return(MP_); }; int getATK() { return(ATK_); }; void setPosition(Vec2 _position) { Position_ = _position;} Vec2 getPosition() { return(Position_); } std::string getName() { return(name_); } }; こんな感じでキャラクタを表すクラスを作ってあげてください。(コンストラクタなどの実装は任せます)\\ このクラスのインスタンスとして、nekoとdragonを作って、そのパラメータを設定します。\\ //猫とドラゴンのインスタンスを生成 cGameChara cNeko("ねこ", 300, 100, 125), cDragon("おりゅう",600,800,500); //cGameChara *pNeko = new cGameChara("ねこ", 300, 100, 125), *pDragon = new cGameChara("おりゅう",600,800,500); //でもいいかなぁ そんで最後に、メッセージウィンドウ表示関数にその情報を渡してあげます。(どうやったらいい?)\\ void drawMessageWindow(const Font& _f, const Rect _rect) { //ごにょごにょ。。。省略 } これを。。。\\ void drawMessageWindow(const Font& _f, Rect _rect, cGameChara *_mychar) { //ごにょごにょ。。。省略 } こんな感じで引数を増やして、ポインタ経由で関数に渡してあげるといいです。\\ __**構造体やクラスをポインタ経由で渡すのはどうしてだっけ?**__\\