===== パラメータ表示するやつ作っていきマッスル =====
まず、いつも通り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)
{ //ごにょごにょ。。。省略
}
こんな感じで引数を増やして、ポインタ経由で関数に渡してあげるといいです。\\
__**構造体やクラスをポインタ経由で渡すのはどうしてだっけ?**__\\