はじめに

DrawPad は、プログラミング学習用の C++ フレームワークです。 むずかしい準備なしに、関数を1つ呼ぶだけで画面に絵が描けます。 C++ のクラスを知らなくても、C言語の関数を呼ぶ感覚でそのまま使えます。

難易度バッジについて

このマニュアルでは、すべての関数に難易度の目安を付けています。左のサイドバーのボタンで表示を絞り込めます。

🔰 初級最初に覚える基本機能。これだけで絵もアニメーションも作れます。
⭐ 中級ゲームらしい作品を作るときに使う機能(画像・音・時間など)。
🚀 上級表現や設計にこだわりたい人向けの機能。

最初のプログラム

DrawPad のプログラムは DrawMain() という関数を書くことから始まります。 main() は書きません(フレームワークが用意しています)。

#include <DrawPad.hpp>

void DrawMain()
{
    Clear(Color::White);                      // 画面を白でクリア
    FillCircle(0, 0, 100, Color::Orange);     // 画面中央にオレンジの円
    DrawText("Hello, DrawPad!", -80, -150, Color::Black);
}

描画関数を呼ぶと、その場ですぐ画面に反映されます。1行ずつ実行結果が見えるので、 「プログラムは上から順番に実行される」ことが目で確認できます。

座標系 — 画面の中央が (0, 0)

画面サイズは 800×600 ピクセル固定です。数学のグラフと同じように、 画面の中央が原点 (0, 0) で、右が +X、上が +Y です。

+X +Y (0, 0) (-400, 299) (399, 299) (-400, -300) (399, -300)
X は -400〜399、Y は -300〜299 の範囲が画面内です。

アニメーションの基本形 — バッチ描画

動く絵を作るには、「消す → 描く → 表示」を高速にくり返します。 ただし1つずつ画面に反映するとちらついて見えるので、 StartBatch()EndBatch() で囲んで「描き終わってからまとめて表示」します。

#include <DrawPad.hpp>

void DrawMain()
{
    double x = -400;
    while (true) {
        x += 2;                      // 少しずつ右へ
        if (x > 400) { x = -400; }   // 右端まで行ったら左へ戻す

        StartBatch();                // ここから画面には反映しない
        Clear(Color::SkyBlue);       //   前のフレームを消す
        FillCircle((int)x, 0, 30, Color::Red);
        EndBatch();                  // ここでまとめて画面に表示
    }
}
💡 この形がすべての基本です。「ループのたびに最初から描き直す」のが DrawPad(と多くのゲーム)の考え方です。画面更新は最大150fpsに自動調整されます(SetMaxFrameRate で変更できます)。

実行中にできること

ウィンドウタイトル現在の状態(Running / Pausing / Finished)と fps が表示されます。
Run メニューPause(一時停止 / 再開)、Step Over(一時停止中に1フレームだけ進める)、Reset(最初から実行し直す)が使えます。
スクリーンショット⌘C で画面をクリップボードにコピー。メニューからデスクトップへのPNG保存もできます。レポート作成に便利です。

逆引きリファレンス — やりたいことから探す

やりたいこと使う関数
画面全体を1色で塗りつぶしたいClear
線・丸・四角・三角を描きたいDrawLine, FillCircle, FillRect, FillRoundRect, FillTriangle
輪郭線だけ描きたいDrawCircle, DrawRect, DrawRoundRect, DrawTriangle
文字を表示したいDrawText, DrawTextAtCenter
絵文字をキャラクターとして使いたいDrawEmoji
画像ファイルを表示したいDrawImage
パラパラ漫画のようなコマ送りアニメをしたいDrawSprite
ちらつきをなくしたい・なめらかに動かしたいStartBatch / EndBatch
キーで動かしたい(押している間ずっと)CheckKey
キーを押した瞬間だけ反応させたい(ジャンプなど)CheckKeyDown
マウスの位置を知りたいGetMouseX / GetMouseY
クリックを検出したいCheckMouseDown
描画しないループで入力や終了操作を処理したいUpdateFrame
フレームレートを調べたい・上限を変えたいGetFrameRate, SetMaxFrameRate
効果音・BGMを鳴らしたいLoadAsset + PlaySound
ランダムな整数・小数が欲しいRandomInt, RandomDouble
値を範囲内に収めたい・補間したいClamp, Lerp, Map, SmoothStep
少し待ちたいSleep
経過時間を知りたい・時間で動きを制御したいGetTime, GetDeltaTime
半透明にしたいSetAlpha
図形の輪郭を滑らかにしたい(アンチエイリアス)SetAntiAlias
自分で色を作りたいColorRGB, ColorHSV, LerpColor
光っているような合成(加算合成など)をしたいSetBlendMode
画面のピクセルの色を調べたいGetColor
マップやデータをファイルから読み込みたいLoadAsset + ReadTextLines, LoadXML
画面の幅・高さを取得したいGetScreenWidth / GetScreenHeight
ウィンドウのタイトルを変えたいSetTitle
ベクトル計算をしたい(座標をまとめて扱う)vec2, rect

サンプルプログラム集

① キー入力でキャラクターを動かす

#include <DrawPad.hpp>

void DrawMain()
{
    int x = 0, y = 0;
    while (true) {
        if (CheckKey(Key::Left))  { x -= 3; }
        if (CheckKey(Key::Right)) { x += 3; }
        if (CheckKey(Key::Up))    { y += 3; }   // Yは上がプラス!
        if (CheckKey(Key::Down))  { y -= 3; }

        StartBatch();
        Clear(Color::Black);
        DrawEmoji("🚀", x, y, 64, 64);
        EndBatch();
    }
}

② ボールの反射(はね返り)

#include <DrawPad.hpp>

void DrawMain()
{
    double x = 0, y = 0;
    double vx = 4, vy = 3;          // 1フレームあたりの移動量

    while (true) {
        x += vx;
        y += vy;
        if (x < -380 || x > 379) { vx = -vx; }   // 左右の壁
        if (y < -280 || y > 279) { vy = -vy; }   // 上下の壁

        StartBatch();
        Clear(Color::MidnightBlue);
        FillCircle((int)x, (int)y, 20, Color::Orange);
        EndBatch();
    }
}
💡 この例の vxvy は「1フレームあたりの移動量」なので、フレームレートが変わると速さも変わります。 どのマシンでも同じ速さにしたいときは、GetDeltaTime を使って x += 240.0 * GetDeltaTime(); のように「1秒あたりの移動量」で書きます。

③ マウスでお絵かき

#include <DrawPad.hpp>

void DrawMain()
{
    Clear(Color::White);
    while (true) {
        if (CheckMouse()) {     // 左ボタンを押している間
            FillCircle(GetMouseX(), GetMouseY(), 5, Color::Black);
        }
        UpdateFrame();          // 画面・入力の更新(終了操作もここで効く。FAQ参照)
    }
}

④ 効果音つきのカウントゲーム

#include <DrawPad.hpp>

void DrawMain()
{
    LoadAsset("coin.mp3");      // ★ 音は最初に1回だけ読み込む
    int score = 0;
    char buf[64];

    while (true) {
        if (CheckKeyDown(Key::Space)) {   // 押した「瞬間」だけ true
            score++;
            PlaySound("coin.mp3");
        }

        StartBatch();
        Clear(Color::DarkSlateBlue);
        snprintf(buf, sizeof(buf), "SCORE: %d", score);
        DrawTextAtCenter(48, buf, 0, 0, Color::Gold);
        DrawTextAtCenter("Press SPACE", 0, -100, Color::White);
        EndBatch();
    }
}

