// nothing but Aquarium :)
// by: Widyo Rio
// youtube.com/SkwaDroneSalatiga
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <stdlib.h>
// Definisi untuk OLED SSD1306
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Jumlah ikan dalam akuarium
#define FISH_COUNT 10
// Ukuran ikan
#define FISH_WIDTH 12
#define FISH_HEIGHT 4
// Struktur data untuk ikan
struct Fish {
int x; // Posisi X ikan
int y; // Posisi Y ikan
int speed; // Kecepatan ikan (berapa banyak piksel per gerakan)
bool direction; // Arah gerakan (true = ke kanan, false = ke kiri)
bool besar; // true jika besar false kecil
int verticalMovement; // Arah gerakan vertikal (1 = naik, -1 = turun, 0 = diam)
};
// Array untuk menyimpan ikan
Fish fishes[FISH_COUNT];
struct Balon {
int x; int y;
int jejari;
int dx; int dy;
bool otw;
};
Balon gelembung;
// 'kanan', 12x4px
const unsigned char ikan_kanan [] PROGMEM = {
0xcf, 0xc0, 0x7f, 0x60, 0x7f, 0xf0, 0xcf, 0xc0
};
// 'kiri', 12x4px
const unsigned char ikan_kiri [] PROGMEM = {
0x3f, 0x30, 0x6f, 0xe0, 0xff, 0xe0, 0x3f, 0x30
};
// 'kanan', 19x6px
const unsigned char big_kanan [] PROGMEM = {
0xe0, 0xfe, 0x00, 0x77, 0xab, 0x80, 0x3f, 0x56, 0xc0, 0x3e, 0xae, 0xe0, 0x71, 0xd7, 0xc0, 0xc0,
0xff, 0x80
};
// 'kiri', 19x6px
const unsigned char big_kiri [] PROGMEM = {
0x0f, 0xe0, 0xe0, 0x3a, 0xbd, 0xc0, 0x6d, 0x5f, 0x80, 0xee, 0xaf, 0x80, 0x7d, 0x71, 0xc0, 0x3f,
0xe0, 0x60
};
// Fungsi untuk menggambar ikan yang lebih realistis
void drawFish(int x, int y, bool direction, bool ukuran) {
if (direction) {
// Gambar ikan menghadap ke kanan
//display.fillTriangle(x, y, x + FISH_WIDTH, y - FISH_HEIGHT / 2, x + FISH_WIDTH, y + FISH_HEIGHT / 2, SSD1306_WHITE); // Badan ikan
//display.drawTriangle(x, y, x + FISH_WIDTH, y - FISH_HEIGHT / 2, x + FISH_WIDTH, y + FISH_HEIGHT / 2, SSD1306_WHITE); // Ekor ikan
if (ukuran) display.drawBitmap(x, y, big_kanan, 19, 6, 1); else display.drawBitmap(x, y, ikan_kanan, 12, 4, 1);
} else {
// Gambar ikan menghadap ke kiri
//display.fillTriangle(x + FISH_WIDTH, y, x, y - FISH_HEIGHT / 2, x, y + FISH_HEIGHT / 2, SSD1306_WHITE); // Badan ikan
//display.drawTriangle(x + FISH_WIDTH, y, x, y - FISH_HEIGHT / 2, x, y + FISH_HEIGHT / 2, SSD1306_WHITE); // Ekor ikan
if (ukuran) display.drawBitmap(x, y, big_kiri, 19, 6, 1); else display.drawBitmap(x, y, ikan_kiri, 12, 4, 1);
}
}
// Fungsi untuk menginisialisasi posisi ikan secara acak
void initializeFish() {
for (int i = 0; i < FISH_COUNT; i++) {
fishes[i].x = rand() % (SCREEN_WIDTH - FISH_WIDTH); // Posisi X acak
fishes[i].y = rand() % (SCREEN_HEIGHT - FISH_HEIGHT) + 5; // Posisi Y acak, dengan sedikit margin
fishes[i].speed = rand() % 3 + 1; // Kecepatan acak (antara 1 hingga 3 piksel per frame)
fishes[i].direction = rand() % 2; // Arah acak (0 = kiri, 1 = kanan)
fishes[i].besar = rand() % 2; // true besar false kecil
fishes[i].verticalMovement = 0; // Awalnya tidak bergerak vertikal
}
}
// Fungsi untuk menginisialisasi posisi ikan secara acak
void lawanArah() {
for (int i = 0; i < FISH_COUNT; i++) {
fishes[i].speed = rand() % 3 + 1; // Kecepatan acak (antara 1 hingga 3 piksel per frame)
fishes[i].direction = !fishes[i].direction;
fishes[i].verticalMovement = (rand() % 2 == 0) ? 1 : -1; // Tentukan arah (1 = naik, -1 = turun)
}
}
// Fungsi untuk memperbarui posisi ikan
void updateFish() {
for (int i = 0; i < FISH_COUNT; i++) {
// Gerakkan ikan sesuai arah dan kecepatan
if (fishes[i].direction) {
fishes[i].x += fishes[i].speed; // Bergerak ke kanan
if (fishes[i].x > SCREEN_WIDTH) {
fishes[i].x = 0; // Kembali ke kiri jika keluar dari layar
}
} else {
fishes[i].x -= fishes[i].speed; // Bergerak ke kiri
if (fishes[i].x < -FISH_WIDTH) {
fishes[i].x = SCREEN_WIDTH; // Kembali ke kanan jika keluar dari layar
}
}
// Pergerakan vertikal
if (rand() % 100 < 5) { // 5% kemungkinan untuk mengubah arah vertikal
if (fishes[i].verticalMovement == 0) {
fishes[i].verticalMovement = (rand() % 2 == 0) ? 1 : -1; // Tentukan arah (1 = naik, -1 = turun)
}
}
// Update posisi vertikal
fishes[i].y += fishes[i].verticalMovement;
// Pastikan ikan tidak keluar dari batas layar
if (fishes[i].y < 0) {
fishes[i].y = 0; // Tidak bisa lebih tinggi dari 0
fishes[i].verticalMovement = 1; // Ubah arah menjadi naik
} else if (fishes[i].y > SCREEN_HEIGHT - FISH_HEIGHT) {
fishes[i].y = SCREEN_HEIGHT - FISH_HEIGHT; // Tidak bisa lebih rendah dari batas bawah
fishes[i].verticalMovement = -1; // Ubah arah menjadi turun
}
}
}
void setup() {
// Memulai komunikasi I2C dengan OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Jika OLED gagal terhubung, berhenti program
}
// Inisialisasi layar OLED
display.clearDisplay();
display.display();
// Inisialisasi posisi dan properti ikan
initializeFish();
gelembung.otw = false;
}
void loop() {
// Bersihkan layar
display.clearDisplay();
//if (analogRead(A0)>200) lawanArah();
// Perbarui posisi ikan
updateFish();
// Gambar setiap ikan di layar
for (int i = 0; i < FISH_COUNT; i++) {
drawFish(fishes[i].x, fishes[i].y, fishes[i].direction,fishes[i].besar) ;
}
// proses gelembung
if (rand() % 100 < 5) { // 5% kemungkinan untuk muncul gelembung
if (!gelembung.otw)
{
gelembung.x= rand() % SCREEN_WIDTH;
gelembung.y= SCREEN_HEIGHT;
gelembung.jejari= 2+rand() % 10;
gelembung.dx=-1;
gelembung.dy= 3+rand() % 3;
gelembung.otw= true;
}
}
if (gelembung.otw)
{
display.drawCircle(gelembung.x+gelembung.dx, gelembung.y, gelembung.jejari, 1);
display.drawCircle(gelembung.x+gelembung.dx+gelembung.jejari, gelembung.y+gelembung.dy, gelembung.jejari/2, 1);
gelembung.y=gelembung.y-gelembung.dy;
if (gelembung.y<(0-gelembung.jejari)) gelembung.otw=false;
gelembung.dx=-1*gelembung.dx;
}
// Tampilkan hasil gambar di layar
display.display();
// Tambahkan sedikit jeda untuk kecepatan animasi
delay(100);
}