アナログスティックを使って、画面上のカーソルを自由に動かしてみましょう。
これまで学んできたセンサや表示のしくみを組み合わせることで、
いよいよゲームらしい動きが作れるようになります!
自分の好きな絵を表示させて
モグラたたきゲームにアレンジしてみましょう。
サンプルのinoファイルはこちら
動画での解説もチェックしてみてね
UIAPduino でジョイコン(アナログスティック)を使おう
アナログスティックを使って、入力のしくみを体験してみましょう。
OLEDディスプレイの練習を終えた人向けです。
あらかじめ、プロジェクトフォルダに「oled_display.zip」を解凍しておいてください。
アナログスティックとは?
ゲームのコントローラーについている、グリグリ動かすパーツのことです。
ボタンは「押した / 押していない(HIGH / LOW)」で表しますが、 アナログスティックは傾き具合を数値で表すことができます。
- x(横方向) → 0〜1023
- y(縦方向) → 0〜1023
アナログスティックは「どれくらい動かしたか」を数値で取得できます。
キャラクターの移動やカーソル操作など、ゲームづくりに欠かせない入力です。
ジョイスティックモジュール (KY-023)
配線しよう
今回使うアナログスティックには、5本のピンがあります。
- GND → GND
- 5V → 5V
- VRX → A0
- VRY → A1
- SW → 2番ピン
SWはボタンと同じなので、プルアップを使って読み取ります。
プルアップを使わない場合は、プルダウン抵抗が必要になります。
プログラムを書こう
extern "C" {
#include "oled_min.h" //Cのプログラム
}
#include "display.h" //C++のプログラム
#define VRX A1
#define VRY A0
#define SW 2
void setup() {
pinMode(SW, INPUT_PULLUP); //スイッチをプルアップに
OLED_init();
}
void loop() {
int x = analogRead(VRX); // よこの動きを取得(左が0 右が1023)
int y = analogRead(VRY); // たての動きを取得(上が0 下が1023)
int sw = digitalRead(SW); // スイッチを取得(OFFが0 ONが1)
OLED_fill(0x00); //全部まっくろにする
drawNumber(x, 0, 0); //xのかたむきを表示
drawNumber(y, 0, 1); //yのかたむきを表示
drawNumber(sw, 0, 2); //スイッチの状態を表示
delay(200);
}
値を確認してみよう
マイコンにプログラムを書き込みましょう。
スティックを動かすと、xとyの値が変化します。
1行目がx
2行目がy
3行目がスイッチの値です
- 左に倒す → xが小さくなる
- 右に倒す → xが大きくなる
- 上に倒す → yが小さくなる
- 下に倒す → yが大きくなる
スティックを押し込むと、swの値も変化します。
アナログスティックの値を使うと、画面上のキャラクターを自由に動かすことができます。
このあと、モグラたたきゲームで実際に使ってみましょう!
カーソルを表示して動かしてみよう
数字だけでなく、自分の絵を画面に表示して動かすこともできます。
赤字の部分を追加して、カーソルを表示してみましょう。
プログラムを書こう
extern "C" {
#include "oled_min.h" //Cのプログラム
}
#include "display.h" //C++のプログラム
#define VRX A1
#define VRY A0
#define SW 2
const unsigned char cursor [] PROGMEM = {
0x7e, 0xc3, 0xa5, 0x99, 0x99, 0xa5, 0xc3, 0x7e };
int cx = 50; // カーソルのx
int cy = 4; // カーソルのy
void drawCursor(int x, int y) {
OLED_draw_bmp(x, y, x + 8, y + 1, cursor); //カーソルを描画
}
void setup() {
pinMode(SW, INPUT_PULLUP); //スイッチをプルアップに
OLED_init();
}
void loop() {
int x = analogRead(VRX);
int y = analogRead(VRY);
int sw = digitalRead(SW);
if (x < 300) cx -= 8; // yの移動量にあわせる
if (x > 700) cx += 8;
if (y < 300) cy--; // yは1段で8ピクセル動く
if (y > 700) cy++;
cx = constrain(cx, 0, 120); // ヨコはみだし防止
cy = constrain(cy, 0, 7); // タテはみだし防止
OLED_fill(0x00);
drawCursor(cx, cy); // カーソル表示
delay(50);
}
アナログスティックの値(0〜1023)をそのまま使うのではなく、
「300より小さい」「700より大きい」といった条件で動きを分けています。
これにより、スティックを倒したときだけカーソルが動くようになります。
cx と cy はカーソルの位置を表す変数です。
値を増減させることで、画面上の位置を動かしています。
constrain() を使うことで、カーソルが画面の外に出ないようにしています。
範囲を制限するときによく使う便利な関数です。
好きな画像を表示してみよう
カーソルの画像は、配列の中にデータとして保存されています。
const unsigned char cursor[] PROGMEM =
{ 0x7e, 0xc3, 0xa5, 0x99, 0x99, 0xa5, 0xc3, 0x7e };
この16進数のデータが、画像の正体です。
OLEDは「縦8ピクセル単位」で描画されます。
そのため、8×8や16×16など、8の倍数サイズの画像が扱いやすいです。

図のように、1と0で絵ができました。
このように2進数で表現してもいいですが、
使う画像をすべて2進数で書くのは大変です。
画像を作る方法
白黒の画像を16進数に変換してくれるツールがあります。
https://javl.github.io/image2cpp/
画像をアップロードし、以下のように設定します