⑤ スプライトシートで歩行アニメーション

#include <DrawPad.hpp>

// walk.png : 32x32 のコマが横に4枚並んだ画像(Assetsフォルダーに置く)
void DrawMain()
{
    while (true) {
        int frame = (int)(GetTime() * 8) % 4;   // 1秒間に8コマ進む

        StartBatch();
        Clear(Color::ForestGreen);
        DrawSprite("walk.png", 32, 32, frame, 0, 0, 0, 96, 96);  // 3倍に拡大表示
        EndBatch();
    }
}

図形の描画

色はすべて 0xRRGGBB 形式の整数、Color::Red などの色定数、または ColorRGB() / ColorHSV() などの色作成関数で指定します。 座標は画面中央が原点です。

Clear🔰 初級

void Clear(int color);

画面全体を指定した色で塗りつぶします。アニメーションでは毎フレームの最初に呼んで、前のフレームを消します。

引数説明
color塗りつぶす色(0xRRGGBB または Color:: 定数)
Clear(Color::SkyBlue);   // 空色で塗りつぶす
Clear(0x336699);         // 数値での指定もOK

Clear() には SetAlpha / SetBlendMode の効果はかかりません(常に不透明で塗りつぶします)。

DrawPoint🔰 初級

void DrawPoint(int x, int y, int color);
void DrawPoint(const vec2<int>& pos, int color);

指定した座標に1ピクセルの点を描画します。画面の範囲外を指定した場合は何も起きません。

引数説明
x, y点の座標
color描画色
// 点を散りばめて星空を作る
for (int i = 0; i < 200; i++) {
    DrawPoint(RandomInt(-400, 399), RandomInt(-300, 299), Color::White);
}

DrawLine🔰 初級

void DrawLine(int x1, int y1, int x2, int y2, int color, int thickness = 1);
void DrawLine(const vec2<int>& p1, const vec2<int>& p2, int color, int thickness = 1);

2点を結ぶ直線を描画します。

引数説明
x1, y1始点の座標
x2, y2終点の座標
color描画色
thickness線の太さ(省略時 1)
DrawLine(-400, 0, 399, 0, Color::Gray);          // 横軸
DrawLine(0, -300, 0, 299, Color::Gray);          // 縦軸
DrawLine(-100, -100, 100, 100, Color::Red, 5);   // 太さ5の斜め線

DrawRect🔰 初級

void DrawRect(int x, int y, int width, int height, int color, int thickness = 1);
void DrawRect(const vec2<int>& pos, const vec2<int>& size, int color, int thickness = 1);
void DrawRect(const rect<int>& r, int color, int thickness = 1);

四角形の輪郭線を描画します。(x, y)角の座標(中心ではありません)。 width はプラスで右方向、height はプラスで上方向に伸びます。

引数説明
x, y始点(角)の座標
width横の大きさ(マイナスなら左方向へ)
height縦の大きさ(マイナスなら下方向へ)
color描画色
thickness線の太さ(省略時 1)
DrawRect(-100, -50, 200, 100, Color::Lime, 3);   // 中央に200×100の枠

⚠ 円や画像は「中心」を指定しますが、四角形だけは「角」を指定します。中央に置きたいときは DrawRect(cx - w/2, cy - h/2, w, h, color) のように半分ずらしてください。

FillRect🔰 初級

void FillRect(int x, int y, int width, int height, int color);
void FillRect(const vec2<int>& pos, const vec2<int>& size, int color);
void FillRect(const rect<int>& r, int color);

四角形を塗りつぶします。座標の指定方法は DrawRect と同じです。

FillRect(-400, -300, 800, 60, Color::SaddleBrown);   // 画面下端に地面を描く

DrawRoundRect🔰 初級

void DrawRoundRect(int x, int y, int width, int height, int radius, int color, int thickness = 1);
void DrawRoundRect(const vec2<int>& pos, const vec2<int>& size, int radius, int color, int thickness = 1);
void DrawRoundRect(const rect<int>& r, int radius, int color, int thickness = 1);

角が丸い四角形の輪郭線を描画します。radius は角丸の半径です。座標の指定方法は DrawRect と同じです。

DrawRoundRect(-120, -50, 240, 100, 16, Color::White, 3);

FillRoundRect🔰 初級

void FillRoundRect(int x, int y, int width, int height, int radius, int color);
void FillRoundRect(const vec2<int>& pos, const vec2<int>& size, int radius, int color);
void FillRoundRect(const rect<int>& r, int radius, int color);

角が丸い四角形を塗りつぶします。座標の指定方法は DrawRect と同じです。

FillRoundRect(-150, -60, 300, 120, 20, Color::SteelBlue);

DrawTriangle🔰 初級

void DrawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color, int thickness = 1);
void DrawTriangle(const vec2<int>& p1, const vec2<int>& p2, const vec2<int>& p3, int color, int thickness = 1);

3点を結ぶ三角形の輪郭線を描画します。

引数説明
x1〜y33つの頂点の座標
color描画色
thickness線の太さ(省略時 1)

FillTriangle🔰 初級

void FillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color);
void FillTriangle(const vec2<int>& p1, const vec2<int>& p2, const vec2<int>& p3, int color);

3点を結ぶ三角形を塗りつぶします。

// 山を描く
FillTriangle(-200, -100, 0, 150, 200, -100, Color::ForestGreen);

DrawPolygon⭐ 中級

void DrawPolygon(const vec2<int> points[], int count, int color, int thickness = 1);
void DrawPolygon(const std::vector<vec2<int>>& points, int color, int thickness = 1);

任意の頂点数の多角形の輪郭線を描画します。頂点は順番に結ばれ、最後の頂点と最初の頂点も自動的に結ばれます。

引数説明
points頂点の配列またはvector(中心 (0,0) 基準)
count頂点数(配列版のみ)
color描画色
thickness線の太さ(省略時 1)
// 配列版(固定頂点数)
vec2<int> star[] = { {0,100}, {25,35}, {95,30}, {40,-15}, {60,-90},
                     {0,-50}, {-60,-90}, {-40,-15}, {-95,30}, {-25,35} };
DrawPolygon(star, 10, Color::Gold, 2);

// vector版(動的に頂点を組み立てる)
std::vector<vec2<int>> pts = { {-100,0}, {0,150}, {100,0} };
DrawPolygon(pts, Color::Cyan);

FillPolygon⭐ 中級

void FillPolygon(const vec2<int> points[], int count, int color);
void FillPolygon(const std::vector<vec2<int>>& points, int color);

任意の頂点数の多角形を塗りつぶします。頂点の並び順(時計回り/反時計回り)はどちらでも自動修正されます。

引数説明
points頂点の配列またはvector(中心 (0,0) 基準)
count頂点数(配列版のみ)
color描画色
// 五角形
vec2<int> pentagon[5];
for (int i = 0; i < 5; i++) {
    double a = M_PI / 2 + i * 2 * M_PI / 5;
    pentagon[i] = { (int)(100 * cos(a)), (int)(100 * sin(a)) };
}
FillPolygon(pentagon, 5, Color::MediumPurple);

凸多角形・凹多角形のどちらにも対応しています。自己交差するパスは正しく描画されない場合があります。

DrawCircle(円)🔰 初級

