Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

JMonkey Engine 3.0: giochi 3D per java (e android)

Breve presentazione dell'engine 3d JMonkey, pensato per applicazioni desktop e... android.
Breve presentazione dell'engine 3d JMonkey, pensato per applicazioni desktop e... android.
Link copiato negli appunti

Con questo articolo introduciamo Jmonkey: un'interessante framework opnesource per la realizzazione di giochi 3D con il linguaggio Java. Il framework utilizza una licenza BSD, ed è liberamente utilizzabile per hobby, fini educazionali o commerciali. L'aspetto particolarmente interessante è quello di poter realizzare giochi non soltanto per piattaforme desktop, ma anche per il web (pensiamo alla crescente richiesta di giochi per le piattaforme "social", come facebook) o per i dispositivi Android.

JMonkeyEngine è un engine ad alte performance scritto in Java e che utilizza LWJGL per l'accesso ad OpenGL. LWJGL (Lightweight Java Game Library) è la libreria Java che permette agli sviluppatori l'accesso a librerie quali OpenGL (Open Graphics Library), OpenCL (Open Computing Language), OpenAL (Open Audio Library).

La libreria è disponibile per Windows, Linux e Mac. I requisiti hardware sono i seguenti:

Sistemi operativi Mac OS X, Windows, Linux, or Solaris
Memoria (JVM heap size) > 40 MB + memory for assets
CPU 1 GHz
Scheda grafica ATI Radeon 9500, NVIDIA GeForce 5 FX, Intel GMA 4500, o superiori supporto OpenGL 2.0 (ultimo driver raccomandato)
Java Development Kit JDK 6

Vogliamo fornire un assaggio di questo motore 3D vedendo l'esecuzione di una applicazione base che visualizzerà una scena 3D di una piccola cittadina. Proviamo il tutto sotto Windows: scarichiamo ed installiamo la platform di sviluppo dall'url:

http://jmonkeyengine.org/downloads/

Una volta completata l'installazione lanciamo l'ambiente.Dovremmo trovarci di fronte ad una schermata simile alla seguente:

Figura 1. schermata inziale applicazione
(clic per ingrandire)


schermata inziale applicazione

Il progetto Basic Game

É il momento di creare il primo progetto, che chiameremo per semplicità BasicGame:

Figura 2. creazione del progetto BasicGame
(clic per ingrandire)


creazione del progetto BasicGame

A questo punto, nel package mygame creato automaticamente definiamo una classe con il nome HelloCollision. All'interno della classe importiamo i seguenti package necessari per la demo:

public class HelloCollision
	extends SimpleApplication
	implements ActionListener {
    // ...
}

Iniziamo con l'aggiungere le seguenti variabili di istanza che utilizzeremo successivamente:

private BulletAppState bulletAppState;
private Spatial sceneModel;
private RigidBodyControl landscape;
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, up = false, down = false;

L'esempio fa uso di quella che viene chiamata game physics (l'implementazione della fisica nel gioco, insomma); ne abbiamo bisogno per simulare massa, gravità, collisioni: pensiamo ad esempio ai fenomeni fisici nel gioco del biliardo o nei giochi che simulano corse di auto. Per utilizzarla abbiamo bisogno di un oggetto BulletAppState che si inizializza con le seguenti righe di codice

bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
definiamo all'interno della classe il metodo
public void simpleInitApp() {
     bulletAppState = new BulletAppState();
     stateManager.attach(bulletAppState);
	// ...
}

e cominciamo con l'inserire al suo interno le righe di codice appena descritte. La variabile stateManager è ereditata dalla superclasse Application superclasse, a sua volta, di SimpleApplication, questa variabile ci consente di gestire lo stato del bullet.

Dopo aver inizializzato le funzionalità di game physics, facciamo lo stesso per la Camera, ovvero ciò che ci consentirà il movimento all'interno dell'ambiente 3D:

public void simpleInitApp() {
	bulletAppState = new BulletAppState();
	stateManager.attach(bulletAppState);
	viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
	flyCam.setMoveSpeed(100);
}

