見出し画像

Arduinoでシューティングゲームを作ってみた。【Arduino UNO R4】

Arduino UNO R4とOLEDディスプレイを使って、クラシックなシューティングゲームを作ってみました。

その内容を簡単にですがご紹介します。(ソースコードもあるよ)


はじめに

この記事では、Arduino UNOでシューティングゲームを作る方法についてご紹介しています。

下記の注意事項をお読みいただいた上で、ぜひお楽しみください。

【 注意 】
当Webサイトに掲載された内容によって生じた損害等の一切の責任を負いません。また生じた問題についてはご自身の責任において解決いただくことをあらかじめご承知おきください。詳しくは下記URLの免責事項をご確認願います。当サイトの免責事項に同意いただける場合に限り、当サイトの内容をご利用いただけます

https://note.com/shingo_shirogane/n/n3d5686bf512b

必要なもの

1. マイコンボード

本記事では、Arduino UNO R4 Wi-Fiを使います。

2. 電子部品

以下の電子部品を使います。

  • OLEDディスプレイ(SSD1306, 秋月電子で購入)

  • ブレッドボード (SAD-101)

  • ジャンパーワイヤー

  • タクトスイッチ × 2

回路図

OLEDディスプレイは👆のように繋ぎます。

加えてタクトスイッチをそれぞれ、Arduinoの2、4、6ピンに繋ぎます。

・2ピン が ←ボタン
・4ピン が →ボタン
・6ピン が Aボタン

です。

実際の動作

どのようなゲームなのかは、👆の動画後半で紹介しています。

ソースコード

ソースコードが👇になります。注意事項をよくお読みいただき、ご使用ください。

//当Webサイトに掲載された内容によって生じた損害・損失の一切の責任を負いません。
//当webサイトの免責事項に同意いただける場合に限り、プログラムをご利用いただけます。

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 
#define SCREEN_HEIGHT 64 

#define SW_A 6
#define SW_R 4
#define SW_L 2

#define NUM_SIZE 2
#define WIDTH 6
#define HEIGHT  8
int CENTER_WIDTH =  SCREEN_WIDTH / 2 - WIDTH / 2 * NUM_SIZE;
int CENTER_HEIGHT = SCREEN_HEIGHT / 2 - NUM_SIZE * 7 / 2;

int playerPosition = SCREEN_WIDTH/2-SCREEN_WIDTH/16/2;
int playerLifePoint = 3;
int playerMoveSpeed = 2;

int bulletPosition[1][2];
int bulletExistFlag = 0;
int bulletMoveSpeed = 2;

int enemyPosition[1][2];
int enemyExistFlag = 0;
int enemyDefeatCount = 0;
int enemyMoveSpeed = 1;

#define OLED_RESET     -1 

//画面のサイズ(データシートから)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


void setup() {

  pinMode(SW_A, INPUT_PULLUP);
  pinMode(SW_L, INPUT_PULLUP);
  pinMode(SW_R, INPUT_PULLUP);

  Serial.begin(115200);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  randomSeed(analogRead(0));
  initialDisp();


}

void loop() {
  display.clearDisplay();

  playerPositionDisp();     //自機の表示

  bulletPositionDisp();     //弾の表示

  enemyPositionDisp();

  attackHitJudge();

  enemyDefeatCountDisp();

  playerLifePointDisp();

  display.display();

  if(playerLifePoint == 0){
    gameOverDisp();
    resultDisp();
  }
}

//起動時の画面表示
void initialDisp(){
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);


  display.setCursor(CENTER_WIDTH-43, CENTER_HEIGHT+30);
  display.println("PRESS A TO START");
  display.display();
  while(digitalRead(SW_A)==HIGH){}
  delay(100);
}

//自機の表示
void playerPositionDisp(void) {
  //display.clearDisplay();
  if(digitalRead(SW_R)==LOW){
    if(playerPosition < SCREEN_WIDTH - SCREEN_WIDTH/16){
        playerPosition += playerMoveSpeed;
    }
  }else if(digitalRead(SW_L)==LOW){
    if(playerPosition > 0){
        playerPosition -= playerMoveSpeed;
    }
  }

  //Serial.println(playerPosition);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(playerPosition, SCREEN_HEIGHT - SCREEN_HEIGHT/16);
  display.println("A");
  //display.display(); 
  //delay(1);
  
}

