初期設定
DXLibを設定しておきましょう。他の記事のようにDXLibがメインではないので詳しくはやりません。一応こちらで公式様が説明していますので貼っておきます
ファイル構成
今回のファイル構成はこちらになってます。実際コピペして動作させたい人は.cppと.hに関しては同じ名前にしましょう

main.h
#pragma once
#include"DxLib.h"
#include<iostream>
#include<ctime>
#include<string>
class game {
private:
class player {
public:
int hp, atack, deffense;
void Initstatus();
int Atack();
int Deffense();
};
class enemy {
public:
int hp, atack, deffense;
void Initstatus();
int Atack();
int Deffense();
};
player Player;
enemy Enemy;
public:
void Init();
void Run();
void Drawstatus();
void Drawwin(int type);
};
これが今回扱うメイン部分になります。他はここに書いている関数を定義しているだけなので大して重要ではありません。
player.cpp
#include"main.h"
void game::player::Initstatus() {
hp = 100;
atack = 10;
deffense = 5;
}
int game::player::Atack() {
return atack+(rand()%10);
}
int game::player::Deffense() {
return deffense +(rand() % 5);
}
なんとなく見てわかる通り、class playerの関数を定義してます。
enemy.cpp
#include"main.h"
void game::enemy::Initstatus() {
hp = 100;
atack = 10;
deffense = 5;
}
int game::enemy::Atack() {
return atack + (rand() % 10);
}
int game::enemy::Deffense() {
return deffense + (rand() % 5);
}
全く変わってませんね。class enemyの関数を定義してます
main.cpp
#include"main.h"
#define SCREEN_X 1280
#define SCREEN_Y 720
void game::Init() {
srand((unsigned int)time(NULL));
ChangeWindowMode(TRUE);
SetGraphMode(SCREEN_X, SCREEN_Y, 32);
if (DxLib_Init() == -1)exit(1);
Player.Initstatus();
Enemy.Initstatus();
}
void game::Drawstatus() {
int green = GetColor(0,255,0),red= GetColor(255,0,0);
DrawBox(10, SCREEN_Y - 30,(300*((double)Player.hp/100))+10, SCREEN_Y - 10,green, TRUE);
DrawFormatString(10, SCREEN_Y - 130,GetColor(255,255,255),"player: atack %d deffence %d",Player.atack,Player.deffense);
DrawFormatString(10, SCREEN_Y - 45, GetColor(255, 255, 255), "playerHP %d", Player.hp);
DrawBox(SCREEN_X-400, SCREEN_Y - 30,(300 * ((double)Enemy.hp / 100))+ SCREEN_X - 400, SCREEN_Y - 10,red, TRUE);
DrawFormatString(SCREEN_X - 400, SCREEN_Y - 130, GetColor(255, 255, 255), "enemy: atack %d deffence %d",Enemy.atack,Enemy.deffense);
DrawFormatString(SCREEN_X - 400, SCREEN_Y - 45, GetColor(255, 255, 255), "enemyHP %d", Enemy.hp);
}
void game::Drawwin(int type) {
ClearDrawScreen();
char s[10] = "enemy";
if (type == 0)strcpy_s(s,"player");
SetFontSize(128);
DrawString(SCREEN_X / 3, SCREEN_Y / 3,s,GetColor(255, 255, 255));
}
void game::Run(){
int atack, deffence;
Init();
Drawstatus();
WaitKey();
ClearDrawScreen();
while (!CheckHitKey(KEY_INPUT_ESCAPE)&& ProcessMessage() != -1) {
atack=Player.Atack();
atack -= Enemy.Deffense();
Enemy.hp -= atack;
Drawstatus();
WaitKey();
if (Player.hp <= 0) {
Drawwin(1);
break;
}
else if (Enemy.hp <= 0) {
Drawwin(0);
break;
}
ClearDrawScreen();
atack = Enemy.Atack();
atack -= Player.Deffense();
Player.hp -= atack;
Drawstatus();
WaitKey();
if (Player.hp <= 0) {
Drawwin(1);
break;
}
else if (Enemy.hp <= 0) {
Drawwin(0);
break;
}
ClearDrawScreen();
}
WaitKey();
DxLib::DxLib_End();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
game Main;
Main.Run();
return 0; // ソフトの終了
}
超絶長いけど中身は繰り返しで長くなってるだけです。
では、ここからclassの使い方をこれらのファイルを用いて説明していきます。
上手なclassの使い方
classの宣言
.hをみて気づいた方も居ると思いますが、classを使うにはまずはclassを宣言しないといけません。
class game {
private:
class player {
//中身省略
};
class enemy {
//中身省略
};
player Player;
enemy Enemy;
public:
void Run();
//中身省略
};
中身を省略をしたことにより随分とわかりやすくなりましたね。この通りclass 名前{中身};で宣言します。ご覧の通り、classの中でclassを宣言することも出来ます。private: public:というのがありますが、これはなんなんでしょうか?
図を書いてみました

classという大きな空間があって、publicは何にも守られずに自由に外からアクセスできます。ですが、privateという壁に守られた中身は別です。この壁はクラスの外からのアクセスはブロックして中身からのアクセスは通します。セキュリティ的に良さそうですよね?実際にセキュリティ的にも、間違ってアクセスしてバグになる危険性も減るのでなるべくprivateで閉じて、使う関数や変数だけ出すようにしましょう。使い方は上のコードの通り、private: public:です。カッコなので囲む必要はありません。
classを使う
宣言はできても使わなければもちろん意味はありません。実際クラスを使うにはどうすればいいのでしょうか、main.cppの一部で使われている部分を抜き出したものがこちらです。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
game Main;
Main.Run();
return 0; // ソフトの終了
}
気づかれた人もいるんじゃないでしょうか。 class gameを使うにはgame 名前;で生成します。もういっちょいくとclassのpublicな部分は先ほど生成した名前.使う変数や関数の名前で使えます。Run()というclass gameでpublicにしてた関数をMain.Run()という形で使ってますよね?class gameの内容をこのように
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
game Main,Sub;
Main.Run();
Sub.Run();
return 0; // ソフトの終了
}
複数生成して使うことも可能です。敵を複数生成したいとか仲間を複数生成したいとかに使えます。覚えておきましょう
関数の定義
宣言や生成はやりましたが肝心な関数の定義をやってないですね。ですが、大して変更点はありません。こうやります
void game::Run(){
//中身省略
}
classの名前::関数の名前です。class gameの中にあるRun()を定義するならgame::Run()ですね。
インナーclass
インナークラスとはclassの中にあるクラスです。
class game {
private:
class player {
//中身省略
};
class enemy {
//中身省略
};
player Player;
enemy Enemy;
public:
void Run();
//中身省略
};
これのplayerとenemyですね。インナークラス中身は先ほど説明した通り、privateの部分は外(class game)からは見えません。ですが、gameのprivate部分はどうでしょうか?実は見えます。この場合はplayerからPlayer,Enemyは見えてしまいます。この性質を使えば安全にグローバル変数が使えそうですよね。その性質を使い忘れました。
最後に
長期戦を覚悟してましたが、意外と少なくてびっくりしています。理解したかどうかは提示したコードを読めばわかると思いますので是非読んでみてください。ちなみに蛇足ですが、このプロジェクトは実行するとこんな感じで表示されて

クリックする度にランダムで体力が減っていきます。どっちが勝ったかも表示されるので時間がある方は実行してみて下さい。
コメント