注釈
こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ!Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。
参加する理由は?
エキスパートサポート:コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
学び&共有:ヒントやチュートリアルを交換してスキルを向上させましょう。
独占的なプレビュー:新製品の発表や先行プレビューに早期アクセスしましょう。
特別割引:最新製品の独占割引をお楽しみください。
祭りのプロモーションとギフト:ギフトや祝日のプロモーションに参加しましょう。
👉 私たちと一緒に探索し、創造する準備はできていますか?[ ここ]をクリックして今すぐ参加しましょう!
ゲーム - ポン
これは、OLEDディスプレイとArduinoボードを使用して設計されたシンプルなポンゲームです。 ポンゲームでは、プレイヤーはコンピュータと対戦し、垂直なパドルを操作して跳ね返るボールを跳ね返します。 目標は、ボールを自分のパドルの端を越えさせないようにすることで、さもなければ相手に得点されます。
ゲームのメカニズムは以下のパーツに分けられます:
ボールの動き - ボールは現在の方向に沿って設定された速度で動きます。ボールがパドルに衝突するたびに、その速度が増加し、ゲームがより難しくなります。
パドルの動き - ボールの動きをブロックするために使用されるパドルは、上または下に動かすことができます。プレイヤーはボタンを使用して自分のパドルを操作し、コンピュータのパドルは自動的にボールの位置に従います。
スコアリング - ボールが画面の左または右端を越えるたびに、対応するプレイヤーまたはCPUが得点します。
必要なコンポーネント
このプロジェクトでは、以下のコンポーネントが必要です。
一式を購入するのが便利です。こちらがリンクです:
名称 |
このキットのアイテム数 |
リンク |
|---|---|---|
Elite Explorer Kit |
300+ |
以下のリンクから個別に購入することもできます。
コンポーネント紹介 |
購入リンク |
|---|---|
- |
|
- |
配線図
回路図
コード
注釈
ファイル
12_pong_oled.inoは、パスelite-explorer-kit-main\fun_project\12_pong_oledで直接開けます。または、このコードをArduino IDEにコピーしてください。
注釈
ライブラリをインストールするには、Arduinoライブラリマネージャーで 「Adafruit SSD1306」 と 「Adafruit GFX」 を検索し、インストールしてください。
1/*
2 This code creates a basic Pong game using an Arduino Uno, an OLED display,
3 and buttons. Players use the buttons to control a vertical paddle and bounce
4 back a moving ball to prevent it from passing their paddle. Scoring happens
5 when the ball goes off the screen edges.
6
7 Board: Arduino Uno R4
8 Component: OLED Display Module and Button
9 Library: https://github.com/adafruit/Adafruit_SSD1306 (Adafruit SSD1306 by Adafruit)
10 https://github.com/adafruit/Adafruit-GFX-Library (Adafruit GFX Library by Adafruit)
11*/
12
13
14#include <SPI.h>
15#include <Wire.h>
16#include <Adafruit_GFX.h>
17#include <Adafruit_SSD1306.h>
18
19#define UP_BUTTON 3
20#define DOWN_BUTTON 2
21
22#define SCREEN_WIDTH 128 // OLED display width, in pixels
23#define SCREEN_HEIGHT 64 // OLED display height, in pixels
24
25// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
26#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
27Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
28
29// ball set
30const unsigned long BALL_RATE = 16;
31int ball_x = 64, ball_y = 32;
32int ball_speed = 1;
33int8_t ball_dir_x = 1, ball_dir_y = 1;
34
35//flash rate
36unsigned long ball_update;
37unsigned long paddle_update;
38
39// paddle set
40const unsigned long PADDLE_RATE = 33;
41const uint8_t PADDLE_HEIGHT = 16;
42const uint8_t CPU_X = 12;
43int8_t cpu_y = 16;
44const uint8_t PLAYER_X = 115;
45int8_t player_y = 16;
46int paddle_speed = 3;
47
48// score
49uint8_t player_score = 0;
50uint8_t cpu_score = 0;
51
52
53void setup() {
54 Serial.begin(115200);
55
56 randomSeed(analogRead(A0));
57 ball_dir_x = random(0, 2) * 2 - 1;
58 ball_dir_y = random(0, 2) * 2 - 1;
59
60 display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
61 display.display();
62
63 pinMode(UP_BUTTON, INPUT);
64 pinMode(DOWN_BUTTON, INPUT);
65
66 unsigned long start = millis();
67
68 display.clearDisplay();
69 drawCourt();
70
71 while (millis() - start < 2000)
72 ;
73
74 displayScore();
75 display.display();
76
77 ball_update = millis();
78 paddle_update = ball_update;
79}
80
81void loop() {
82 bool update = false;
83 unsigned long time = millis();
84
85 static bool up_state = false;
86 static bool down_state = false;
87
88 /* check if the button pressed */
89 up_state |= (digitalRead(UP_BUTTON) == LOW);
90 down_state |= (digitalRead(DOWN_BUTTON) == LOW);
91
92 /* refresh the ball */
93 if (time > ball_update) {
94 int new_x = ball_x + ball_dir_x * ball_speed;
95 int8_t new_y = ball_y + ball_dir_y * ball_speed;
96
97 // Check if it hits the horizontal walls.
98 if (new_y <= 0 || new_y >= SCREEN_HEIGHT - 1) {
99 ball_dir_y = -ball_dir_y;
100 new_y += ball_dir_y + ball_dir_y * ball_speed;
101 displayScore();
102 }
103
104 // Check if it hits the CPU paddle
105 if (crossesCpuPaddle(ball_x, new_x, ball_y)) {
106 ball_dir_x = -ball_dir_x;
107 new_x = CPU_X + 1;// move the ball's position to the left edge of the paddle
108 ball_speed++; // speeds up
109 }
110
111 // Check if it hits the player paddle
112 if (crossesPlayerPaddle(ball_x, new_x, ball_y)) {
113 ball_dir_x = -ball_dir_x;
114 new_x = PLAYER_X - 1; // move the ball's position to the right edge of the paddle
115 ball_speed++; // speeds up
116 }
117
118 // Check if it hits the vertical walls
119 if (new_x <= 0 || new_x >= SCREEN_WIDTH - 1) {
120 if (new_x <= 1) {
121 player_score++;
122 }
123 if (new_x >= 126) {
124 cpu_score++;
125 }
126 /* reset ball */
127 displayScore();
128 ball_speed = 1; // reset speed
129 new_x = 64; // reset position
130 // new_y = 32;
131 ball_dir_x = (ball_dir_x > 0) ? -1 : 1; // reset direction
132 ball_dir_y = (random(0, 2) == 0) ? 1 : -1; // reset direction
133 }
134
135 display.drawPixel(ball_x, ball_y, BLACK);
136 display.drawPixel(new_x, new_y, WHITE);
137 ball_x = new_x;
138 ball_y = new_y;
139
140 ball_update += BALL_RATE; // next refresh time
141 update = true;
142 }
143
144 /* refresh paddles */
145 if (time > paddle_update) {
146 paddle_update += PADDLE_RATE; // next refresh time
147
148 // CPU paddle
149 display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, BLACK); //clear paddle
150 const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
151 if (cpu_y + half_paddle > ball_y) {
152 cpu_y -= paddle_speed;
153 }
154 if (cpu_y + half_paddle < ball_y) {
155 cpu_y += paddle_speed;
156 }
157 // constraint position
158 if (cpu_y < 1) cpu_y = 1;
159 if (cpu_y + PADDLE_HEIGHT > 63) cpu_y = 63 - PADDLE_HEIGHT;
160 display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, WHITE); //show paddle
161
162 // Player paddle
163 display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK); //clear paddle
164 if (up_state) {
165 player_y -= paddle_speed;
166 }
167 if (down_state) {
168 player_y += paddle_speed;
169 }
170 up_state = down_state = false;
171 // constraint position
172 if (player_y < 1) player_y = 1;
173 if (player_y + PADDLE_HEIGHT > 63) player_y = 63 - PADDLE_HEIGHT;
174 display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE); //show paddle
175 update = true;
176 }
177
178 if (update)
179 display.display();
180}
181
182bool crossesPlayerPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
183 return old_x < PLAYER_X && new_x >= PLAYER_X && ball_y >= player_y && ball_y <= player_y + PADDLE_HEIGHT;
184}
185
186bool crossesCpuPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
187 return old_x > CPU_X && new_x <= CPU_X && ball_y >= cpu_y && ball_y <= cpu_y + PADDLE_HEIGHT;
188}
189
190void drawCourt() {
191 display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
192}
193
194void displayScore() {
195 display.fillRect(SCREEN_WIDTH / 2 - 20, 10, 60, 10, BLACK);// clear
196
197 display.setCursor(SCREEN_WIDTH / 2 - 20, 10);
198 display.setTextSize(1);
199 display.setTextColor(WHITE);
200
201 display.print(cpu_score);
202 display.print(" - ");
203 display.print(player_score);
204}
どのように動作するのか?
プログラムの構造は以下の5つの部分に分けられます:
必要なライブラリのインポート - OLEDスクリーンの制御とボタン入力の読み取りに使用されます。
定数とグローバル変数の定義:
OLEDスクリーンの幅と高さの定義。 ボタンとOLEDリセットピンの定義。 ボールとパドルの位置、速度、サイズ、方向。 プレイヤーとCPUのスコア。
初期化:
シリアル通信、OLEDスクリーンを初期化し、初期インターフェースを表示します。 ボタンを入力として設定し、プルアップ抵抗器を接続します。 プレイングフィールドを描きます。
メインループ:
ボタンの状態を読み取ります。 設定されたリフレッシュレートに基づいてボールを動かします。 ボールとパドルまたは壁との衝突を検出し、ボールの方向と速度をそれに応じて調整します。 得点イベントに基づいてスクリーン上のスコアを更新します。 パドルの位置をリフレッシュします。
追加の関数:
crossesPlayerPaddleとcrossesCpuPaddle- ボールがプレイヤーのパドルまたはCPUのパドルと衝突するかどうかを検出するために使用されます。drawCourt- OLEDスクリーン上にプレイングフィールドを描きます。displayScore- 画面上にプレイヤーとCPUのスコアを表示します。