void DrawCircle(int cx, int cy, int radius, int color, int thickness = 1);
void DrawCircle(const vec2<int>& center, int radius, int color, int thickness = 1);

中心と半径を指定して、円の輪郭線を描画します。

引数説明
cx, cy中心の座標
radius半径(ピクセル)
color描画色
thickness線の太さ(省略時 1)
DrawCircle(0, 0, 150, Color::DeepPink, 4);

FillCircle(円)🔰 初級

void FillCircle(int cx, int cy, int radius, int color);
void FillCircle(const vec2<int>& center, int radius, int color);

中心と半径を指定して、円を塗りつぶします。ボールやキャラクターを描く定番の関数です。

FillCircle(0, 100, 40, Color::Yellow);    // 顔
FillCircle(-15, 110, 5, Color::Black);    // 左目
FillCircle( 15, 110, 5, Color::Black);    // 右目

DrawArc(円弧)⭐ 中級

void DrawArc(int cx, int cy, int radius, int color,
                double startAngleRad, double endAngleRad, int thickness = 1);
void DrawArc(const vec2<int>& center, int radius, int color,
                double startAngleRad, double endAngleRad, int thickness = 1);

開始角度と終了角度をラジアンで指定して、円弧(円の一部)を描画します。 角度0は右方向(+X方向)で、反時計回りに進みます。

引数説明
cx, cy中心の座標
radius半径
color描画色
startAngleRad開始角度(ラジアン)
endAngleRad終了角度(ラジアン)
thickness線の太さ(省略時 1)
#include <cmath>
DrawArc(0, 0, 100, Color::Cyan, 0.0, M_PI / 2);   // 第1象限の90度分の弧

⚠ 角度は内部で -π〜+π の範囲に変換されます(例: 0〜5/2π → 0〜1/2π と同じ扱い)。 開始角度と終了角度が同じ値のときは何も描画されません。

FillArc(扇形)⭐ 中級

void FillArc(int cx, int cy, int radius, int color,
                double startAngleRad, double endAngleRad);
void FillArc(const vec2<int>& center, int radius, int color,
                double startAngleRad, double endAngleRad);

開始角度と終了角度をラジアンで指定して、中心から円弧の両端を結んだ扇形を塗りつぶします。円グラフや残り時間ゲージに使えます。

#include <cmath>
// 残り時間を扇形で表示(残り75%の例)
double rate = 0.75;
FillArc(0, 0, 80, Color::Tomato, 0.0, 2 * M_PI * rate);

⚠ 開始角度と終了角度が同じ値のときは何も描画されません。円全体を塗りつぶしたいときは FillCircle() を使います。

DrawEllipse🔰 初級

void DrawEllipse(int cx, int cy, int radius_x, int radius_y, int color, int thickness = 1);
void DrawEllipse(const vec2<int>& center, const vec2<int>& radius, int color, int thickness = 1);

中心と縦横それぞれの半径を指定して、楕円の輪郭線を描画します。

引数説明
cx, cy中心の座標
radius_xX方向(横)の半径
radius_yY方向(縦)の半径

FillEllipse🔰 初級

void FillEllipse(int cx, int cy, int radius_x, int radius_y, int color);
void FillEllipse(const vec2<int>& center, const vec2<int>& radius, int color);

楕円を塗りつぶします。キャラクターの足元の影などに便利です。

FillEllipse(0, -80, 50, 12, Color::DarkGray);   // 影
DrawEmoji("🐱", 0, -40, 80, 80);               // その上にキャラ

GetColor⭐ 中級

int GetColor(int x, int y);
int GetColor(const vec2<int>& pos);

画面上の指定した座標のピクセルの色を取得します。「色を調べて当たり判定をする」といった使い方ができます。

戻り値: 0xRRGGBB 形式の色。画面の範囲外を指定すると 0(黒と同じ値)。

// マウス位置の色を調べる
int c = GetColor(GetMouseX(), GetMouseY());
if (c == Color::Red) {
    DrawText("RED!", 0, 250, Color::White);
}

バッチ処理(画面更新の制御)

StartBatch / EndBatch🔰 初級

void StartBatch();
void EndBatch();

ふだん描画関数は1回呼ぶたびに画面へ反映されますが、StartBatch() を呼ぶと反映を止め、 EndBatch()まとめて一度に画面へ反映します。

アニメーションでは必須です。理由は2つあります。

  • ちらつき防止: 「消した直後の画面」が見えなくなり、なめらかに見える。
  • 高速化: 画面反映は1回あたり数ミリ秒かかるため、図形をたくさん描くときはバッチでまとめないと極端に遅くなります。
while (true) {
    StartBatch();
    Clear(Color::Black);
    for (int i = 0; i < 100; i++) {
        FillCircle(i * 8 - 400, (int)(100 * sin(i * 0.2 + GetTime())), 5, Color::Aqua);
    }
    EndBatch();   // 100個の円がここで一度に表示される
}

EndBatch() を忘れると画面に何も表示されません。「真っ黒のまま動かない」ときはまずこれを疑ってください。

画像とスプライト

画像ファイルはプロジェクトの Assets フォルダーに入れておきます。PNG・JPEG など、macOS が読める形式に対応しています。 読み込みは自動で行われ、2回目以降はキャッシュされるので高速です。

DrawImage⭐ 中級

void DrawImage(const char *imageFileName, int cx, int cy,
               double angle = 0.0, bool flipX = false, int color = Color::White);
void DrawImage(const char *imageFileName, int cx, int cy, int width, int height,
               double angle = 0.0, bool flipX = false, int color = Color::White);
// vec2版: DrawImage(file, pos, ...) / DrawImage(file, pos, size, ...)

Assets フォルダー内の画像を、指定した座標を中心として描画します。 サイズを指定しない場合は画像の元の大きさで描画されます。

