Gioco multiplayer 8-ball a due giocatori su internet[cite: 3]. Backend: json e sql. Frontend: JavaScript ES5 + Canvas 2D[cite: 3].
Il server è l'autorità di stato (anti-cheat)[cite: 3].
Fig. 1 — Schermata di gioco. Da sinistra: barra dei giocatori sopra il tavolo (avatar + login + montepremi),
tavolo con triangolo di biglie disposto e la bianca sulla linea di tiro, pannello destro: PUNTO DI IMPATTO
(grande biglia bianca per impostare l'effetto), BIGLIE INBUCATE (ordine) e ROUND.
Sotto il tavolo, il messaggio di stato "In attesa dei giocatori" e il pulsante "Siediti al tavolo".
Fig. 2 — Test del motore di tiro (A–H). Per ogni tiro il motore riporta:
imbucata/mancata buca, posizione finale e velocità finale, nonché la traiettoria completa della biglia.
Scenari testati: imbucata in buca d'angolo e centrale (A, F, G, H), rimbalzo dalla sponda (B),
rotolamento lungo la sponda senza cadere (C, D) e traiettoria che manca la buca (E).
Disposizione: bianca sulla linea di tiro (x=260), triangolo di 15 biglie con l'apice a x=700;
la nera (8) al centro del triangolo, agli angoli una biglia piena e una striata.
Spaccata (Break): primo tiro con la bianca contro il triangolo; il giocatore che esegue la spaccata viene sorteggiato dal server (mt_rand).
Gruppi: il giocatore che per primo, nello stato playing, imbuca una biglia, ottiene quel gruppo —
piene (1–7) o striate (9–15); l'avversario riceve l'altro gruppo.
Turno: imbucare la propria biglia = tiro successivo; errore o fallo = il turno passa
all'avversario.
Biglia nera (8): legale solo dopo aver imbucato tutto il proprio gruppo; deve entrare nella buca
diagonale rispetto alla buca in cui è stata imbucata l'ultima biglia (evidenziata con un anello
dorato). La nera troppo presto o nella buca sbagliata = sconfitta immediata.
Falli (conseguenza: l'avversario prende la bianca in mano)
Primo contatto della bianca con una biglia dell'avversario o con la nera (quando non è legale)
La bianca non ha colpito alcuna biglia e ha rimbalzato contro meno di 3 sponde differenti
Imbucare la bianca o una biglia dell'avversario (la biglia dell'avversario viene conteggiata per lui)
Superamento del tempo per mossa / del limite di tempo per eseguire il tiro
Fine della partita
Vittoria: nera nella buca richiesta → il vincitore si aggiudica il montepremi (2× puntata)
Forfait (Walkover): l'avversario ha lasciato il tavolo o non è tornato entro 30 s → il montepremi va al giocatore presente
Rivincita: dopo lo stato finished il pulsante "Rivincita" preleva nuovamente la quota di iscrizione
4. Geometria del tavolo e buche
Le coordinate della fisica sono sempre nel sistema logico 1000×620 px (panno da (53,53) a (947,547));
il ridimensionamento dello schermo non altera la fisica. Ciascuna delle 6 buche è un corridoio-guida con
ganasce a imbuto — non un punto. La biglia nel corridoio scorre lungo una canalina fino al buco nero (raggio ~25 px)
e solo lì scompare; le pareti del canale la respingono verso il centro (nessuna "sponda invisibile").
Fig. 4 — Geometria del tavolo: panno, 6 buche numerate e regola della buca diagonale per la nera.
asse lungo PAXIS; quelle d'angolo hanno un "grembiule" fino a t=34
Diagonali delle buche
0↔4, 1↔3, 2↔5
buca richiesta per la nera
Blocco posizionamento bianca
PCAP + raggio ≈ cueR+15
vietato posizionare nell'area della buca / sopra un'altra biglia
5. Motore fisico (client, deterministico)
Costante
Valore
Significato
SIM_DT
1/240 s
passo di simulazione fisso — determinismo su entrambi i client
FRICTION
0.997 / passo
attrito di rotolamento
RAIL_REST
0.8
coefficiente di rimbalzo della sponda
STOP_V
8 px/s (scalato con Ø)
soglia di arresto della biglia
MAX_SPEED
1600 px/s (scalato con Ø)
forza del tiro = 1.0
Collisioni tra biglie: elastiche, con separazione della posizione — la separazione non spinge mai una biglia
fuori dal corridoio della buca facendola tornare sulla sponda.
Effetto (spin): laterale (x) incurva la traiettoria della bianca prima del primo contatto;
superiore/inferiore (y) modifica il comportamento dopo il contatto (follow/draw). Resettato dopo ogni tiro.
Scalatura: la forza del tiro e la soglia di arresto si ridimensionano in base al diametro delle biglie
(base Ø28 px) — le biglie di qualsiasi dimensione si muovono in modo naturale.
Rotolamento delle biglie: rotazione = spazio/raggio; numeri e strisce rotolano sulla sfera
seguendo la direzione del movimento (360° completi).
Eventi di simulazione:pocketed (biglia+buca, in ordine),
firstHit (primo contatto della bianca), rails (insieme delle sponde toccate).
Eventi + posizioni finali riportati al server come risultato del tiro.
6. Controlli e punto di impatto
Azione
PC
Telefono (touch)
Mira
il mouse imposta la direzione; linea di mira + biglia fantasma + traiettoria di rimbalzo
il trascinamento imposta direzione e forza con un solo gesto ("fionda")
Forza del tiro
tieni premuto e trascina lungo la stecca all'indietro (in avanti diminuisce); rilascia = tiro
come per la mira
Punto di impatto
grande biglia bianca nel pannello: alto = tira dietro la biglia (follow), basso = richiama (draw), lati = arco ed effetto sulla sponda
Bianca in mano
il clic posiziona immediatamente
trascinare il fantasma e rilasciare il dito posiziona
Validazione del server della posizione della bianca (place_cue): all'interno del panno, non troppo vicina alla buca,
non si sovrappone a un'altra biglia.
7. Multiplayer — macchina a stati e tempo
Fig. 5 — Macchina a stati del tavolo.
Limite
Costante / configurazione
Conseguenza
Tempo per mossa
turn_time per tavolo (5–300 s, def. 30)
fallo: turno + bianca in mano all'avversario
Ritorno al tavolo
SEAT_TIMEOUT = 30 s
posto trattenuto per 30 s; poi liberato, in partita = forfait
Risultato del tiro
SHOT_TIMEOUT = 150 s
il tiro scade → fallo di tempo
Heartbeat
polling get_status ogni ~1,2 s
aggiorna last_activity del giocatore
Il tempo per mossa viene calcolato solo dopo l'arresto di tutte le biglie (fase aim) —
la barra del tempo appare dopo la simulazione. Tutte le operazioni sullo stato sono atomiche sotto flock
(withState) — nessun conflitto di scrittura.
8. API — elenco completo delle azioni
bilard_api.php?table=<id>&action=<azione> (richiede sessione; le azioni POST richiedono token CSRF)
Azione
Metodo
Effetto
get_status
GET
Stato completo: biglie, posti (+rango/saldo/idle), turno, fase, montepremi, time_left/time_limit, pending_shot, potted_order, moves/round, configurazione (feltro, ball_r, cue_r, table_w/h), saldo e rango del chiamante
test_session
GET
Diagnostica: user, userId, balance
sit
POST
Occupazione del posto (verifica saldo min., blocco del tavolo, posto libero)
leave_table
POST
Rilascio del posto; durante la partita = resa (forfait)
start_game
POST
Avvio quando entrambi sono seduti; preleva la quota, montepremi = 2× puntata, sorteggia chi rompe
place_cue
POST
Posizionamento della bianca in mano; validazione della posizione (panno, buche, collisioni)
shoot
POST
Registrazione del tiro (angolo, forza, spin) → pending_shot, fase moving
shot_result
POST
Risultato della simulazione (biglie + eventi) → validazione → nuovo stato; segnalato da qualsiasi giocatore seduto (risultato deterministico)
Anti-cheat — validazione di shot_result lato server
16 biglie, posizioni entro i confini del panno (fuori dal panno solo nei corridoi delle buche)
Una biglia non può: scomparire senza un'imbucata dichiarata, apparire dal nulla, sovrapporsi a un'altra
(distanza min. 12 px)
Imbucate: nessun duplicato, solo biglie presenti sul tavolo, struttura corretta (biglia 0–15, buca 0–5)
Il primo contatto deve essere legale (gruppo / nera secondo le regole)
Risultato rifiutato: contatore fails; 2 segnalazioni errate corrispondenti = fallo e fine del tiro
Sedersi richiede min_balance; start_game preleva da entrambi i giocatori
blind (quota) → montepremi = 2× puntata.
Il vincitore si aggiudica l'intero montepremi; in caso di eliminazione del tavolo durante la partita, il montepremi viene rimborsato al 50%.
Saldo in baza/<uid>/stankonta.txt; scritture sotto LOCK_EX.
10. Ranghi e calcolatore VIP
Rango
Assegnato
Privilegio
normal
automaticamente alla registrazione
—
silver / gold
admin (elenco giocatori)
distintivo accanto al login
VIP
admin
% dinamica di probabilità di imbucata durante la mira
Calcolatore VIP (client, solo anteprima): calcola per la biglia mirata la traiettoria della biglia colpita —
direttamente, dopo il rimbalzo dalla sponda e in combinazione (biglia scagliata da quella colpita). La percentuale deriva
dall'intersezione fisica della traiettoria con la gola del canale della buca, dall'angolo di entrata e dagli ostacoli sul percorso. Vengono calcolate
solo le biglie legali (gruppo / qualsiasi quando i gruppi non sono assegnati). Verde ≥ 50%, rosso al di sotto;
scritta orizzontale anche in modalità verticale.
11. Pannello di amministrazione (admin.php)
Tavoli
Parametro
Intervallo
Note
Quota di iscrizione (blind)
≥ 1 valuta
montepremi = 2× puntata
Saldo min.
≥ quota
blocco del sedersi sotto la soglia
Colore panno
HEX
panno, canaline e ombre calcolati da questo colore
Diametro biglie
18–44 px
la fisica scala proporzionalmente
Tempo per mossa
5–300 s
"X s/mossa"
Dimensioni tavolo
320–1600 × 280–1400 px
solo tavolo — biglie rotonde, UI dimensione fissa (letterbox)
Schede dei tavoli: parametri, giocatori 0–2/2, montepremi sul tavolo, stato; azioni:
Arresta/Riprendi, Anteprima (modalità di sola lettura), Elimina.
Statistiche: giocatori registrati, giocatori online (attività < 120 s), numero di tavoli.
Elenco dei giocatori: login, saldo, tavolo attuale, menu a tendina dei ranghi.
Una nuova installazione crea 1 tavolo. Avviso in caso di password di amministrazione predefinita.
Interfaccia di gioco
Barra dei giocatori in alto: avatar + login + gruppo + miniature delle biglie; il giocatore attivo
ha un bordo dell'avatar dorato lampeggiante; al centro il montepremi e il pulsante REGOLE DEL GIOCO.
Pannello sotto il tavolo: punto di impatto, biglie imbucate in ordine, round/mossa.
Barra informativa: turno, falli, bianca in mano, movimento delle biglie, stato della partita.
"Inizia la partita" — pulsante al centro del tavolo; al termine = "Rivincita".
Modalità verticale (telefono): quando lo schermo è più alto che largo su un dispositivo mobile,
il tavolo viene visualizzato ruotato di −90°, adattato allo schermo. Ombre/riflessi compensano la rotazione
(la luce rimane orientata allo schermo), le scritte e la % VIP sono controruotate. Su PC sempre orizzontale.
12. Livello di sicurezza
(plik6).php modulo condiviso incluso da ogni file PHP pubblico:
Licenza di dominio (anti-furto): lo script funziona solo sui domini dell'elenco
SEC_LICENSED_HOSTS; la voce .dominio include tutti i sottodomini.
Dominio non autorizzato → HTTP 403.
Sessione: cookie HttpOnly + SameSite=Lax + secure (HTTPS),
use_strict_mode, rigenerazione dell'ID dopo il login.
CSRF: token di sessione richiesto in tutte le azioni che modificano lo stato
(moduli, API admin, API di gioco).
Rate limiting: login admin 5/5 min, login giocatore 8/5 min,
registrazione 5/10 min — contatori per IP in baza/_ratelimit/.
Intestazioni: X-Frame-Options, nosniff, Referrer-Policy (anche in .htaccess).
.htaccess: blocco del listing, file nascosti, estensioni di dati
(.txt .json .hash .bak .zip …) e directory di file del file specyfikacja.html .
Password: dei giocatori — password_hash (bcrypt); dell'admin — hash in
.hash (al di fuori del codice).
Login: whitelist [A-Za-z0-9_-]{2,20} — elimina XSS tramite il login
nei pannelli e nei messaggi.
Autorizzazione: saldo solo proprio, tavoli solo dalla configurazione admin,
anteprima admin di sola lettura.
13. Note tecniche
PHP 5.6, JSON/TXT o SQL come archivio; compatibilità con semplice hosting Apache.
Client: puro JS + Canvas 2D, ES5; un unico file 8.php senza dipendenze esterne.
Simulazione deterministica (SIM_DT = 1/240) — entrambi i giocatori calcolano lo stesso movimento;
il risultato può essere segnalato da uno qualsiasi di essi, il server valida.
Coordinate della fisica sempre nel sistema 1000×620; TABLE_SCALE è solo la scala di disegno.
Tutte le scritture di stato sono atomiche sotto flock; json_encode fallito →
stato precedente preservato (senza pulire il file).
Per la protezione completa del codice sorgente contro il furto: ionCube Encoder / SourceGuardian
(il blocco del dominio è una barriera, non una cifratura).