C++でのゲーム開発勉強(1)

c++
GitHub - kowara-gan/ProjectCpp: c++勉強用
c++勉強用. Contribute to kowara-gan/ProjectCpp development by creating an account on GitHub.

参考書の初めに作るゲームであるpongGameをつくります。日本ではポンゲームとよばれ、画面上で遊ぶ卓球ゲームのことです。

Visual Studioで新しいプロジェクトを作ります。c++の空のオブジェクト。

前回と同じようにソリューション名のプロジェクト名(Project1)を右クリック、追加->新しい項目->C++ファイルからGame.cppとmain.cppを作成します。また、追加->新しい項目->ヘッダーファイルを選択し、Game.hを作成します。

前回同様にSDLが使用できるように設定していきます。githubからすべてをコピぺする前に、main.cppに前回のHello.cppをコピペして動くか試したほうが無難です。

main.cpp

#include "Game.h"

int main(int argc, char** argv) {
	Game game;
	bool success = game.Initialize();
	if (success) {
		game.RunLoop();
	}
	game.Shutdown();
	return 0;
}

プログラムを動かすとき、はじめにこのプログラムが起動します。Gameクラスオブジェクトが初期化され、ループされます。ループ状態を抜けると、シャットダウンして終了します。

Game.h

#pragma once
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "SDL.h"

struct Vector2 {
	float x;
	float y;
};

struct Ball {
	Vector2 pos;
	Vector2 vel;
};

class Game {
public:
	Game();
	//ゲームを初期化する
	bool Initialize();
	//ゲームオーバーまでゲームループを実行する
	void RunLoop();
	//ゲームをシャットダウンする
	void Shutdown();
private:
	//ゲームループのためのヘルパー関数群
	void ProcessInput();
	void UpdateGame();
	void GenerateOutput();

	//SDLが作るウィンドウ
	SDL_Window* mWindow;
	//2D描画のためのレンダリング
	SDL_Renderer* mRenderer;
	// Number of ticks since start of game
	Uint32 mTicksCount;
	//ゲームの続行を支持する
	bool mIsRunning;

	//Pong の詳細
	//パドルの方向
	std::vector<int> mPaddlesDir;
	//パドルの位置
	std::vector<Vector2> mPaddlesPos;
	//ボール
	std::vector<Ball> mBalls;

};

ゲームのための様々なフィールドと関数を持っています。ヘッダーファイルなので具体的なプログラムはGame.cppに書き込まれます。

Game.cpp

初期化・入力処理・ゲームループ・描画処理をするための具体的なプログラムが書き込まれます。

初期化

bool Game::Initialize() {
...
	// SDLレンダラーを作成
	mRenderer = SDL_CreateRenderer(
		mWindow,
		-1,
		SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
	);
...
}

初期化では、Game.hのフィールドを初期化しています。SDLで描画に必要なレンダラーを生成し、このオブジェクトを参照して画面に変化を起こしています。

入力処理

void Game::ProcessInput() {
	SDL_Event event;
	// キューにイベントがあれば繰り返す
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_QUIT:
			mIsRunning = false;
			break;
		default:
			break;
		}
	}
//その他ボタン処理
...
}

入力処理は、OSからのイベントを処理したり、ボタン入力を処理します。SDLではボタンを押す等のイベント(SDL_QUOT)をキューに入れるのでSDL_PollEvent(&SDL_Event)でとりだして処理します。

ゲームループ

main.cppでGame.Initialize()を終えてると、Game.RunLoop()がはじまります。

void Game::RunLoop() {
	while (mIsRunning) {
		ProcessInput();
		UpdateGame();
		GenerateOutput();
	}
}
void Game::UpdateGame() {
	//前のフレームから16msが経過するまで待つ
	while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16));

	// deltatimeは前のフレームとの時刻の差を秒に変換した値
	float deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f;

	//deltatimeを最大値で制限する
	if (deltaTime > 0.05f) {
		deltaTime = 0.05f;
	}
・・・
}

RunLoopでは入力とそれに基づいたゲーム情報の更新、出力を行います。また、更新では、プログラム全体のfpsをきめる、待機が存在します。16msの待機で1秒間に60回処理を行えるので60fpsになります。待機は前後フレームの秒数を参考にしており、これをデルタタイムと呼びます。

描画処理

void Game::GenerateOutput() {

	// 描画色を青色に設定
	SDL_SetRenderDrawColor(
		mRenderer,
		0, 0, 255, 255 // (R,G,B,A)
	);

	// バックバッファを青色で塗りつぶす
	SDL_RenderClear(mRenderer);

	// 描画色を白色に設定
	SDL_SetRenderDrawColor(mRenderer, 255, 255, 255, 255);
  // 壁を作成
	SDL_Rect wall{
		0,			// Top left x
		0,			// Top left y
		1024,		// width
		thickness	// height

	};
	SDL_RenderFillRect(mRenderer, &wall);
...
// バックバッファとフロントバッファを入れ替え
	SDL_RenderPresent(mRenderer);
}

バッファはコンピュータ内の画像情報です。画面に映すフロントバッファと、次のフレーム情報を書き込むバックバッファの2つを利用し、描画更新の最後にバッファを交換します。これはダブルバッファと呼ばれるゲームプログラムの基本です。

起動

ローカルデバッカーをクリック、もしくはデバック->デバックの開始するとゲームが起動します。

左のパドルはWとSキーで操作し、右のパドルはIとKキーで操作します。ボールを左もしくは右の画面端の壁にぶつかると自動で終了します。

改良版

これをもとに少し改良したバージョンをつくりました。

GitHub - kowara-gan/pongCpp: Pong in c++(SDL2)
Pong in c++(SDL2). Contribute to kowara-gan/pongCpp development by creating an account on GitHub.

ライセンス元

GitHub - gameprogcpp/code: Game Programming in C++ Code
Game Programming in C++ Code. Contribute to gameprogcpp/code development by creating an account on GitHub.

NEXT

コメント

タイトルとURLをコピーしました