引数説明
imageFileNameAssets フォルダー内のファイル名(例: "player.png"
cx, cy描画の中心座標
width, height描画サイズ(ピクセル)。指定すると拡大縮小される
angle回転角度(ラジアン)。反時計回りが正。省略時 0
flipXtrue で左右反転。省略時 false
color色合い(ティント)。省略時は白(= 元の色のまま)。Color::Red などを指定すると画像にその色がかかる
DrawImage("player.png", 0, 0);                       // 等倍で中央に
DrawImage("player.png", 100, 50, 64, 64);            // 64×64に拡縮
DrawImage("player.png", 0, 0, 64, 64, GetTime());    // くるくる回転
DrawImage("player.png", 0, 0, 64, 64, 0, true);      // 左右反転(左向き→右向き)
DrawImage("player.png", 0, 0, 64, 64, 0, false, Color::Red);  // 赤くする(ダメージ表現)

⚠ ファイルが見つからないときは、エラーを表示してプログラムを終了します。ファイル名と置き場所(Assets フォルダー)を確認してください。 なお画像は LoadAsset なしでも初回描画時に自動で読み込まれますが、LoadAsset で先読みしておくと初回描画のひっかかりがなくなります。

DrawSprite⭐ 中級

void DrawSprite(const char *imageFileName, int frameWidth, int frameHeight,
                int column, int row, int cx, int cy,
                double angle = 0.0, bool flipX = false, int color = Color::White);
void DrawSprite(const char *imageFileName, int frameWidth, int frameHeight,
                int column, int row, int cx, int cy, int width, int height,
                double angle = 0.0, bool flipX = false, int color = Color::White);
// vec2版: DrawSprite(file, frameSize, frame, pos, ...) など

1枚の画像にコマが並んだ「スプライトシート」から、1コマを切り出して描画します。 切り出し位置は画像の左上を起点に (column × frameWidth, row × frameHeight) です。

引数説明
imageFileNameスプライトシート画像のファイル名
frameWidth / frameHeight1コマの幅・高さ(ピクセル)
column / row切り出すコマの列・行(0始まり
cx, cy描画の中心座標
width, height描画サイズ(省略時はコマの等倍)
angle / flipX / colorDrawImage と同じ
// 32×32のコマが横4枚並んだ walk.png をアニメーション
int frame = (int)(GetTime() * 8) % 4;
DrawSprite("walk.png", 32, 32, frame, 0, 0, 0);

文字と絵文字

DrawText🔰 初級

void DrawText(const char *str, int x, int y, int color);
void DrawText(int fontSize, const char *str, int x, int y, int color);
void DrawText(const char *str, const vec2<int>& pos, int color);
void DrawText(int fontSize, const char *str, const vec2<int>& pos, int color);

指定した座標に文字列を描画します。(x, y) は文字列の左下(ベースライン左端)の位置です。 フォントサイズを省略すると 18 ポイントになります。等幅フォントで描画されます。

引数説明
fontSizeフォントサイズ(ポイント)。省略時 18
str描画する文字列
x, y描画位置(文字列の左下あたり)
color描画色
DrawText("Hello!", -380, 260, Color::White);          // 画面左上に
DrawText(36, "BIG TEXT", -150, 0, Color::Yellow);     // 大きな文字

// 数値を表示したいときは snprintf で文字列にする
char buf[64];
snprintf(buf, sizeof(buf), "SCORE: %d", 1200);
DrawText(buf, -380, 220, Color::White);

DrawTextAtCenter🔰 初級

void DrawTextAtCenter(const char *str, int cx, int cy, int color, double angle = 0.0);
void DrawTextAtCenter(int fontSize, const char *str, int cx, int cy, int color, double angle = 0.0);
void DrawTextAtCenter(const char *str, const vec2<int>& pos, int color, double angle = 0.0);
void DrawTextAtCenter(int fontSize, const char *str, const vec2<int>& pos, int color, double angle = 0.0);

指定した座標が文字列の中心になるように描画します。タイトルやメッセージを画面中央に出すときに便利です。 回転角度(ラジアン)も指定できます。angle反時計回りが正です。

DrawTextAtCenter(64, "GAME OVER", 0, 50, Color::Red);
DrawTextAtCenter("Press SPACE to retry", 0, -50, Color::White);

DrawEmoji🔰 初級

void DrawEmoji(const char *emojiStr, int x, int y,
               double angle = 0.0, bool flipX = false);
void DrawEmoji(const char *emojiStr, int x, int y, int width, int height,
               double angle = 0.0, bool flipX = false);
void DrawEmoji(const char *emojiStr, const vec2<int>& pos,
               double angle = 0.0, bool flipX = false);
void DrawEmoji(const char *emojiStr, const vec2<int>& pos, const vec2<int>& size,
               double angle = 0.0, bool flipX = false);

絵文字を描画します。画像ファイルを用意しなくてもキャラクターが作れる、DrawPad の楽しい機能です。 絵文字は "🎈" のように文字列で渡します。

引数説明
emojiStr描画する絵文字
x, y描画の中心座標
width, height描画サイズ。省略すると約128ポイント相当のかなり大きいサイズになるので、ふつうはサイズ指定版を使う
angle回転角度(ラジアン)。反時計回りが正。省略時 0
flipXtrue で左右反転。省略時 false
DrawEmoji("🎈", 0, 100, 48, 48);                 // 48×48の風船
DrawEmoji("🐟", x, y, 64, 64, 0.0, true);        // 左右反転した魚
DrawEmoji("⭐", 0, 0, 80, 80, GetTime() * 2);    // 回る星

💡 一度描画した絵文字はキャッシュされるので、2回目以降は高速に描画されます。 サイズを毎フレーム少しずつ変えるアニメーション(拡大縮小演出など)でも、内部で適切にキャッシュが共有されるため、安心して使えます。

GetTextSize⭐ 中級

vec2<int> GetTextSize(const char *str);
vec2<int> GetTextSize(int fontSize, const char *str);

文字列を描画したときの幅と高さを返します。フォントサイズを省略すると 18 になります。 右寄せ・中央揃え・吹き出しの幅合わせなど、テキストのレイアウトに使います。

戻り値: 幅と高さの入った vec2<int>.x が幅、.y が高さ)

// 右端に右寄せで描画する
vec2<int> sz = GetTextSize("Score: 999");
DrawText("Score: 999", 399 - sz.x, 290, Color::White);

// フォントサイズを指定する場合
vec2<int> sz2 = GetTextSize(32, "GAME OVER");

GetEmojiSize⭐ 中級

vec2<int> GetEmojiSize(const char *emojiStr);

絵文字をサイズ無指定(128ポイント相当)で描画したときの幅と高さを取得します。

戻り値: 幅と高さの入った vec2<int>.x が幅、.y が高さ)

半透明と合成

SetAlpha⭐ 中級

void SetAlpha(double alpha);

これ以降の描画の不透明度を設定します。0.0(完全に透明)〜 1.0(不透明)。 設定は変更するまでずっと有効なので、使い終わったら 1.0 に戻すのを忘れずに。

引数説明
alpha不透明度 0.0〜1.0(範囲外は自動的に丸められる)
SetAlpha(0.3);
FillCircle(0, 0, 100, Color::Red);    // 30%の濃さの赤い円
SetAlpha(1.0);                        // ★ 必ず戻す

Clear() には効きません。

SetAntiAlias⭐ 中級

void SetAntiAlias(bool enabled);

図形描画時のアンチエイリアス(輪郭を滑らかにする処理)のON/OFFを切り替えます。デフォルトは ON(有効)です。 OFF にすると斜め線や円の輪郭がピクセル単位のカクカクした描画になり、ピクセルアートやレトロゲーム風の表現に向きます。

引数説明
enabledtrue でアンチエイリアスON(デフォルト)、false でOFF
SetAntiAlias(false);
FillCircle(0, 0, 100, Color::Red);    // 輪郭がカクカクしたレトロ風の円
SetAntiAlias(true);                   // 元(滑らか)に戻す

SetBlendMode🚀 上級

void SetBlendMode(BlendMode mode);

これ以降の描画の合成方法(ブレンドモード)を設定します。Photoshop のレイヤー合成と同じ考え方です。 使えるモードはBlendMode 一覧を参照してください。デフォルトは BlendMode::Normal です。

SetBlendMode(BlendMode::PlusLighter);          // 加算合成(光の表現)
FillCircle(-20, 0, 60, Color::Red);
FillCircle( 20, 0, 60, Color::Blue);           // 重なりが明るく光る
SetBlendMode(BlendMode::Normal);               // ★ 必ず戻す

色定数一覧(Color::)

HTMLの標準色に基づく141色が定義されています。クリックするとコード(Color::名前)をコピーできます。

💡 定数にない色は 0xRRGGBB 形式の16進数で自由に作れます。 例: 0xFF8040(R=FF, G=80, B=40)。Webの「カラーピッカー」で調べた値がそのまま使えます。 RGB値や色相(HSV)から動的に色を作りたいときは、下の ColorRGB() / ColorHSV() も使えます。