Anche viewPort è ereditata dalla classe Application e qui viene utilizzata per impostare il background color; flyCam (anch'essa nella classe Application) è una estensione della Camera di default presente nella classe SimpleApplication. La flyCam è preconfigurata per rispondere ai tasti W,A,S,D che ci permetteranno diruotare all'interno dell'ambiente nelle 4 direzioni.

Interazione con l'utente

Per completare la configurazione del movimento all'interno dell'ambiente, definiamo il seguente metodo che invochiamo subito dopo l'istruzione relativa a flyCam:

private void setUpKeys() {
	inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
	inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
	inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
	inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
	inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
	inputManager.addListener(this, "Left");
	inputManager.addListener(this, "Right");
	inputManager.addListener(this, "Up");
	inputManager.addListener(this, "Down");
	inputManager.addListener(this, "Jump");
}

L'interazione con l'utente avviene attraverso la tastiera, il mouse, il joystick, per gestire questi dispositivi si fa uso dell'oggetto inputManager ereditato dalla classe SimpleApplication.

Attraverso il metodo addMapping definiamo dei trigger che si attivano per determinate azioni. Ad esempio Left, Right, Up, Down rappresentano le azioni di movimento verso sinistra, destra, in alto, in basso. Nel metodo addMapping le specifichiamo attraverso il primo parametro, mentre con il secondo indichiamo,nel nostro caso, quale tasto premuto le attiva : KeInput.KEY_A tasto con lettera A, KeyInput.KEY_B tasto con lettera B e cosi via. Il metodo addListener serve per impostare l'ascoltatore per le azioni-evento.

Il metodo simpletInitApp diventa:

public void simpleInitApp() {
	bulletAppState = new BulletAppState();
	stateManager.attach(bulletAppState);
	viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
	flyCam.setMoveSpeed(100);
	setupKeys();
}

gestione della luce e delle ombre

Il prossimo aspetto da considerare e la gestione delle luci e delle ombre: ad ogni oggetto visibile dovrà avere associata una sorgente di luce con una locazione e direzione.

In JMonkey abbiamo a disposizione differenti tipi di sorgenti di luce. Quelle che utilizziamo in questo esempio sono DirectionalLight e AmbientLight. DirectionalLight è caratterizzata dal non avere posizione ma solo direzione, è considerata infinita, tipicamente usata per simulare la luce del sole.

AmbientLight viene utilizzata per influenzare la luminosità della scena globale, non ha direzione ne posizione e non comporta nessuna ombra. Inizializziamo queste sorgenti di luce all'interno del seguente metodo:

private void setUpLight() {
	AmbientLight al = new AmbientLight();
	al.setColor(ColorRGBA.White.mult(1.3f));
	rootNode.addLight(al);
	DirectionalLight dl = new DirectionalLight();
	dl.setColor(ColorRGBA.White);
	dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
	rootNode.addLight(dl);
}

che invochiamo subito dopo setupKeys all'interno del metodo simpleInitApp:

public void simpleInitApp() {
	bulletAppState = new BulletAppState();
	stateManager.attach(bulletAppState);
	viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
	flyCam.setMoveSpeed(100);
	setupKeys();
	setupLight();
}

configurazione della scena

A questo punto continuiamo caricando tutto l'ambiente all'interno del quale ci muoveremo, definito in termini di risorse immagini, font, suoni, nel file town.zip. Il codice da aggiungere dopo setupLight è il seguente:

assetManager.registerLocator("town.zip", ZipLocator.class.getName());
sceneModel = assetManager.loadModel("main.scene");
sceneModel.setLocalScale(2f);

assetManager è ereditata dalla classe Application estesa da SimpleApplication, mentre sceneModel è stata dichiarata come variabile di istanza precedentemente. Il codice del metodo si completa con la gestione delle collisioni tra l'ambiente ed il giocatore che si muove in esso:

CollisionShape sceneShape =
CollisionShapeFactory.createMeshShape((Node) sceneModel);
landscape = new RigidBodyControl(sceneShape, 0);
sceneModel.addControl(landscape);
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
player = new CharacterControl(capsuleShape, 0.05f);
player.setJumpSpeed(20);
player.setFallSpeed(30);
player.setGravity(30);
player.setPhysicsLocation(new Vector3f(0, 10, 0));

le seguenti ultime righe di codice completano la configurazione della scena ed il metodo simpleInitApp:

rootNode.attachChild(sceneModel);
bulletAppState.getPhysicsSpace().add(landscape);
bulletAppState.getPhysicsSpace().add(player);

La classe HelloCollision implementa com.jme3.input.controls.ActionListener. Questa classe definisce il metodo onAction che dobbiamo implementare.Ecco il codice che inseriamo in HelloCollision:

public void onAction(String binding, boolean value, float tpf) {
	if (binding.equals("Left")) {
		if (value) { left = true; } else { left = false; }
	} else if (binding.equals("Right")) {
		if (value) { right = true; } else { right = false; }
	} else if (binding.equals("Up")) {
		if (value) { up = true; } else { up = false; }
	} else if (binding.equals("Down")) {
		if (value) { down = true; } else { down = false; }
	} else if (binding.equals("Jump")) {
		player.jump();
	}
}

il codice all'interno del metodo non effettua nessun movimento in una determinata direzione ma ne mantiene solo traccia. La classe SimpleApplication ha un metodo

public void simpleUpdate(float tpf)

la cui implementazione è vuota. Dobbiamo fare override di questo metodo in HelloCollision:

@Override
public void simpleUpdate(float tpf) {
	Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
	Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
	walkDirection.set(0, 0, 0);
	if (left)  { walkDirection.addLocal(camLeft); }
	if (right) { walkDirection.addLocal(camLeft.negate()); }
	if (up)    { walkDirection.addLocal(camDir); }
	if (down)  { walkDirection.addLocal(camDir.negate()); }
	player.setWalkDirection(walkDirection);
	cam.setLocation(player.getPhysicsLocation());
}

Attraverso questo metodo viene ripetutamente controllata la posizione della camera. Grazie alla direzione forward(camDir) e left(leftDir) della camera, si riesce a determinare la posizione del giocatore. Attraverso setWalkDirection() sull'oggetto player, definito come variabile di istanza in HelloCollision, realizziamo quella che viene chiamata physics-controlled object per il movimento fluido e continuo dell'oggetto, inoltre il physics engine gestisce le collisioni per noi. Con l'ultima istruzione invece si fa in modo, invece, che la camera segua il giocatore.

L'applicazione demo è praticamente conclusa, dobbiamo aggiungere in HelloCollision il metodo main di lancio:

public static void main(String[] args) {
	HelloCollision app = new HelloCollision();
	app.start();
}

Infine copiamo all'interno del cartella del progetto il file town.zip fornito in allegato con l'articolo. Questo file contiene tutto ciò che riguarda la grafica dell'ambiente. Siamo pronti per compilare e lanciare l'applicativo HelloCollision. La prima schermata che viene visualizzata è quella di lancio:

Figura 3. jmonkey: schermata di lancio dell'applicazione, con selezione del tipo di visualizzazione
(clic per ingrandire)


jmonkey: schermata di lancio dell'applicazione

Facendo click su ok partirà finalmente la nostra demo in un piccolo ambiente 3D, all'interno del quale possiamo muoverci con i tasti freccia e i tasti w,a,s,d:

Figura 4. jmonkey: l'ambiente 3D di prova
(clic per ingrandire)


jmonkey: l'ambiente 3D di prova

Conclusioni

Abbiamo introdotto velocemente il software senza soffermarci sugli aspetti realizzativi e concetti matematici 3D, necessari per poter comprendere i codice scritto, e poter effettivamente sfruttare la libreria partendo da un livello principiante. Potete trovare questo ed altri tutorial al seguente link:

http://jmonkeyengine.org/wiki/doku.php/jme3:beginner

Nei prossimi articoli vedremo in dettaglio le caratteristiche fondamentali degli strumenti messi a disposizione, concetti matematici alla base del loro utilizzo e come costruire oggetti ed ambienti.

Ti consigliamo anche