この記事はSLP-KBIT AdventCalendar20246日目の記事です。
目次
・はじめに
・環境構築と基礎
・作ったもの一覧
・メイン関数最終形態
・おわりに
はじめに
こんにちは、Advent Calendar 6日目担当のkaedeです。現在時刻は12月6日17時です。完全に忘れていました。何も考えてなかったので最近触っているDXライブラリで簡単にゲームを作ります。
はい、よーいスタート。
環境構築や基礎
正直、環境構築はよくわかってません。ですが皆さんあちらの方へ行かれるようです。
ゲームの設計についてはこのサイトが参考になります。公式リファレンスを見ながら作りましょう。とりあえずメイン関数の骨組みは次の通り。
#include "DxLib.h"
#include"osero.h"
#include"keyboard.h"
#include<ctime>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (ChangeWindowMode(TRUE))return -1;
SetGraphMode(640, 640, 16);
if (DxLib_Init())return -1;
if (SetDrawScreen(DX_SCREEN_BACK))return -1;
srand((unsigned)time(NULL));
Osero osero;
osero.init();
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
osero.draw_board();
osero.move();
if ( hitkey(KEY_INPUT_RETURN)) {
osero.put_stone();
}
}
DxLib_End();
return 0;
}
osero.h
とkeyboard.h
は自分で作る予定のものです。メイン関数の動作は
- DXライブラリやオセロクラスの初期化
- ゲームボードの表示
- プレーヤーの操作を受け付ける
- 3を受けて必要な処理を実行する
- 4の結果を表示(=2に戻る)
このような流れになる予定です。
それでは実装してきます。
作ったもの一覧
実装してきました。現在時刻は21時ぐらいです。4時間ほどでだいたい作れたのでまとめて紹介します。
keyboard.h
DXライブラリにはキーボード入力回数を扱う関数はないため自作する必要があります。ということで作ったものがこちら。KeyCode
はDXライブラリで定義されているマクロです。
#include"DxLib.h"
#include"keyboard.h"
bool hitkey(int KeyCode) {
bool f = false;
while (CheckHitKey(KeyCode))f = true;
return f;
}
osero.h
多いので関数の実装はほとんど省略します。汚コードを見る覚悟の準備ができた方はこちらも参考にしてください。
#ifndef OSERO_H
#define OSERO_H
typedef struct {//座標
int y;
int x;
}P;
class Osero {
public:
int board[8][8];//i行j列の石の色(-1, 0, 1)
int color[3];//(0, 1, 2) = (黒, 緑, 白)
int dx[8] = { 0,1,1,1,0,-1,-1,-1 };//xの8方向
int dy[8] = { -1,-1,0,1,1,1,0,-1 };//yの8方向
int turn = 1;//現在の手番色
int pturn, cturn;//プレーヤー、コンピューターの手番色
P p;//カーソル
void init();
void draw_board();
void move();
void put_stone();
bool check_stone(int y, int x);
void res();
};
#endif
きたないですね。各関数の簡単な説明を書いておきます。
void init();//board, color, p, turnの初期化
void draw_board() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
//緑の正方形を間をあけて描写
DrawBox(j * 80 + 1, i * 80 + 1, j * 80 + 80, i * 80 + 80, color[1], TRUE);
//黒, 緑, 白の石を描写
DrawCircle(j * 80 + 40, i * 80 + 40, 30, color[board[i][j]+1], TRUE);
}
}
//プレイヤーのカーソル(手番色の小さい正方形)を描写
DrawBox(p.x * 80 + 3, p.y * 80 + 3, p.x * 80 + 15, p.y * 80 + 15, color[pturn+1], TRUE);
}
この関数ではゲームボード、石、プレイヤーのカーソルを描写します(下画像参照)。
現在の手番と色の番号を1(白)、-1(黒)で表現しているため、color
にアクセスするときはboard+1
しています。
手抜きポイントとして、マスの境界線は描写していません。画像の境界線は黒い線や長方形ではなく、何も描写されてないだけです。
void move();//上下キーで移動、ゲームボード外へ行かないように調整
void put_stone();//check_stone()で置けるか確認し、boardとturnを更新
bool check_stone(int y,int x);//y行x列マスに石を置けるならtrue
void res();//結果発表~~
メイン関数最終形態
上で用意したものを使って最終的にこんなものができました。
#include "DxLib.h"
#include"osero.h"
#include"keyboard.h"
#include<ctime>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (ChangeWindowMode(TRUE))return -1;
SetGraphMode(640, 640, 16);
if (DxLib_Init())return -1;
if (SetDrawScreen(DX_SCREEN_BACK))return -1;
srand((unsigned)time(NULL));
Osero osero;
osero.init();
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
osero.draw_board();
osero.move();
if ( hitkey(KEY_INPUT_RETURN)) {
osero.put_stone();
}
bool f = true;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (osero.check_stone(i, j))f = false;
}
}
if (f)break;
}
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
osero.res();
if (hitkey(KEY_INPUT_RETURN))break;
}
DxLib_End();
return 0;
}
ゲームは次のように進行します。
- DXライブラリと
Osero
クラスの初期化 - ゲームボード、石、カーソルの表示
- 十字キーでカーソルを動かす
- Enterが押されると次のどちらかを実行
- プレーヤーの手番の場合、カーソルがあるマスに石を置こうとする
- コンピューターの手番の場合、石を置けるマスからランダムに選択して置こうとする
- 石を置けなくなっているか調べる
- 置ける場合2に戻る
- 置けない場合は
break
する
- 石を数えて勝敗を表示する
おわりに
現在時刻は22時ぐらいです。ここでタイマーストップ。記録はだいたい5時間でした。完装した感想ですが、とりあえず終わってよかったです。完装したとは言いましたがいろいろ足りてないと思います。後、とにかく汚い。例えば、ここには載せてないですが、put_stone()
とcheck_stone()
はほぼ同じコードを書いているのでもうちょっとやりようがあったと思います。
もういい時間なのでこの記事はおしまいです。ここまで読んでくださりありがとうございました。
変更とか
ゲームボード描写の説明を追記しました。また、githubにコードを追加しました。
記事内で"オセロ"を"othello"ではなく"osero"と表記していますが仕様です。