ColorRGB / ColorHSV / LerpColor⭐ 中級

int ColorRGB(double r, double g, double b);
int ColorHSV(double h, double s, double v);
int LerpColor(int c1, int c2, double t);

色を作ったり、2つの色を混ぜたりします。戻り値は Color::Red などと同じ 0xRRGGBB 形式の色です。

関数引数
ColorRGBr, g, b は赤・緑・青の強さ。0.01.0
ColorHSVh は色相(度、0〜360で一周)、s は鮮やかさ、v は明るさ。s, v0.01.0
LerpColort は混ぜ具合。0.0c11.0c2
FillCircle(-120, 0, 40, ColorRGB(1.0, 0.4, 0.0));       // オレンジ
FillCircle(0, 0, 40, ColorHSV(GetTime() * 60, 1.0, 1.0)); // 虹色に変化
FillCircle(120, 0, 40, LerpColor(Color::Red, Color::Blue, 0.5));

範囲外の値は安全な範囲に丸められます。ColorHSVh は 360 度ごとに一周します。

BlendMode 一覧

SetBlendMode() で指定できる合成モードです。まずは ★ 付きのよく使うものから試してみてください。

モード効果
Normal通常の描画(デフォルト)
PlusLighter加算合成。重なるほど明るく光る。炎・光・魔法エフェクトの定番
Multiply乗算。重なるほど暗くなる。影・夜の表現
Screenスクリーン。重なると明るくなる(加算よりおだやか)
Overlayオーバーレイ(明るい所はより明るく、暗い所はより暗く)
Darken / Lighten暗い方/明るい方の色を採用
ColorDodge / ColorBurn覆い焼き/焼き込み
SoftLight / HardLightソフトライト/ハードライト
Difference / Exclusion差の絶対値/除外(ネガポジ反転風)
Hue / Saturation / Color / Luminosity色相/彩度/カラー/輝度の合成
PlusDarker加算の逆(暗くなる方向に加算)
Clear / Copy / Xor /
SourceIn / SourceOut / SourceAtop /
DestinationOver / DestinationIn / DestinationOut / DestinationAtop
Porter-Duff 合成(マスク処理などの特殊用途。上級者向け)

キーボード入力

キーは Key::AKey::Space などの定数で指定します。 複数キーは | でまとめて判定できます。

CheckKey🔰 初級

bool CheckKey(std::uint64_t key);

指定したキーがいま押されているかを調べます。押している間ずっと true になるので、 「押している間、動き続ける」という移動処理に向いています。

戻り値: 押されていれば true

if (CheckKey(Key::Right)) { x += 3; }            // 右キーで移動
if (CheckKey(Key::Space | Key::Up)) { jump(); }  // スペースまたは上キー

CheckKeyDown⭐ 中級

bool CheckKeyDown(std::uint64_t key);

指定したキーが押された瞬間かどうかを調べます。押しっぱなしにしても、true になるのは押した直後の1フレームだけです。 ジャンプ・決定ボタン・弾の発射など、「1回押したら1回だけ反応」させたい処理に使います。

戻り値: 直前のフレームで押されていなくて、今のフレームで押されていれば true

if (CheckKeyDown(Key::Space)) {
    score++;          // 押しっぱなしでも1回しか増えない
}

⚠ 「瞬間」の判定は、次の入力更新タイミングまで同じ結果が残ります。 EndBatchClear()Sleep()UpdateFrame() のどれかを1ループに1回呼んでください。 アニメーションやゲームでは StartBatch / EndBatch で「1ループ = 1フレーム」の形にすると扱いやすくなります。

CheckKeyUp⭐ 中級

bool CheckKeyUp(std::uint64_t key);

指定したキーが離された瞬間かどうかを調べます。「ボタンを離したら発射」のようなタメ撃ち表現に使えます。

戻り値: 直前のフレームで押されていて、今のフレームで離されていれば true

KeyFlagToName🚀 上級

std::string KeyFlagToName(std::uint64_t keyFlag);

キー定数を "A""Space" のような名前の文字列に変換します。デバッグ表示に便利です。 複数のキーを含む場合は "A|B" のように連結されます。

キー定数一覧(Key::)

分類定数
アルファベットKey::AKey::Z
数字Key::Num0Key::Num9
矢印キーKey::Up / Key::Down / Key::Left / Key::Right
修飾キーKey::Shift / Key::Control / Key::Option
その他Key::Return(Enter) / Key::Space / Key::Escape / Key::Backspace / Key::Delete / Key::Tab

複数のキーは | で組み合わせられます: CheckKey(Key::W | Key::Up)(WキーまたはUpキー)。

マウス入力

GetMouseX / GetMouseY / GetMousePos🔰 初級

int GetMouseX();
int GetMouseY();
vec2<int> GetMousePos();

マウスカーソルの現在位置を取得します。座標系は描画と同じ(画面中央が原点、右と上がプラス)です。

