Joystick'li Yılan Oyunu
Orta45 dk8x8 LED ekranda oynanan klasik yılan oyunu: yılanı joystick ile yönlendirirsin, yanıp sönen yemi yiyince yılan bir boy uzar, biraz hızlanır ve buzzer kısa öter. Ekran küçük olduğu için yılan bir kenardan çıkınca karşı kenardan girer; kendi gövdesine çarpınca oyun biter, üç inen notayla puanın ekranda rakamlarla görünür ve joystick'in düğmesine basınca yeni oyun başlar. Analog bir joystick'i okuyup yöne çevirmeyi, bir oyunu dizilerle tutmayı (yılanın hücreleri), millis() ile oyun hızını ayarlamayı ve MAX7219 sürücülü bir LED matrisi birkaç kabloyla yönetmeyi öğretir. Kitaplık Yöneticisi'nden "LedControl" kurulur.
Uygulamada adım adım yapGerekli malzemeler
1 × Arduino Uno R3
1 × Breadboard 830 Pin (MB-102)
1 × MAX7219 8x8 Dot Matrix LED Modülü
1 × XY Joystick Modülü
1 × Pasif Buzzer (Piezo)
6 × Jumper Kablo - Erkek/Erkek
10 × Jumper Kablo - Erkek/Dişi
Bağlantı adımları
- 1
Güç sıralarını bağla ve birleştir

Kırmızı erkek-erkek jumper kabloyu Arduino'nun güç başlığındaki 5V pinine tak, diğer ucunu breadboard'un alttaki kırmızı çizgili (+) güç sırasına bağla. Siyah kabloyu aynı başlıktaki GND pinine tak, alttaki mavi çizgili (−) sıraya bağla. Breadboard'un üstteki ve alttaki güç sıraları birbirine bağlı değildir: breadboard'un sağ ucunda kırmızı bir kabloyla alttaki (+) sırayı üstteki (+) sıraya, siyah bir kabloyla alttaki (−) sırayı üstteki (−) sıraya bağla. Artık dört sıranın hepsinde 5V ve GND var.
- Arduino 5V → alttaki kırmızı çizgili (+) sıra (kırmızı kablo)
- Arduino GND → alttaki mavi çizgili (−) sıra (siyah kablo)
- alttaki kırmızı çizgili (+) sıra → üstteki kırmızı çizgili (+) sıra (kırmızı kablo)
- alttaki mavi çizgili (−) sıra → üstteki mavi çizgili (−) sıra (siyah kablo)
- 2
8x8 LED matrisi bağla

Matris modülünün iki yanında 5'er pin vardır: DIN yazan taraf giriştir, öbür taraf (DOUT) başka bir matrise zincirlemek içindir. Giriş tarafındaki pinlere erkek-dişi kabloların dişi uçlarını tak. VCC'yi üstteki (+) sıraya, GND'yi üstteki (−) sıraya, DIN'i Arduino'nun 12, CS'yi 10, CLK'yi 11 numaralı pinine bağla (DIN_PIN, CS_PIN, CLK_PIN). Matrisi, giriş pinleri aşağıda kalacak şekilde önüne koy.
- LED matris VCC → üstteki kırmızı çizgili (+) sıra (kırmızı kablo)
- LED matris GND → üstteki mavi çizgili (−) sıra (siyah kablo)
- Arduino pin 12 → LED matris DIN (mavi kablo)
- Arduino pin 10 → LED matris CS (sarı kablo)
- Arduino pin 11 → LED matris CLK (yeşil kablo)
- 3
Joystick'i bağla

