Lecția 13 30 min
avansat 3 întrebări quiz
PvP între 2 mașini — ESP-NOW + ultrasonic
Cum trimit mașina ta un mesaj la mașina lui Darius când îl lovești. Damage, scut activ, magnet. ESP-NOW peer-to-peer fără router.
Ce înveți
- Cum trimit 2 ESP32 mesaje direct între ele (ESP-NOW, fără router)
- Cum măsori distanța cu HC-SR04 ultrasonic
- Cum sincronizezi 'scut activ' între mașini — efect global, nu doar local
- Cum desenezi pe pagina de control viața (HP) și power-up-ul activ
Ce ai nevoie
ESP-NOW recap (de la VIA)
ESP-NOW = mesaje directe între 2 ESP32. Nu trebuie router, nu trebuie internet. Doar:
- Fiecare ESP32 are un MAC (adresa fizică unică, 6 bytes ca
C0:49:EF:00:00:01) - Tu îți spui în cod: „vreau să vorbesc cu MAC
C0:49:EF:00:00:02” - Trimiți
esp_now_send(mac, pachet, lungime)→ ajunge în 1-2 ms
La CART-K avem 2 mașini care comunică:
- M1 (Sergiu) — MAC
C0:49:EF:00:00:01 - M2 (Darius) — MAC
C0:49:EF:00:00:02
Mesaje pe care le trimitem
struct cart_msg {
uint8_t tip; // 1 = lovire, 2 = scut activ, 3 = magnet, 4 = ping
uint8_t source_id; // 1 sau 2
int hp; // viața mea curentă (0..100)
int power_up; // ce power-up am activ (0=niciunul, 1=banana, etc.)
uint32_t ms_ramas; // câte ms mai durează power-up-ul meu
};
Detectare lovire cu HC-SR04
const int TRIG = 5;
const int ECHO = 18;
float distanta_cm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long durata = pulseIn(ECHO, HIGH, 30000); // timeout 30ms
return durata * 0.0343 / 2; // cm
}
void verifica_lovire() {
float d = distanta_cm();
if (d > 0 && d < 10.0) {
// Posibil mașină inamică
cart_msg m = { .tip = 1, .source_id = MEU, .hp = hp_curent };
esp_now_send(mac_inamic, (uint8_t*)&m, sizeof(m));
}
}
Recepție și reguli PvP
void onESPNowRecv(const uint8_t* mac, const uint8_t* data, int len) {
cart_msg* m = (cart_msg*)data;
if (m->tip == 1) { // m-a lovit
if (scut_activ) {
// Reflectez damage înapoi
cart_msg back = { .tip = 1, .source_id = MEU, .hp = hp_curent };
esp_now_send(mac_inamic, (uint8_t*)&back, sizeof(back));
} else {
hp_curent -= 10;
flash_led_damage();
if (hp_curent <= 0) {
morm_temporar(); // 5s oprit pentru „respawn"
}
}
}
if (m->tip == 2) { // inamic a activat scut
scut_activ_inamic = true;
sfarsit_scut_inamic = millis() + m->ms_ramas;
}
}
Magnet — efect global
Când M1 activează magnet (trece peste tile portocaliu):
- M1 broadcast: „M1 has magnet, dur 3000ms”
- M2 primește mesajul → forțează direcția spre M1 timp de 3s, indiferent de ce trimite joystick-ul lui Darius
- M2 trimite înapoi „I’m pulled, can’t escape” → pe pagina de control a lui Darius apare „!! MAGNETIZAT !!”
Cod pe M2:
if (magnetizat && millis() < sfarsit_magnetizare) {
drive_spre(POSITIE_M1); // ignoră joystick
} else {
drive_din_joystick();
}
Pe pagina de control — afișare HP + power-up
<div class="hp-bar">
<div class="hp-fill" style="width: 80%"></div>
</div>
<div class="powerup">SCUT ACTIV 3.2s</div>
Pagina /sergiu/cart-k/control/ ascultă pe WebSocket de la mașina ta și afișează în plus și starea mașinii inamice (din mesajele ESP-NOW recepționate).
Reguli PvP de pornit
| Eveniment | Efect |
|---|---|
| Lovești inamic la <10cm fără scut | -10 HP pentru el |
| Inamic te lovește în timp ce ai scut | -10 HP pentru el (reflectat) |
| Ai magnet activ | inamicul vine spre tine 3s |
| Treci peste vârtej (mov) | te învârti 1.5s |
| HP < 0 | „mort” temporar 5s, apoi revino cu 50 HP |
| Primul la 3 ture câștigă | sau primul care reduce inamicul la 0 HP de 3 ori |
Tu decizi regulile. Asta-i partea cea mai distractivă — fără reguli scrise în piatră de altcineva.
Pas următor
Construiește. Curse cu Darius. Schimbă regulile când se plictisesc unul dintre voi.
După lecția asta, poți
- 2 mașini se vede una pe alta și interactionează în timp real
- Implementezi reguli PvP simple: scut blochează damage, magnet trage mașina inamică spre tine
- Faci propriul tău joc multi-player fără internet, doar 2 ESP32