戻り値: X座標 / Y座標(GetMousePos() は両方をまとめた vec2<int>

// マウスに追従する円
StartBatch();
Clear(Color::Black);
FillCircle(GetMouseX(), GetMouseY(), 20, Color::Lime);
EndBatch();

CheckMouse / CheckMouseMiddle / CheckMouseRight🔰 初級

bool CheckMouse();         // 左ボタン
bool CheckMouseMiddle();   // 中央ボタン
bool CheckMouseRight();    // 右ボタン

マウスのボタンがいま押されているかを調べます。押している間ずっと true です。

if (CheckMouse()) {
    FillCircle(GetMouseX(), GetMouseY(), 5, Color::Black);   // ドラッグでお絵かき
}

CheckMouseDown / CheckMouseDownMiddle / CheckMouseDownRight⭐ 中級

bool CheckMouseDown();         // 左ボタンが押された瞬間
bool CheckMouseDownMiddle();   // 中央ボタンが押された瞬間
bool CheckMouseDownRight();    // 右ボタンが押された瞬間

ボタンが押された瞬間だけ true になります。「クリックしたらそこに何かを置く」ような処理に使います。 判定の仕組みと注意点は CheckKeyDown と同じです。

if (CheckMouseDown()) {
    balloonX = GetMouseX();   // クリックした場所に風船を移動
    balloonY = GetMouseY();
}

CheckMouseUp / CheckMouseUpMiddle / CheckMouseUpRight⭐ 中級

bool CheckMouseUp();         // 左ボタンが離された瞬間
bool CheckMouseUpMiddle();   // 中央ボタンが離された瞬間
bool CheckMouseUpRight();    // 右ボタンが離された瞬間

ボタンが離された瞬間だけ true になります。ドラッグ&ドロップの「ドロップ」の検出などに使います。

GetMouseWheelV / GetMouseWheelH / GetMouseWheel🚀 上級

double GetMouseWheelV();      // 縦方向のスクロール量
double GetMouseWheelH();      // 横方向のスクロール量
vec2<double> GetMouseWheel(); // 両方まとめて

マウスホイール(トラックパッドの2本指スクロール)の移動量を取得します。 値の符号はスクロール方向を表します(macOSの「ナチュラルなスクロール」設定によって向きが変わります)。

値は直前のフレームからスクロールした量です。スクロールしていないフレームでは 0 になります。

SetMouseCursorHidden / IsMouseCursorHidden🚀 上級

void SetMouseCursorHidden(bool hidden);
bool IsMouseCursorHidden();

マウスカーソルの表示/非表示を切り替えます。自作の照準カーソルを表示するゲームなどで使います。

SetMouseCursorHidden(true);                          // OSのカーソルを隠す
DrawEmoji("🎯", GetMouseX(), GetMouseY(), 48, 48);  // 代わりに照準を描く

時間

Sleep🔰 初級

void Sleep(double seconds);

指定した秒数だけプログラムを止めます。描画の途中経過をゆっくり見せたいときに便利です。

引数説明
seconds待つ秒数(例: 0.5 で0.5秒)
for (int i = 0; i < 10; i++) {
    FillCircle(i * 60 - 270, 0, 25, Color::Tomato);
    Sleep(0.3);   // 0.3秒ごとに1個ずつ円が増えていく
}

⚠ 関数名は大文字の Sleep() です。小文字の sleep() はC言語の標準ライブラリーにある別の関数なので、DrawPadで待ち時間を入れるときは先頭を大文字にしてください。

UpdateFrame⭐ 中級

void UpdateFrame();

描画や Clear() を行わないループで、1フレーム分の画面更新・速度調整・入力更新を行います。 バッチ処理中は入力の更新のみ行います。

while (true) {
    if (CheckKeyDown(Key::Space)) {
        // スペースが押された瞬間だけ実行
    }
    UpdateFrame();
}

GetTime⭐ 中級

double GetTime();

プログラムの実行開始からの経過秒数を返します。時間に応じた動き(波・回転・点滅・制限時間)の基本です。

戻り値: 実行開始からの秒数

#include <cmath>
double t = GetTime();
int y = (int)(100 * sin(t * 2));            // 上下にゆれる
FillCircle(0, y, 30, Color::Violet);

if ((int)(t * 4) % 2 == 0) {                // 点滅
    DrawTextAtCenter("PUSH START", 0, -200, Color::White);
}

GetDeltaTime⭐ 中級

double GetDeltaTime();

前のフレームから今のフレームまでの経過秒数を返します。 「1フレームあたり◯ピクセル」ではなく「1秒あたり◯ピクセル」で動きを書くと、 パソコンの速さに関係なく同じ速度で動くプログラムになります。

戻り値: 前フレームからの経過秒数

double speed = 200.0;               // 1秒あたり200ピクセル
x += speed * GetDeltaTime();        // フレームレートが変わっても同じ速さ

GetFrameRate⭐ 中級

double GetFrameRate();

現在のフレームレート(fps)を返します。パフォーマンスの確認やデバッグ表示に使えます。

戻り値: 現在のフレームレート(fps)

char buf[32];
snprintf(buf, sizeof(buf), "%.0f fps", GetFrameRate());
DrawText(buf, -390, 270, Color::White);

Windows版は整数精度(小数なし)です。

SetMaxFrameRate⭐ 中級

void SetMaxFrameRate(double fps);

フレームレートの上限を設定します。デフォルトは150fpsです。0以下を指定すると上限なし(最大速度)になります。

引数説明
fpsフレームレートの上限値(fps)。0以下で上限なし。
SetMaxFrameRate(30);    // 30fps上限(スローモーション演出など)
SetMaxFrameRate(60);    // 60fps上限
SetMaxFrameRate(0);     // 上限なし(最大速度)

Windows版はV-Syncを無効にしてソフトウェア制御でfpsを制限します。上限なし(0以下)を指定するとV-Syncが再び有効になります。

ウィンドウと実行制御

GetScreenWidth / GetScreenHeight🔰 初級

int GetScreenWidth();    // 800 を返す
int GetScreenHeight();   // 600 を返す

画面の幅と高さをピクセル単位で返します。DrawPad の画面は常に 800×600 です。

定数としてもアクセスできます。

// 定数(変数の代わりに直接使える)
kScreenWidth      // 800  — 画面幅
kScreenHeight     // 600  — 画面高さ
kScreenHalfWidth  // 400  — 画面幅の半分(原点から右端まで)
kScreenHalfHeight // 300  — 画面高さの半分(原点から上端まで)
// 画面端に触れたら跳ね返る
if (x < -GetScreenWidth() / 2 || x >= GetScreenWidth() / 2) {
    vx = -vx;
}

// 定数を使って同じことを書く場合
if (x < -kScreenHalfWidth || x >= kScreenHalfWidth) {
    vx = -vx;
}

DrawPadの座標系は画面中央が原点です。X座標の範囲は -400399、Y座標は -300299 です(kScreenHalfWidth / kScreenHalfHeight が境界値になります)。

SetTitle⭐ 中級

void SetTitle(const char *title);

ウィンドウのタイトルを設定します。日本語も使えます(UTF-8)。タイトルの後ろには実行状態と fps が自動で表示されます。

SetTitle("ぼくのシューティングゲーム");

IsRunning / IsFinished⭐ 中級

bool IsRunning();    // 実行中なら true
bool IsFinished();   // 終了しようとしていたら true

プログラムが終了(Quit / Reset)しようとしているかどうかを調べます。 while (true) の代わりに while (IsRunning()) と書くと、終了処理を自分で書きたいときに便利です。

while (IsRunning()) {
    StartBatch();
    Clear(Color::Black);
    // …
    EndBatch();
}
// ここに終了前の後片付けを書ける

💡 ふだんは while (true) でも問題ありません。描画関数や Sleep() を呼んだタイミングで、フレームワークが自動的に終了処理をしてくれます。

アセットの読み込み

LoadAsset🔰 初級

void LoadAsset(const char *filename);

Assets フォルダーからファイルを読み込みます。拡張子で自動的に種類を判別します。

  • 音声ファイル(.mp3 .wav .m4a .aac .aif .aiff .caf .flac .ogg)→ サウンドとして読み込み、PlaySound で再生できるようになる
  • 画像ファイル(.png .jpg .jpeg .bmp .gif .tif .tiff .webp)→ 画像として事前に読み込む(DrawImage は LoadAsset なしでも使用できます)
  • それ以外(.txt .csv .json など)→ テキストとして読み込み、ReadText / ReadTextLines で参照できるようになる
引数説明
filenameAssets フォルダー内のファイル名
void DrawMain()
{
    // ★ 読み込みは DrawMain の最初に、1回だけ行う
    LoadAsset("bgm.mp3");
    LoadAsset("jump.wav");
    LoadAsset("stage1.txt");

    PlaySound("bgm.mp3", true);   // BGMをループ再生
    // …ゲーム本体…
}

LoadAsset() を忘れて PlaySound()ReadText() を呼ぶと、エラーを表示してプログラムを終了します。 DrawMain の最初で、使う音声ファイルやテキストファイルを先に読み込んでください。

サウンド

すべてのサウンド関数は、事前に LoadAsset() で読み込んだファイルに対してだけ動作します。読み込んでいないファイルを指定すると、エラーを表示してプログラムを終了します。

PlaySound🔰 初級

void PlaySound(const char *filename, bool loop = false);

サウンドを最初から再生します。再生中にもう一度呼ぶと、頭から再生し直します。

引数説明
filenameLoadAsset 済みのファイル名
looptrue でループ再生(BGM向け)。省略時 false(1回だけ。効果音向け)
PlaySound("bgm.mp3", true);    // BGM: ループ再生
PlaySound("jump.wav");         // 効果音: 1回だけ

StopSound / PauseSound⭐ 中級

void StopSound(const char *filename);    // 停止して先頭に戻す
void PauseSound(const char *filename);   // その場で一時停止

StopSound() は再生を止めて曲の先頭に戻します。PauseSound() はその場で一時停止します。

⚠ 現在のAPIには「一時停止した位置から再開する」関数はありません。PauseSound() のあとに PlaySound() を呼ぶと、先頭からの再生になります。

IsSoundPlaying⭐ 中級

bool IsSoundPlaying(const char *filename);

指定したサウンドが再生中かどうかを調べます。

戻り値: 再生中なら true

if (!IsSoundPlaying("bgm.mp3")) {
    PlaySound("bgm.mp3");    // 止まっていたら再生し直す
}

SetSoundVolume / SetSoundPan / SetSoundSpeed🚀 上級

void SetSoundVolume(const char *filename, double volume);   // 音量 0.0〜1.0
void SetSoundPan(const char *filename, double pan);          // 左右バランス -1.0〜1.0
void SetSoundSpeed(const char *filename, double speed);      // 再生速度 0.5〜2.0

サウンドの音量・左右バランス・再生速度を変更します。再生中でも効果があります。

引数説明
volume0.0(無音)〜 1.0(最大)。範囲外は自動で丸められる
pan-1.0(左だけ)〜 0(中央)〜 1.0(右だけ)。範囲外は自動で丸められる
speed0.5(半分の速さ)〜 2.0(倍速)。範囲外は自動で丸められる(AVAudioPlayer の仕様上限)
SetSoundVolume("bgm.mp3", 0.3);                       // BGMを小さめに
SetSoundPan("shot.wav", GetMouseX() / 400.0);         // 撃った位置から聞こえる

テキスト・XMLデータ

ReadText / ReadTextLines⭐ 中級

std::string ReadText(const char *filename);
std::vector<std::string> ReadTextLines(const char *filename);

LoadAsset() で読み込んでおいたテキストファイルの内容を取得します。 ReadText() はファイル全体を1つの文字列で、ReadTextLines() は1行ずつの配列で返します (改行コード \n / \r\n / \r すべてに対応。各行に改行文字は含まれません)。

戻り値: ファイルの内容。LoadAsset していない場合はエラーを表示して終了します。

LoadAsset("stage1.txt");
auto lines = ReadTextLines("stage1.txt");

// 「#」を壁として描く簡易マップ表示
for (int row = 0; row < (int)lines.size(); row++) {
    for (int col = 0; col < (int)lines[row].size(); col++) {
        if (lines[row][col] == '#') {
            FillRect(col * 32 - 400, 268 - row * 32, 32, 32, Color::Gray);
        }
    }
}

LoadXML / XMLElement🚀 上級

std::shared_ptr<XMLElement> LoadXML(const char *filename);

struct XMLElement {
    std::string name;                                   // タグ名
    std::string text;                                   // テキスト内容
    std::map<std::string, std::string> attributes;      // 属性
    std::vector<std::shared_ptr<XMLElement>> children;  // 子要素

    bool        HasAttribute(const std::string& key) const;
    std::string GetAttribute(const std::string& key, const std::string& def = "") const;
    int         GetAttributeInt(const std::string& key, int def = 0) const;
    double      GetAttributeDouble(const std::string& key, double def = 0.0) const;
    bool        GetAttributeBool(const std::string& key, bool def = false) const;
    std::string GetChildText(const std::string& name, const std::string& def = "") const;
    int         GetChildInt(const std::string& name, int def = 0) const;
    double      GetChildDouble(const std::string& name, double def = 0.0) const;
    bool        GetChildBool(const std::string& name, bool def = false) const;
    std::shared_ptr<XMLElement> FirstChild() const;
    std::shared_ptr<XMLElement> FirstChild(const std::string& name) const;
    std::shared_ptr<XMLElement> NextSibling() const;
};

Assets フォルダーから XML ファイルを読み込んで、要素ツリーとして返します。ゲームの設定ファイルやステージデータの管理に使えます。

戻り値: ルート要素。読み込み・解析に失敗した場合は nullptr

// config.xml:  <game name="MyGame"><hp>100</hp></game>
auto root = LoadXML("config.xml");
if (root) {
    std::string name = root->GetAttribute("name", "untitled");
    int hp = root->GetChildInt("hp", 100);
}

数学ユーティリティ

値を範囲内に収めたり、なめらかに補間したりする関数と、座標や範囲をまとめて扱うためのテンプレート構造体です。多くの描画・入力関数には、 個別の int x, int y 版に加えてこれらを受け取るオーバーロードが用意されています。

範囲と補間の関数🔰 初級

int Sign(int value);
int Sign(double value);

double Clamp(double value, double min, double max);
int Clamp(int value, int min, int max);
double Clamp01(double value);

double Lerp(double a, double b, double t);
int LerpInt(int a, int b, double t);

double InverseLerp(double a, double b, double value);
double Map(double value,
           double inMin, double inMax,
           double outMin, double outMax);
double MapClamped(double value,
                  double inMin, double inMax,
                  double outMin, double outMax);

double SmoothStep(double a, double b, double t);

double EaseIn(double t);
double EaseOut(double t);
double EaseInOut(double t);
double EaseInQuad(double t);
double EaseOutQuad(double t);
double EaseInOutQuad(double t);

double MoveTowards(double current, double target, double maxDelta);
double Repeat(double value, double length);
double PingPong(double value, double length);

double DegToRad(double degrees);
double RadToDeg(double radians);
double NormalizeAngleDeg(double angle);
double NormalizeAngleRad(double angle);

Clamp は値を範囲内に収めます。Lerp は2つの値の間を補間し、Map はある範囲の値を別の範囲へ変換します。MoveTowardsRepeat は、一定速度の移動やくり返しアニメーションに便利です。

関数用途
Clamp値を min 以上 max 以下に収める
Clamp01値を 0.0 以上 1.0 以下に収める
Lerpt=0.0at=1.0b になる線形補間
LerpInt整数版の線形補間。結果は四捨五入される
InverseLerp値が範囲内のどの割合にあるかを求める
Map入力範囲の値を出力範囲へ変換する
MapClamped入力値を範囲内に収めてから変換する
SmoothStep0.0〜1.0の t を使ってなめらかに補間する
EaseInゆっくり始まってだんだん速くなる割合を返す
EaseOut速く始まってだんだんゆっくり止まる割合を返す
EaseInOut始まりと終わりがゆっくりになる割合を返す
EaseInQuad / EaseOutQuad / EaseInOutQuad2次関数を使ったイージング。EaseIn などの基本形と同じ
Sign負なら -1、0なら 0、正なら 1 を返す
MoveTowards現在値を目標値へ、1回あたり最大 maxDelta だけ近づける
Repeat値を 0.0 以上 length 未満の範囲で繰り返す
PingPong0.0 → length → 0.0 を往復する値を作る
DegToRad / RadToDeg度数法とラジアンを変換する
NormalizeAngleDeg角度を 0.0 以上 360.0 未満に収める
NormalizeAngleRad角度を 0.0 以上 未満に収める
double t = Clamp01(GetMouseX() / 600.0);
double x = Lerp(-250.0, 250.0, EaseInOut(t));
double size = MapClamped(GetMouseY(), -200.0, 200.0, 20.0, 100.0);

double y = PingPong(GetTime() * 120.0, 180.0) - 90.0;
FillCircle(x, y, size, Color::DeepSkyBlue);

InverseLerpMap は範囲外の値もそのまま割合として扱います。0.0〜1.0に収めたい場合は Clamp01 または MapClamped を使います。

vec2<T>🚀 上級

template <typename T> struct vec2 {
    T x, y;

    vec2();                       // (0, 0)
    vec2(T x, T y);

    // 演算子: + - * / += -= *= /= == !=  (* と / はスカラー値と)
    void Add(const vec2<T>& v);          // 加算(+= と同じ)
    vec2<T> Center() const;              // (x/2, y/2)
    T Dot(const vec2<T>& v) const;       // 内積
    T Cross(const vec2<T>& v) const;     // 外積(2Dなのでスカラー)
    double Length() const;               // ベクトルの長さ
    double LengthSquared() const;        // 長さの2乗(高速・比較用)
    double Distance(const vec2<T>& v) const;          // 2点間の距離
    double DistanceSquared(const vec2<T>& v) const;   // 距離の2乗
    vec2<double> Normalized() const;     // 長さ1に正規化したベクトル
};

2次元ベクトル。座標・速度・大きさなどを1つの変数で扱えます。vec2<int>vec2<double> のように型を指定して使います。

vec2<double> pos(0, 0);
vec2<double> vel(3, 2);
pos += vel;                                  // 位置を速度ぶん進める

// プレイヤーとの距離で当たり判定
if (pos.Distance(playerPos) < 30.0) { hit(); }

// マウスの方向へ速度100で進む
vec2<double> dir = (vec2<double>(GetMousePos()) - pos).Normalized();
pos += dir * (100.0 * GetDeltaTime());

/ 演算子は0で割ろうとすると例外(std::runtime_error)を投げます。

rect<T>🚀 上級

template <typename T> struct rect {
    T x, y, width, height;

    rect();
    rect(T x, T y, T width, T height);
    rect(const vec2<U>& pos, const vec2<U>& size);

    static rect<T> FromEdges(T left, T top, T right, T bottom);
    bool Intersects(const rect<T>& other) const;   // 重なっているか
};

矩形(四角形の範囲)。Intersects() で矩形同士の重なり判定ができるので、簡単な当たり判定に使えます。 DrawRect / FillRect にそのまま渡せます。

rect<int> player(x - 16, y - 16, 32, 32);
rect<int> enemy(ex - 20, ey - 20, 40, 40);

if (player.Intersects(enemy)) {
    DrawTextAtCenter(48, "HIT!", 0, 0, Color::Red);
}
FillRect(player, Color::Aqua);   // rect をそのまま描画にも使える

乱数

実行するたびに違う結果を出したいときに使います。シードを固定すれば、デバッグ用に毎回同じ乱数列を再現できます。

DrawPadの乱数はPCG32アルゴリズムを使用しています。C/C++の標準ライブラリーにある一般的な乱数関数よりも高速で、ゲームやアニメーションでも軽快に使えます。

RandomInt🔰 初級

int RandomInt(int min, int max);

min以上max以下の整数をランダムに返します(両端を含む)。

引数説明
min最小値(含む)
max最大値(含む)

戻り値: min以上max以下の整数

int x = RandomInt(-400, 399);      // 画面内のX座標をランダムに決める
int y = RandomInt(-300, 299);      // 画面内のY座標をランダムに決める
int dice = RandomInt(1, 6);        // サイコロ(1〜6)

RandomDouble🔰 初級

double RandomDouble();
double RandomDouble(double min, double max);

引数なしの場合は0.0以上1.0未満の小数を返します。引数を指定するとmin以上max未満の範囲で返します。

引数説明
(なし)0.0以上1.0未満の乱数
min, max最小値(含む)〜最大値(含まない)の乱数
double r = RandomDouble();              // 0.0 以上 1.0 未満
double angle = RandomDouble(0.0, 360.0);  // 0〜360度のランダムな角度

CreateRandomSeed⭐ 中級

uint64_t CreateRandomSeed();

実行するたびに異なるランダムなシード値を生成して返します。 SetRandomSeed() と組み合わせることで、「今回のゲームで使ったシードを保存して後で同じマップを再現する」といった使い方ができます。

戻り値: ランダムに生成された64ビットのシード値

// ゲーム開始時にシードを生成して記録
uint64_t seed = CreateRandomSeed();
SetRandomSeed(seed);

// ステージやマップの生成
int mapData = RandomInt(1, 100);

// seed を表示しておくと、同じステージを後で再現できる

同じseedを SetRandomSeed() に渡すと、Mac版・Windows版を問わず同じ乱数列が再現されます。

SetRandomSeed⭐ 中級

void SetRandomSeed(uint64_t seed);

乱数のシードを設定します。同じseedを渡すと、常に同じ乱数列が生成されます。 Mac版・Windows版で同じseedを使えば同じ乱数列になります。 デバッグや再現テストに便利です。

引数説明
seedシード値(任意の整数)
SetRandomSeed(12345);               // シードを固定
int a = RandomInt(1, 100);          // 毎回同じ値になる
int b = RandomInt(1, 100);          // こちらも毎回同じ値
SetRandomSeed(12345);               // 同じシードに戻すと同じ列が再現される

シードを設定しない場合は起動のたびに自動的に異なるシードが選ばれます。

FAQ・つまずきポイント

Q. 音が鳴らない

PlaySound() の前に LoadAsset() を呼びましたか? LoadAsset していないファイルの PlaySound は、エラーを表示してプログラムを終了します。LoadAsset は DrawMain の最初に1回だけ書きます。 ファイル名のスペルミス、Assets フォルダーに入っているかも確認してください。

Q. 画面がちらつく/たくさん描くと遅い

StartBatch() / EndBatch() で1フレームぶんの描画を囲んでください。 バッチを使わない場合、描画関数1回ごとに画面更新(数ミリ秒)が走るため、図形の数が増えると目に見えて遅くなります。

Q. CheckKeyDown / CheckMouseDown がうまく反応しない

→ 「押した瞬間」の判定は、次の入力更新タイミングまで同じ結果が残ります。 EndBatch()Clear()Sleep()UpdateFrame() のどれかを1ループに1回呼んでください。 バッチ描画のゲームなら 「1ループ = StartBatch〜EndBatch が1回」、クリックしたときだけ描くペイントならループ末尾に UpdateFrame() を書くのが基本です。

Q. 画像・絵文字が表示されない

→ 画像はファイル名の打ち間違い・Assets フォルダーへの入れ忘れが原因のほとんどです(その場合はエラーが表示されてプログラムが終了するので、メッセージのファイル名を確認してください)。 絵文字は "🎈" のような文字列で指定します。

Q. 何も表示されず真っ黒のまま

EndBatch() を忘れていませんか? StartBatch() のあと EndBatch を呼ぶまで、画面には一切反映されません。

Q. Reset や Quit が効かない・ウィンドウが固まる

→ DrawPad は描画関数・Sleep()UpdateFrame() を呼んだタイミングで停止要求をチェックします。 これらを1つも呼ばないループ(計算だけのループや、条件付きでしか描画しないループ)があると、停止できなくなります。 そのようなループには UpdateFrame() を入れておきましょう(サンプル③参照)。

Q. キャラが上に動くはずなのに下に動く

→ DrawPad の Y 軸は数学と同じく上がプラスです(画面系のライブラリには下がプラスのものも多いので混乱しがち)。 「上に移動」は y += 速度 です。

Q. ウィンドウの大きさを変えたい

→ 画面サイズは 800×600 固定です(X: -400〜399、Y: -300〜299)。