//弾の表示
void bulletPositionDisp(void) {
  //display.clearDisplay();
  if(digitalRead(SW_A) == LOW && bulletExistFlag == 0){
    bulletPosition[0][0] = playerPosition+2;
    bulletPosition[0][1] = SCREEN_HEIGHT - SCREEN_HEIGHT/16;
    bulletExistFlag =  1;
    display.fillCircle(bulletPosition[0][0], bulletPosition[0][1], 1, SSD1306_INVERSE);
  }else if(bulletExistFlag == 1){
    bulletPosition[0][1] -= bulletMoveSpeed;
    display.fillCircle(bulletPosition[0][0], bulletPosition[0][1], 1, SSD1306_INVERSE);
  }
    
  if(bulletPosition[0][1] < 0){
    bulletExistFlag = 0;
  }

}

//敵機の表示
void enemyPositionDisp(){
  if(enemyExistFlag == 0){
    enemyPosition[0][0] = random(SCREEN_WIDTH/16/2,SCREEN_WIDTH+1-SCREEN_WIDTH/16/2);
    enemyPosition[0][1] = 0;
    display.fillCircle(enemyPosition[0][0], enemyPosition[0][1], 3, SSD1306_INVERSE);
    enemyExistFlag =1;
  }else if(enemyExistFlag == 1){
    enemyPosition[0][1] += enemyMoveSpeed;
    display.fillCircle(enemyPosition[0][0], enemyPosition[0][1], 3, SSD1306_INVERSE);
  }
  
  if(enemyPosition[0][1] > SCREEN_HEIGHT){
    enemyExistFlag = 0;
    playerLifePoint--;
  }
}

//攻撃が当たったかの判定
void attackHitJudge(){
  if(abs(bulletPosition[0][0]-enemyPosition[0][0])<=3 && abs(bulletPosition[0][1] - enemyPosition[0][1]) <= 3 ){
    bulletExistFlag = 0;
    enemyExistFlag = 0;
    enemyDefeatCount++;

    //初期化
    bulletPosition[0][0] = playerPosition+SCREEN_WIDTH/16/2;
    bulletPosition[0][1] = SCREEN_HEIGHT - SCREEN_HEIGHT/16;

    enemyPosition[0][1] = 0;

  }
}

//敵機の撃破数
void enemyDefeatCountDisp(){
  display.setTextColor(WHITE);
  display.setTextSize(NUM_SIZE);
  if(enemyDefeatCount<10){
    display.setCursor(CENTER_WIDTH, CENTER_HEIGHT-10);
  }else{
    display.setCursor(CENTER_WIDTH-8, CENTER_HEIGHT-10);
  }
  
  display.println(enemyDefeatCount); 
}

//自機のライフ表示
void playerLifePointDisp(){

  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(CENTER_WIDTH-5, CENTER_HEIGHT+10);
  display.print("L:");
  display.println(playerLifePoint); 
}

void difficultyChange(){
  if(enemyDefeatCount == 10){
    playerMoveSpeed = 4;
    bulletMoveSpeed = 4;
    enemyMoveSpeed = 2;
  }
}

//ゲームオーバー表示
void gameOverDisp(){
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(CENTER_WIDTH-20, CENTER_HEIGHT+4);
  display.println("GAME OVER");
  display.display();
  delay(2000);
}

//リザルト表示
void resultDisp(){
    display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(CENTER_WIDTH-20, CENTER_HEIGHT+4);
  display.print("SCORE: ");
  display.println(enemyDefeatCount);
  display.println("");
  display.println("");
  display.println("            RESTART>>"); 
  display.display();

  while(digitalRead(SW_A)==HIGH){}
  delay(200);
  //初期化
  playerLifePoint = 3;
  enemyDefeatCount = 0;
  bulletExistFlag = 0;
  enemyExistFlag = 0;
  playerMoveSpeed = 2;
  enemyMoveSpeed = 1;
  bulletMoveSpeed = 2;
}

おわりに

いかがだったでしょうか。

もしこの記事がお役に立てたら、"スキ"や"サポート"をいただけると励みになります!

最後まで読んでいただき、ありがとうございました。


いいなと思ったら応援しよう!

みんなの電気・電子回路
今後ともお役に立てるような記事を発信していきます!よろしければサポートいただけると嬉しいです!