Inleiding tot JavaFX vir Spelontwikkeling
JavaFX is 'n kruis platform GUI toolkit vir Java, en is die opvolger van die Java Swing biblioteke. In hierdie handleiding sal ons die funksies van JavaFX ondersoek wat dit maklik maak om Java-spele te gebruik.
Hierdie handleiding neem aan dat jou reeds weet hoe om in Java te kodeer. Indien nie, lees gerus Leer Java vir Android, Inleiding tot Rekenaarprogrammering Met Java: 101 en 201, Kop eers Java, Greenfoot, of leer Java die moeilike manier om te begin.
As jou reeds programme met Java ontwikkel, hoef jou waarskynlik niks hoegenaamd te laai nie: JavaFX is ingesluit by die standaard JDK (Java Development Kit) bundel sedert JDK weergawe 7u6 (Augustus 2012). As jou nie u Java installasie op 'n geruime tyd opgedateer het nie, gaan na die Java download website vir die nuutste weergawe.
Die skep van 'n JavaFX-program begin met die Application klas, waaruit alle JavaFX-programme uitgebrei word. Jou hoofklas moet die launch () metode noem, wat dan die init () metode en dan die begin () metode sal wag, wag tot die program klaar is en dan die stop () metode. Van hierdie metodes is slegs die begin () metode abstrak en moet dit oortree word.
Die Stage klas is die JavaFX houer op die hoogste vlak. Wanneer 'n aansoek geloods word, word 'n aanvanklike stadium geskep en geslaag na die program se begin metode. Stadiums beheer basiese venster eienskappe soos titel, ikoon, sigbaarheid, resizability, fullscreen modus en versierings; laasgenoemde is ingestel met behulp van StageStyle. Bykomende stadiums kan gebou word soos nodig. Nadat 'n stadium is ingestel en die inhoud bygevoeg word, word die metode show() genoem.
As ons dit alles weet, kan ons 'n minimale voorbeeld skryf wat 'n venster in JavaFX bekendstel:
Strukturering van Inhoud
Inhoud in JavaFX (soos teks, beelde en UI-kontroles) word georganiseer met behulp van 'n boomagtige datastruktuur wat bekend staan ​​as 'n scene graph, wat die elemente van 'n grafiese toneel groepeer en rangskik.
Verteenwoordiging van 'n JavaFX Skets Grafiek.
'N Algemene element van 'n toneelgrafiek in JavaFX word 'n Node. Elke knoop in 'n boom het 'n enkele "ouer'' knoop, met die uitsondering van 'n spesiale knoop wat aangewys is as die ''wortel''. 'N Groep is 'n node wat baie "kind" node elemente kan hê. Grafiese transformasies (vertaling, rotasie en skaal) en effekte wat op 'n groep toegepas word, is ook van toepassing op sy kinders. Nodes kan gestileer word met behulp van JavaFX Cascading Style Sheets (CSS), wat baie ooreenstem met die CSS wat gebruik word om HTML dokumente te formateer.
Die Scene klas bevat alle inhoud vir 'n toneelgrafiek en vereis dat 'n wortelnodus ingestel word (in die praktyk is dit dikwels 'n Groep). Jou kan die grootte van 'n toneel spesifiek spesifiseer; Andersins sal die grootte van 'n toneel outomaties bereken word op grond van die inhoud daarvan. 'N Scenario-voorwerp moet aan die stadium oorgedra word (volgens die setScene() metode) om vertoon te word.
Die lewering van grafika is veral belangrik vir spelprogrammeerders! In JavaFX is die Canvas voorwerp 'n beeld waarop ons teks, vorms en beelde kan teken deur die gepaardgaande GraphicsContext voorwerp te gebruik. (Vir die ontwikkelaars wat bekend is met die Java Swing toolkit, is dit soortgelyk aan die Grafiese voorwerp wat geslaag is in die verf() metode in die JFram -klas.)
Die GraphicsContext voorwerp bevat 'n magdom kragtige aanpassingsvermoëns. Om 'n kleur te kies vir die teken van tekste en vorms, kan jou die invulkleur (binnekant) en beroerte (grens) stel Paint voorwerp: dit kan 'n soliede een wees Color, gebruiker gedefinieerde gradiënt (fyn LinearGradient of RadialGradient),of selfs a ImagePattern. Jou kan ook een of meer Effect styl voorwerpe, soos Lighting, Shadow, of GaussianBlur, en verander die font van verstek deur gebruik te maak Font klas.
Die Image klas maak dit maklik om beelde uit 'n verskeidenheid formate van lêers te laai en teken dit via die GraphicsContext-klas. Dit is maklik om prosedureel gegenereerde prente te konstrueer deur die WritableImage klas saam met die PixelReader en PixelWriter klasse.
Deur hierdie klasse te gebruik, kan ons 'n baie meer waardige ''Hello, World'' -stylvoorbeeld soos volg skryf. Vir kortheid, sal ons net die begin() metode hier insluit (ons sal die invoerstate en hoof() metode slaan); Die volledige bronkode kan egter gevind word in die GitHub repo wat hierdie tutoriaal vergesel.
Vervolgens moet ons programme dinamies maak, wat beteken dat die spelstaat oor tyd verander. Ons sal aansoek doen game loop:'n oneindige lus wat die spelobjek bywerk en skerms op die skerm maak, ideaal teen spoed van 60 keer per sekonde.
Die maklikste manier om dit te bereik in JavaFX, gebruik die AnimationTimer klas, waar 'n metode (genoem handle()) geskryf kan word wat teen 'n tempo van 60 keer per sekonde genoem word, of so naby aan die koers as moontlik. (Hierdie klas hoef nie net vir animasie doeleindes gebruik te word nie; dit kan veel meer.)
Die gebruik van die AnimationTime klas is 'n bietjie lastig: aangesien dit 'n abstrakte klas is, kan dit nie direk geskep word nie. Die klas moet verleng word voordat 'n voorbeeld geskep kan word. Maar vir ons eenvoudige voorbeeld sal ons die klas uitbrei deur te skryf anonymous inner class. Hierdie innerlike klas moet die abstrakte metode handle(), wat 'n enkele argument gaan gee: die huidige stelsel tyd in nanosekondes. Na die definisie van die innerlike klas, doen ons dadelik die start() metode, wat die lus begin. (Die lus kan gestop word deur die stop() metode te skakel.)
Met hierdie klasse kan ons ons 'Hello, World' voorbeeld verander, wat 'n animasie skep wat bestaan ​​uit die Aarde wat om die Son wentel, teen 'n sterrige agtergrondbeeld.
Daar is alternatiewe maniere om 'n spellus in JavaFX te implementeer. 'N Effens langer (maar meer buigsame) benadering behels die Timeline klas, wat 'n animasie reeks is wat bestaan ​​uit 'n stel KeyFrame voorwerpe. Om 'n spellus te skep, moet die tydlyn vir onbepaalde tyd herhaal word, en slegs 'n enkele KeyFrame word vereis, met 'n Duration van 0.016 sekondes (om 60 siklusse per sekonde te bereik). Hierdie implementering kan gevind word in die Example3T.java lêer in die GitHub repo.
Nog 'n algemeen benodigde spelprogrammeringskomponent is raamgebaseerde animasie: 'n reeks beelde word vinnig vertoon om die illusie van beweging te skep.
As dit aanvaar word dat alle animasies loop en alle rame vir dieselfde aantal sekondes vertoon, kan 'n basiese implementering so eenvoudig soos volg wees:
Om hierdie klas in die vorige voorbeeld te integreer, kan ons 'n geanimeerde UFO skep wat die voorwerp initialiseer deur die kode te gebruik:
... en binne die AnimationTimer, voeg die enkele reël kode by:
... op die toepaslike plek. Vir 'n volledige werk kode voorbeeld, sien die lêer Example3AI.java in die GitHub repo.
Hantering van Gebruikerinvoer
Die opsporing en verwerking van gebruikersinvoer in JavaFX is eenvoudig. Gebruiker aksies wat deur die stelsel opgespoor kan word, soos sleuteldrukke en muisklikke, word gebeurtenisse genoem. In JavaFX veroorsaak hierdie aksies outomaties die opwekking van voorwerpe (soos KeyEvent en MouseEvent) wat die gepaardgaande data stoor (soos die werklike sleutel gedrukte of die plek van die muiswyser). Enige JavaFX-klas wat die EventTarget klas implementeer, soos 'n toneel, kan "luister" vir gebeurtenisse en hanteer dit; In die voorbeelde wat volg, sal ons wys hoe om 'n toneel op te stel om verskeie gebeure te verwerk.
Deur die dokumentasie vir die Scene klas te kyk, is daar baie metodes wat luister vir die hantering van verskillende tipes insette uit verskillende bronne. Byvoorbeeld, die metode setOnKeyPressed() kan 'n EventHandler toewys wat sal aktiveer wanneer 'n sleutel gedruk word. Met die metode setOnMouseClicked() kan 'n EventHandler wat aktiveer wanneer 'n muisknop gedruk word, toewys. Die EventHandler-klas dien as een doel: om 'n metode te inkapsuleer (genoem handvat()) wat genoem word wanneer die ooreenstemmende gebeurtenis plaasvind.
Wanneer EventHandler skep, moet jou die tipe gebeurtenis wat hanteer word, spesifiseer: jou kan 'n EventHandler <keyEven> of a EventHandler<mouseEvent>,byvoorbeeld. EventHandlers word ook dikwels as anonieme innerlike klasse geskep, aangesien hulle tipies slegs een keer gebruik word (wanneer hulle as 'n argument aangewys word by een van die bostaande metodes).
Hantering van Sleutelbordgebeure
Gebruikerinvoer word dikwels binne die hoofspeling uitgevoer, en dus moet 'n rekord gehou word van watter sleutels tans aktief is. Een manier om dit te bereik, is deur 'n ArrayList of String voorwerpe te skep. Wanneer 'n sleutel aanvanklik gedruk word, voeg ons die Stringvoorstelling van die KeyEvent se KeyCode by die lys toe; Wanneer die sleutel vrygestel word, verwyder ons dit uit die lys.
In die voorbeeld hieronder bevat die doek twee beelde van pyltjie sleutels; Wanneer 'n sleutel gedruk word, word die ooreenstemmende beeld groen.
Die bronkode is vervat in die lêer Example4K.java in die GitHub repo.
Hantering van Muisgebeure
Kom ons kyk nou na 'n voorbeeld wat fokus op die MouseEvent klas eerder as die KeyEvent klas. In hierdie mini-speletjie verdien die speler 'n punt elke keer as die teiken gekliek word.
Aangesien die EventHandlers innerlike klasse is, moet enige veranderlikes wat hulle gebruik finaal of ''effektief finaal'' wees, wat beteken dat die veranderlikes nie heritialiseer kan word nie. In die vorige voorbeeld is die data oorgedra aan die EventHandler deur middel van 'n ArrayList, waarvan die waardes verander kan word sonder om te herkitialiseer (via die add() en remove() metodes).
In die geval van basiese datatipes kan die waardes egter nie verander word sodra dit geïnitialiseer is nie. As jou wil hê dat EventHandler toegang tot basiese datatipes wat elders in die program verander word, kan jou 'n wikkelklas skep wat publieke veranderlikes of getter/setter metodes bevat. (In die voorbeeld hieronder, IntValue is 'n klas wat 'n openbare int veranderlike genoteerde waarde value.)
Die volledige bronkode is vervat in die GitHub-repo; die hoofklas is Example4M.java.
Die Skep van 'nBbasiese Sprite Klas Met JavaFX
In videospeletjies is 'n sprite die term vir 'n enkele visuele entiteit. Hieronder is 'n voorbeeld van 'n Sprite-klas wat 'n beeld en posisie stoor, sowel as snelheidsinligting (vir mobiele entiteite) en wydte/hoogte-inligting wat gebruik moet word wanneer grensboksies bereken word vir die botsingsdeteksie. Ons het ook die standaard getter/setter metodes vir die meeste van hierdie data (weggelaat vir kortheid), en 'n paar standaard metodes wat nodig is in spel ontwikkeling:
update() : bereken die nuwe posisie gebaseer op die Sprite se snelheid.
render() : teken die geassosieerde prent na die doek (via die GraphicsContext klas) deur die posisie as koördinate te gebruik.
getBoundary(): gee 'n JavaFX Rectangle2D voorwerp, wat nuttig is in botsingsopsporing as gevolg van die kruisingsmetode.
intersects() : bepaal of die grenskassie van hierdie Sprite sny met dié van 'n ander Sprite.
Die volledige bronkode is ingesluit in Sprite.java in die GitHub-repo.
Gebruik die Sprite Klas
Met die hulp van die Sprite-klas kan ons maklik 'n eenvoudige versamel spel in JavaFX skep. In hierdie speletjie neem jy die rol van 'n sentrieke aktetas aan, wie se doel is om die baie geldtasse wat deur 'n onverskillige vorige eienaar gelê is, in te samel. Die pyltjie sleutels beweeg die speler om die skerm.
Hierdie kode leen swaar uit vorige voorbeelde: die opstel van lettertipes om die telling te vertoon, sleutelbordinvoer met 'n ArrayList te stoor, die spellus te implementeer met 'n AnimationTimer, en die skep van wikkelklasse vir eenvoudige waardes wat tydens die spellus verander moet word.
Een segment van 'n spesifieke belangstelling kode behels die skep van 'n Sprite-voorwerp vir 'n speler (bagasie) en 'n ArrayList of Sprite-voorwerp vir 'n versameling (sakgeld):
Nog 'n voorkeur kode segment is die skep van AnimationTimer, wat toegeken word:
die verloop van die tyd sedert die laaste opdatering
die spoed van die speler hang af van die knoppie wat tans gedruk word
botsingsopsporing tussen spelers en versamelings uitvoer, en werk tellings en versamelingslyste op wanneer dit gebeur. (Iterators word in plaas van ArrayList gebruik om direk te vermy Concurrent Modification Exception wanneer voorwerpe uit die lys verwyder word)
spreuke en teks na doek gemaak
Soos altyd kan die volledige kode gevind word in die aangehegte kode lêer (Example5.java) in die GitHub-repo.
Daar is 'n reeks inleidende tutoriale op die Oracle webwerf, wat jou sal help om te leer oor algemene JavaFX take: Getting Started with JavaFX Sample Applications.
Jou sal dalk belangstel om te leer hoe om die Tema Skepper te gebruik, 'n visuele uitleg omgewing vir die ontwerp van gebruikerskoppelvlakke. Hierdie program genereer FXML, wat 'n XML-gebaseerde taal is wat gebruik kan word om die gebruikerskoppelvlak vir JavaFX programme te definieer. Vir hierdie, sien JavaFX Scene Builder: Getting Started.
FX Experience is 'n goeie blog wat gereeld opgedateer word, met inligting en voorbeeldprojekte wat van belang is vir JavaFX ontwikkelaars. Baie van die genoemde demonstrasies is baie inspirerende!
José Pereda het 'n baie goeie voorbeeld van 'n meer gesofistikeerde speletjie wat met JavaFX geskep is his GitHub repository.
Die JFxtras-projek bestaan ​​uit 'n groep ontwikkelaars wat ekstra JavaFX komponente geskep het wat die huidige algemene funksies wat van JavaFX ontbreek verskaf.
Die JavaFXPorts-projek laat jou toe om jou JavaFX-programme te verpak vir implementering op iOS en Android.
jou moet spesifiek 'n amptelike verwysing vir JavaFX merk, Oracle's JavaFX guide en API documentation.
Sommige goed-hersiene boeke op JavaFX sluit in Pro JavaFX 8,JavaFX 8 - Introduction by Example, en, 'n spesiale belangstelling vir spelontwikkelaars, Beginning Java 8 Games Development.
In hierdie handleiding, stel ek jou voor vir 'n JavaFX klas wat nuttig is in spelprogrammering. Ons werk deur 'n reeks voorbeelde van verhoogde kompleksiteit, wat uitloop op sprite-gebaseerde versamelingstylspeletjies. Nou is jou gereed om sommige van die bogenoemde bronne te ondersoek, of om in te spring en jou eie spel te begin skep. Beste geluk aan jou in jou pogings!