- Code output format:Arduino code , single bitmapを選択します
- Identifier/Prefix : 画像の名前を入力します
- Draw mode:Vertical – 1 bit per pixelを選択します
「Generate code」を押すと、画像データが生成されます。
コピーしてプログラムに貼り付ければ、自分の絵を表示できます。
好きなキャラクターやマークを表示すれば、オリジナルゲームにぐっと近づきます!
描画のしくみを理解しよう
OLEDに画像を描画するときは、OLED_draw_bmp()という関数を使います。
OLED_draw_bmp(開始x, 開始y, 終了x, 終了y, 画像データ);
たとえば、8×8ピクセルの画像を描画するときは、次のように書きます。
OLED_draw_bmp(x, y, x + 8, y + 1, cursor);
横方向(x)はピクセル単位なので、8ピクセルなら「+8」になります。
縦方向(y)は「8ピクセルで1マス」として扱われるため、「+1」となります。
しくみ解説
コンピュータでは、「1バイト = 8個の0と1」でデータを表します。
OLEDでは、この1バイトが「縦8ピクセル分のデータ」として使われています。
- 1バイト → 縦8ピクセル
- それが横に並ぶ → 画像になる
そのため、画像の高さは「8の倍数」にすると扱いやすくなります。
モグラを追加してみよう
16×16ピクセルのモグラ画像を使って、ゲームにしてみましょう。
const unsigned char mogura [] PROGMEM = {
0x00, 0x00, 0xf0, 0xf8, 0x3c, 0x0c, 0xfc, 0xfc, 0xfc, 0x3c, 0x0c, 0xfc, 0xf8, 0xf0, 0x00, 0x00,
0x80, 0x40, 0xbf, 0xdf, 0x5f, 0x93, 0xd5, 0xd1, 0xd1, 0xd1, 0x93, 0x5f, 0xdf, 0xbf, 0x40, 0x80
};
int score = 0;
int mx = 40;
int my = 2;
モグラの処理を作ろう
// モグラ描画
void drawMogu(int x, int y) {
OLED_draw_bmp(x, y, x + 16, y + 2, mogura);
}
// 当たり判定
bool isHit() {
return (cx < mx + 16 &&
cx + 8 > mx &&
cy >= my &&
cy < my + 2);
}
カーソルとモグラの位置が重なっているかをチェックしています。
このような処理を「当たり判定」といいます。
画像は左上が原点で、原点から+16の位置がモグラの右端になります。
同じように、y座標は、+2マスの位置がモグラの下端になります。
このエリアにカーソルの座標があれば、カーソルが触れていると言えます。
ゲーム処理を追加しよう
void loop() {
int x = analogRead(VRX);
int y = analogRead(VRY);
int sw = digitalRead(SW);
if (x < 300) cx-=8; // yの移動量にあわせる
if (x > 700) cx+=8; //
if (y < 300) cy--; // yは1段で8ピクセル動く
if (y > 700) cy++;
cx = constrain(cx, 0, 120); // ヨコはみだし防止
cy = constrain(cy, 0, 7); // タテはみだし防止
OLED_fill(0x00);
drawMogu(mx, my);
drawCursor(cx, cy); // カーソル表示
uint8_t msg1[] = {K_SU, K_KO, K_A, K_SPACE}; // スコア
printKanaList(msg1, 4, 0, 0);
drawNumber(score, 32, 0);
if (digitalRead(SW) == LOW) { // 押された!
if (isHit()) {
score++;// ヒット!
// モグラを別の場所へ
mx = random(0, 112); // 横は0〜112くらい
my = random(1, 7); // 縦は1〜7(ページ単位)
}
delay(200); // チャタリング防止
}
delay(50);
}
モグラの位置は random() を使ってランダムに決めています。
画面サイズ(128ピクセル)からモグラの大きさ(16ピクセル)を引いて、 はみ出さないようにしています。
完成!モグラたたきゲーム
これで、カーソルを動かしてモグラを叩くゲームが完成しました!
自分で作ったキャラクターが動くと、一気にゲームらしくなりますね。
アレンジしてみよう
- ブザーを追加して音を鳴らす
- 制限時間をつける
- スコア表示を工夫する
いろいろなアイデアで、自分だけのゲームにしてみましょう!
カタカナの描画
OLEDに、カタカナを表示するための仕組みを用意しました。
8x8の可愛いフォント 美咲フォントを使用しています。
display.hでは、カタカナを次のように表します。
K_(ローマ字)
たとえば「スコア」と表示したい場合は、このように書きます。
uint8_t msg[] = {K_SU, K_KO, K_A};
printKanaList(msg, 3, 0, 0);
カタカナは「配列」にまとめてから表示します。
配列の中に、表示したい文字を順番に並べていきます。
K_A や K_KA などは、それぞれのカタカナに対応した「番号(インデックス)」です。
printKanaList() は、その番号をもとに、対応する文字の画像を表示しています。
空白や記号も使える
スペースを入れたいときは、K_SPACE
そのほか
K_BAR 「ー」
K_QUES 「?」
K_EXCL 「!」
K_DOTS 「。」
の記号がつかえます。
uint8_t msg[] = {K_SU, K_KO, K_A, K_SPACE, N_1};
printKanaList(msg, 5, 0, 0);
スコア表示や「スタート」「ゲームオーバー」など、 ゲームの文字表示にとても便利です
タブからdisplay.hやdisplay.cppをチェックしてみて下さい

UIAPduinoのページ https://www.uiap.jp/uiapduino/pro-micro/ch32v003/ ディスプレイ表示に使用したライブラリ https://github.com/wagiminator/CH32V003-GameConsole/
(電子工作ステーション ¥185)
コメント