Prin intermediul acestui proiect am explorat capabilitățile Greenfoot în ceea ce privește implementarea unui joc de biliard. Acesta încorporează o redare realistă a bilelor, în perspectivă 3D, având în vedere limitarea strictă spre elemente 2D a Greenfoot. Mai jos se află o mică demonstrație a proiectului (n.b. afișajul de depanare este activat, astfel că se pot vedea toate collider-ele atașate obiectelor):
Toate asset-urile jocului sunt create în cod, în directorul images al proiectului neexistând imagini prefabricate. Astfel, se pot modifica programatic diverse caracteristici ale obiectelor jocului cum ar fi dimensiunile mesei, dimensiunile bilelor, lungimea tacului etc. printr-o simplă apelare a unei funcții corespunzătoare (e.g. setWidth
, setHeight
, setRadius
).
Două elemente mai interesante de subliniat în ceea ce privește asset-urile jocului sunt bilele cu texturi ce creează un efect de tridimensionalitate a acestora (vezi clasa TexBall
) și umbrele (vezi clasa Glow
), aceste două elemente creând un aspect grafic mai plăcut.
Pentru realizarea efectului de tridimensionalitate a bilelor s-au folosit ecuațiile următoare, pentru convertirea coordonatelor texturilor la coordonate sferice:
x = r * cos(theta) * sin(phi); y = r * sin(theta) * sin(phi); z = r * cos(phi)
. Pixelii cu z < 0
nu contribuie la imaginea finală, dat fiind faptul că bilele se văd „de sus”, deci le este vizibilă doar calota superioară.
Textura din imaginea de mai jos este traversată, iar pentru fiecare pixel se calculează o coordonată sferică cu ajutorul unghiurilor theta
și phi
corespunzătoare pixelului în cauză:
Astfel, pe o altă imagine se desenează rezultatul sferizat al imaginii de mai sus, sub acesta aflându-se un disc alb desenat separat:
Pentru rotirea texturilor atunci când bilele se află în mișcare s-au folosit [cuaternioni] (vezi clasa Quaternion
).
Generarea umbrelor se face cu ajutorul bibliotecii externe JH Labs Java Image Filters, folosindu-se un filtru de tip BoxBlurFilter
.
Umbrele poti fi de tip INNER
(vezi Pocket
, Table
) sau OUTER
(vezi Ball
, Cue
):
Efectul de umbră este creat prin construirea unui contur pentru forma obiectului, contur peste care se aplică filtrul de blur cu 3 iterații pentru a crea un efect de auroră în jurul sau în interiorul obiectului, în funcție de tipul umbrei. Culoarea umbrei poate fi schimbată (vezi setColor
în clasa Glow
).
Proiectul se folosește de un mic physics engine, referit în codul sursă ca Physics2
, pentru tot ceea ce înseamnă detecarea și rezolvarea coliziunilor dintre obiecte.
Coliziunile cerc-trapez sunt detectate în felul următor: știind vectorii pt_v
și seg_v
se proiectează pt_v
pe seg_v
, obținându-se vectorul closest
, care are aceeași origine ca pt_v
. Acum putem calcula dist_v
și, comparând modului acestui vector cu raza cercului putem determina dacă are loc o coliziune sau nu:
abs(dist_v) > r
=> nu are loc o coliziuneabs(dist_v) = r
=> cercul și trapezul doar se atingabs(dist_v) < r
=> are loc o coliziune
Coliziunile cerc-cerc se detectează mai simplu, fiindcă pur și simplu comparăm distanța dintre cele două cercuri cu suma razelor celor două cercuri. Dacă distanța e mai mică ca suma razelor cercurilor, atunci a avut loc o coliziune.
Coliziunile cerc-trapez se rezolvă prin reflectarea vectorului viteză al bilei față de normala la planul de coliziune.
Coliziunile cerc-cerc se rezolvă prin despărțirea vectorilor viteză ai bilelor relativ la planul de coliziune într-o componentă normală și o componentă tangențială:
Componentele tangențiale ale vitezelor rămân neschimbate. În schimb, componentele normale, dat fiind faptul că masele bilelor sunt egale, sunt schimbate între ele: