アナログスティックを使って、画面上のカーソルを自由に動かしてみましょう。

これまで学んできたセンサや表示のしくみを組み合わせることで、 いよいよゲームらしい動きが作れるようになります!

自分の好きな絵を表示させて
モグラたたきゲームにアレンジしてみましょう。

サンプルのinoファイルはこちら

動画での解説もチェックしてみてね

mogura

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は、スティックを押し込んだときのスイッチです。

image2


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行目がスイッチの値です


image3

  • 左に倒す → 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の倍数サイズの画像が扱いやすいです。

16進数を2進数になおしてみると…

image4

図のように、1と0で絵ができました。

このように2進数で表現してもいいですが、
使う画像をすべて2進数で書くのは大変です。

画像を作る方法

白黒の画像を16進数に変換してくれるツールがあります。

https://javl.github.io/image2cpp/



画像をアップロードし、以下のように設定します

image5
  • 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);
}

カーソルとモグラの位置が重なっているかをチェックしています。

このような処理を「当たり判定」といいます。
image6
画像は左上が原点で、原点から+16の位置がモグラの右端になります。
同じように、y座標は、+2マスの位置がモグラの下端になります。
このエリアにカーソルの座標があれば、カーソルが触れていると言えます。


ゲーム処理を追加しよう

■ loopの追加部分

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をチェックしてみて下さい

sc8_605




UIAPduinoのページ https://www.uiap.jp/uiapduino/pro-micro/ch32v003/ ディスプレイ表示に使用したライブラリ https://github.com/wagiminator/CH32V003-GameConsole/