Joystick modülünün 5 pinine erkek-dişi kabloların dişi uçlarını tak. GND'yi alttaki (−) sıraya, +5V'u alttaki (+) sıraya bağla. VRx'i (yatay eksen) Arduino'nun A0, VRy'yi (dikey eksen) A1 pinine, SW'yi (joystick'e basınca kapanan düğme) 2 numaralı pine bağla. Düğmenin direncini kod Arduino'nun içindeki pull-up ile sağlar, ayrıca direnç gerekmez.
- joystick +5V → alttaki kırmızı çizgili (+) sıra (kırmızı kablo)
- joystick GND → alttaki mavi çizgili (−) sıra (siyah kablo)
- Arduino A0 → joystick VRx (turuncu kablo)
- Arduino A1 → joystick VRy (mor kablo)
- Arduino pin 2 → joystick SW (beyaz kablo)
- 4
Buzzer'ı tak ve bağla

Pasif buzzer'ın + bacağını üst yarıda 15. sütuna, öbür bacağını 16. sütuna tak; + bacak genelde daha uzundur ve gövdesinde + işareti vardır. Turuncu kabloyla Arduino'nun 8 numaralı pinini 15. sütuna bağla (BUZZER_PIN 8). Kısa siyah bir kabloyla 16. sütunu üstteki (−) sıraya bağla.
- buzzer + bacak → 15. sütun, üst yarı
- buzzer − bacak → 16. sütun, üst yarı
- Arduino pin 8 → 15. sütun, üst yarı (turuncu kablo)
- 16. sütun, üst yarı → üstteki mavi çizgili (−) sıra (siyah kablo)
Arduino kodu
// Kitaplık Yöneticisi'nden kurulacak:
// "LedControl" (Eberhard Fahle)
#include <LedControl.h>
// MAX7219 modülünün DIN, CLK, CS pinleri
const int DIN_PIN = 12;
const int CLK_PIN = 11;
const int CS_PIN = 10;
// Joystick: iki eksen ve basma düğmesi
const int JOY_X = A0;
const int JOY_Y = A1;
const int JOY_BUTTON = 2;
const int BUZZER_PIN = 8;
// Yılan ters gidiyorsa bunları değiştir:
// ekranı yatay/dikey çevirir, eksenleri
// yer değiştirir
const bool FLIP_X = false;
const bool FLIP_Y = false;
const bool SWAP_AXES = false;
// Bir adımın süresi (ms): her yemde
// biraz kısalır, en az MIN_DELAY olur
const int START_DELAY = 350;
const int MIN_DELAY = 120;
// Puan için 3x5 rakamlar, satır satır
const byte DIGITS[10][5] = {
{7, 5, 5, 5, 7}, {2, 6, 2, 2, 7}, {7, 1, 7, 4, 7}, {7, 1, 3, 1, 7},
{5, 5, 7, 1, 1}, {7, 4, 7, 1, 7}, {7, 4, 7, 5, 7}, {7, 1, 1, 2, 2},
{7, 5, 7, 5, 7}, {7, 5, 7, 1, 7}
};
LedControl matrix(DIN_PIN, CLK_PIN, CS_PIN, 1);
// Yılanın hücreleri, baştan kuyruğa
byte snakeX[64];
byte snakeY[64];
int length = 3;
// Gidiş yönü (-1, 0, 1) ve sıradaki yön
int dx = 1, dy = 0;
int nextDx = 1, nextDy = 0;
byte foodX = 0, foodY = 0;
int score = 0;
int stepDelay = START_DELAY;
bool playing = false;
unsigned long lastStep = 0;
// Bir LED'i yak/söndür (x sağa, y aşağı)
void plot(int x, int y, bool on) {
int col = FLIP_X ? 7 - x : x;
int row = FLIP_Y ? 7 - y : y;
matrix.setLed(0, row, col, on);
}
bool isSnake(int x, int y, int count) {
for (int i = 0; i < count; i++) {
if (snakeX[i] == x && snakeY[i] == y) return true;
}
return false;
}
// Yemi yılanın olmadığı rastgele bir yere
void placeFood() {
do {
foodX = random(8);
foodY = random(8);
} while (isSnake(foodX, foodY, length));
}
void draw() {
matrix.clearDisplay(0);
for (int i = 0; i < length; i++) {
plot(snakeX[i], snakeY[i], true);
}
}
void newGame() {
length = 3;
for (int i = 0; i < length; i++) {
snakeX[i] = 3 - i;
snakeY[i] = 4;
}
dx = nextDx = 1;
dy = nextDy = 0;
score = 0;
stepDelay = START_DELAY;
placeFood();
draw();
playing = true;
lastStep = millis();
Serial.println("Yeni oyun başladı.");
}
// İki haneli puanı rakamlarla göster
void showScore() {
matrix.clearDisplay(0);
int digits[2] = {score / 10 % 10, score % 10};
for (int d = 0; d < 2; d++) {
if (d == 0 && score < 10) continue;
// Tek hane ortada, iki hane yan yana
int left = score < 10 ? 2 : 1 + d * 4;
for (int r = 0; r < 5; r++) {
for (int c = 0; c < 3; c++) {
bool on = DIGITS[digits[d]][r] & (4 >> c);
plot(left + c, r + 1, on);
}
}
}
}
void gameOver() {
playing = false;
Serial.print("Oyun bitti! Puan: ");
Serial.println(score);
int notes[3] = {440, 330, 220};
for (int i = 0; i < 3; i++) {
tone(BUZZER_PIN, notes[i], 200);
delay(250);
}
showScore();
}
// Joystick'i oku; geri dönüşe izin verme
void readJoystick() {
int x = analogRead(JOY_X);
int y = analogRead(JOY_Y);
if (SWAP_AXES) {
int t = x;
x = y;
y = t;
}
int jx = 0, jy = 0;
if (x < 300) jx = -1;
if (x > 700) jx = 1;
if (y < 300) jy = -1;
if (y > 700) jy = 1;
// Çapraz basılırsa yatay öncelikli
if (jx != 0) jy = 0;
if (jx == 0 && jy == 0) return;
if (jx == -dx && jy == -dy) return;
nextDx = jx;
nextDy = jy;
}
void step() {
dx = nextDx;
dy = nextDy;
// Kenardan çıkan karşı kenardan girer
int x = (snakeX[0] + dx + 8) % 8;
int y = (snakeY[0] + dy + 8) % 8;
bool ate = (x == foodX && y == foodY);
// Yem yenince kuyruk yerinde kalır
if (isSnake(x, y, ate ? length : length - 1)) {
gameOver();
return;
}
if (ate) length++;
for (int i = length - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
snakeX[0] = x;
snakeY[0] = y;
if (ate) {
score++;
tone(BUZZER_PIN, 1800, 60);
stepDelay = max(MIN_DELAY, stepDelay - 15);
Serial.print("Yem yendi, puan: ");
Serial.println(score);
if (length == 64) {
gameOver();
return;
}
placeFood();
}
draw();
}
void setup() {
Serial.begin(9600);
pinMode(JOY_BUTTON, INPUT_PULLUP);
// Bağlı olmayan A5'in gürültüsü her
// oyunda yemleri farklı yerlere koyar
randomSeed(analogRead(A5));
matrix.shutdown(0, false);
matrix.setIntensity(0, 4);
newGame();
}
void loop() {
if (!playing) {
// Puan ekranda; düğmeye basınca başla
if (digitalRead(JOY_BUTTON) == LOW) newGame();
return;
}
readJoystick();
if (millis() - lastStep >= (unsigned long)stepDelay) {
lastStep = millis();
step();
}
// Yem yanıp söner, yılandan ayrılır
if (playing) plot(foodX, foodY, millis() / 150 % 2);
}
Seri Monitörde göreceğin
Yeni oyun başladı. Yem yendi, puan: 1 Yem yendi, puan: 2 Yem yendi, puan: 3 Oyun bitti! Puan: 3 Yeni oyun başladı.
Sonuç
Kodu yükleyince matriste 3 LED'lik yılan sağa doğru yürümeye başlar, ekranın bir yerinde yem yanıp söner. Joystick'i iterek yılanı yönlendir: yılan geri dönemez, yalnızca sağa ya da sola sapar. Yemi yiyince buzzer kısa öter, yılan bir boy uzar ve biraz hızlanır; puan Seri Monitöre de yazılır. Yılan bir kenardan çıkınca karşı kenardan girer. Kendi gövdesine çarpınca üç inen nota çalar ve puan ekranda rakamla görünür; joystick'e yukarıdan bastırınca yeni oyun başlar. Joystick'i sağa ittiğinde yılan sola gidiyorsa koddaki FLIP_X'i true yap; yukarı-aşağı terse FLIP_Y'yi true yap; sağa itince yılan yukarı-aşağı gidiyorsa SWAP_AXES'i true yap ve yeniden yükle. Ekran hiç yanmıyorsa DIN, CS ve CLK kablolarının matrisin giriş tarafında (DIN yazan tarafta) olduğuna bak. Yeni oyun başlamıyorsa SW kablosunun 2 numaralı pinde olduğuna bak.
Uygulamada her bağlantıyı tek tek işaretle, envanterindeki parçalarla eşleştir ve kaldığın yerden devam et.
Uygulamada adım adım yap