10 urodziny NetBeans!

NetBeans Decathlon to konkurs zorganizowany na 10. urodziny NetBeans. A skoro urodziny, to prezenty! Dlatego 300 pierwszych osób otrzyma koszulki NetBeans z limitowanej serii wydanej specjalnie na 10. urodziny.

By wziąć udział w konkursie wystarczy wykonać zadania, których łączna wartość punktowa wyniesie 50 lub więcej. Zadania są różnorodne, od napisania posta na blogu, nagrania filmu lub podcastu, przez wypełnienie ankiety aż do publikacji wiadomości lub zdjęć na grupie NetBeans w serwsie Facebook. Pełna lista zadań dostępna jest na stronie NetBeans Decathlon, podobnie jak formularz, w którym zgłaszamy się do konkursu oraz deklarujemy wykonane zadania (i podajemy linki do “dowodów rzeczowych”). Powodzenia i szybkości w reakcji, bo kto pierwszy, ten lepszy!

Ganymede – co nowego?

Pobawiłem się już chwilę najnowszą edycją Eclipse, wg mnie najważniejsze nowości to:

Po zerowe: ładniejszy splash:

Free Image Hosting at www.ImageShack.us vs Free Image Hosting at www.ImageShack.us

Po pierwsze – jest szybszy! Ładowanie projektu trwa krócej i całe środowisko daje subiektywne wrażenie szybszego działania 🙂

Po drugie – breadcrumbs, czyli rewelacyjne uproszczenie w nawigacji:

Free Image Hosting at www.ImageShack.us

Po trzecie: nie udało mi się do tej pory ani razu wywrócić nowego eclipse’a, mimo że wypchałem go już moimi ulubionymi pluginami. Super!

Po czwarte: ‘ktoś’ wreszcie wymyślił, że update’y były skopane i stworzono zupełnie nowy ekran:

Free Image Hosting at www.ImageShack.us

Java Monkey Engine with Eclipse Ganymede

25 czerwca wydana została nowa wersja Eclipse o kosmicznej nazwie Ganymede. Mimo, że na co dzień używam czegoś zupełnie innego, muszę zobaczyć co u konkurencji słychać 😀 Dodatkowo z okazji wydania Ganymede fundacja Eclipse zorganizowała Ganymede Around the World Contest. Ja z kolei od jakiegoś czasu bawię się Java Monkey Engine, wiec postanowiłem coś o nim napisać.

Na początek… co to jest JME?

To pełnoprawny (czyt. w pełni wypasiony :D) silnik do tworzenia gier, wspierający grafikę przestrzenną i dzwięk 3d. Ale jak to, w Javie? A tak! Oczywiście zgodnie z filozofią platformy, nie obeszło sie bez natywnych bibliotek, ale coś za coś, a tutaj ‘cały komplet’ cosiów jest dostarczony wraz z jme.

Zaczynamy: z repozytorium sciągamy aktualną wersję JME2, kompilujemy (ant dist-all) i dodajemy do naszego projektu biblioteki. Istnieje też repozytorium jme na java.net, ale zawiera kod w starszej (1.x) wersji.

Ponieważ będzie to pierwsza aplikacja, nie będzie robiła niczego skomplikowanego – ot, zainicjalizujemy sobie wyświetlacz i pokażemy kilka obiektów.

Glówna klasa naszego programu oparta będzie o klasę com.jme.app.SimpleGame – dzięki temu nie będziemy musieli (tym razem!) wykonywać wielu czynności ręcznie – implementacji dostarczy nam właśnie klasa SimpleGame. Pozostaje ja tylko rozszerzyć 🙂


1
public class Demo extends com.jme.app.SimpleGame {<br /><br />   public static void main(String[] args) {<br />       Demo demo = new Demo();<br />       demo.start();<br /><br />       System.out.println("Done with the game");<br />   }<br /><br />   @Override<br />   protected void simpleInitGame() {<br />       // TODO Auto-generated method stub<br />   }<br />}

Z ciekawości i niecierpliwości spróbujemy uruchomić już teraz i… Niestety, nie działa.


1
<br />   Jul 16, 2008 12:35:47 AM com.jme.app.BaseGame start<br />   INFO: Application started.<br />   Jul 16, 2008 12:35:47 AM com.jme.system.PropertiesGameSettings &lt;init&gt;<br />   INFO: PropertiesGameSettings created<br />   Jul 16, 2008 12:35:47 AM com.jme.system.PropertiesGameSettings load<br />   WARNING: Could not load properties. Creating a new one.<br />   Jul 16, 2008 12:35:47 AM com.jme.app.BaseSimpleGame initSystem<br />   INFO: jME version 2.0 dev build 1<br />   Jul 16, 2008 12:35:47 AM com.jme.input.joystick.DummyJoystickInput &lt;init&gt;<br />   INFO: Joystick support is disabled<br />   Jul 16, 2008 12:35:47 AM com.jme.system.lwjgl.LWJGLDisplaySystem &lt;init&gt;<br />   INFO: LWJGL Display System created.<br />   Jul 16, 2008 12:35:47 AM class pl.ags.jme.Demo start()<br />   SEVERE: Exception in game loop<br />   java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path<br />      at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)<br />      at java.lang.Runtime.loadLibrary0(Runtime.java:823)<br />      at java.lang.System.loadLibrary(System.java:1030)<br />      at org.lwjgl.Sys$1.run(Sys.java:72)<br />      at java.security.AccessController.doPrivileged(Native Method)<br />      at org.lwjgl.Sys.doLoadLibrary(Sys.java:65)<br />      at org.lwjgl.Sys.loadLibrary(Sys.java:81)<br />      at org.lwjgl.Sys.&lt;clinit&gt;(Sys.java:98)<br />      at org.lwjgl.opengl.Display.&lt;clinit&gt;(Display.java:128)<br />      at com.jme.system.lwjgl.LWJGLDisplaySystem.getValidDisplayMode(Unknown Source)<br />      at com.jme.system.lwjgl.LWJGLDisplaySystem.selectMode(Unknown Source)<br />      at com.jme.system.lwjgl.LWJGLDisplaySystem.initDisplay(Unknown Source)<br />      at com.jme.system.lwjgl.LWJGLDisplaySystem.createWindow(Unknown Source)<br />      at com.jme.app.BaseSimpleGame.initSystem(Unknown Source)<br />      at com.jme.app.BaseGame.start(Unknown Source)<br />      at pl.ags.jme.Demo.main(Demo.java:10)<br />   Jul 16, 2008 12:35:47 AM com.jme.app.BaseSimpleGame cleanup<br />   INFO: Cleaning up resources.<br />   Jul 16, 2008 12:35:47 AM com.jme.app.BaseGame start<br />   INFO: Application ending.<br />   Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class org.lwjgl.opengl.Display<br />      at com.jme.system.lwjgl.LWJGLDisplaySystem.close(Unknown Source)<br />      at com.jme.app.BaseGame.quit(Unknown Source)<br />      at com.jme.app.BaseSimpleGame.quit(Unknown Source)<br />      at com.jme.app.BaseGame.start(Unknown Source)<br />      at pl.ags.jme.Demo.main(Demo.java:10)<br />

Wpadliśmy, w dodatku przez te ‘nieszczęsne’ bindingi. 🙂 Na szczęście rozwiązanie problemu jest banalnie proste, wystarczy zadeklarować w parametrze java.library.path podać lokalizację bibliotek odpowiednich dla naszego systemu.

Np: Free Image Hosting at www.ImageShack.us
-Djava.library.path=c:/workspace/ganymede/jmeDemo/lib/lwjgl/native/win32

Spróbujmy jeszcze raz: coś sie włącza, (dzwięku nie ruszaliśmy, więc nie buczy), mruga – Hurra! Great success! Ale: co się dzieje, black screen?! Chociaz nie, w prawym górnym rogu jest napisane “F4 – toggle stats”. Czyli jednak działa 🙂 Czas więc najwyższy dodać cokolwiek do naszej gry, zeby nie wyglądala jak tor dla pcheł. Zrobimy sobie bardzo biedny model jakiegoś układu słonecznego. Układ składał się będzie z planety i gwiazdy.

new Sphere(“planet”, 10, 10, 10);

tworzy nową kulę o nazwie “planet” w polożeniu (10, 10, 10). Żeby nie było statycznie (nudno), planeta będzie kręcić się wokół własnej osi, a gwiazda rosnąć 🙂 Umiesćmy więc w metodzie simpleUpdate wywołania rotateSphere() i growSphere().


1
protected void simpleUpdate() {<br />   rotateSphere(planet);<br />   growSphere(star);<br />}<br /><br />private void rotateSphere(Sphere sphere) {<br />   angle = angle + (tpf * 1);<br />   if (angle &amp;gt; 360)<br />      angle = 0;<br /><br />   rotationQuat.fromAngleAxis(angle, axis);<br />   sphere.setLocalRotation(rotationQuat);<br />}<br /><br />private void growSphere(Sphere sphere) {<br />   Vector3f scale = sphere.getLocalScale();<br />   scale = scale.mult(1.0001f);<br />   sphere.setLocalScale(scale);<br />}<br />

1) www.ImageShack.us

1
demo.setConfigShowMode(AbstractGame.ConfigShowMode.AlwaysShow);


Metoda setCofnigShowMode ustala w jakich okolicznościach wyświetlone będzie okno z ustawieniami (wybiera sie rozdzielczość, głębię kolorów, tryb pełnoekranowy, renderer). My chcemy, zeby bylo widoczne za kazdym razem.

2) metoda simpleUpdate() jest wykonywana przy każdym przebiegu glównej pętli gry.
www.ImageShack.us

A tutaj cały kod naszej klasy (nie tej).


1
public class Demo extends com.jme.app.SimpleGame {<br />   private Quaternion rotationQuat = new Quaternion();<br />   private float angle = 0;<br />   private Vector3f axis = new Vector3f(1, 1, 0);<br /><br />   private Sphere planet;<br />   private Sphere star;<br /><br />   public static void main(String[] args)<br />   {<br />      Demo demo = new Demo();<br /><br />      demo.setConfigShowMode(AbstractGame.ConfigShowMode.AlwaysShow);<br />      demo.start();<br />   }<br /><br />   protected void simpleUpdate()<br />   {<br />      rotateSphere(planet);<br />      growSphere(star);<br />   }<br /><br />   private void rotateSphere(Sphere sphere)<br />   {<br />      angle = angle + (tpf * 1);<br />      if (angle &gt; 360)<br />      {<br />         angle = 0;<br />      }<br /><br />      rotationQuat.fromAngleAxis(angle, axis);<br />      sphere.setLocalRotation(rotationQuat);<br />   }<br /><br />   private void growSphere(Sphere sphere)<br />   {<br />      Vector3f scale = sphere.getLocalScale();<br />      scale = scale.mult(1.0001f);<br />      sphere.setLocalScale(scale);<br />   }<br /><br />   @Override<br />   protected void simpleInitGame()<br />   {<br />      display.setTitle(&quot;java malpa silnik&quot;);<br /><br />      planet = createEarth();<br />      star = createSun();<br />      rootNode.attachChild(star);<br />      rootNode.attachChild(planet);<br /><br />      try<br />      {<br />         MultiFormatResourceLocator loc2 = new MultiFormatResourceLocator(<br />            new File(&quot;c:/workspace/ganymede/jmeDemo/model&quot;).toURI(),<br />            &quot;.jpg&quot;, &quot;.png&quot;, &quot;.tga&quot;);<br />         ResourceLocatorTool.addResourceLocator(<br />            ResourceLocatorTool.TYPE_TEXTURE, loc2);<br />      }<br />      catch (Exception e)<br />      {<br />         e.printStackTrace();<br />      }<br /><br />      URL grass = ResourceLocatorTool.locateResource(<br />         ResourceLocatorTool.TYPE_TEXTURE, &quot;model/grass.jpg&quot;);<br />      URL sun = ResourceLocatorTool.locateResource(<br />         ResourceLocatorTool.TYPE_TEXTURE, &quot;model/sun.jpg&quot;);<br /><br />      TextureState grassTexture = loadTexture(grass);<br />      TextureState sunTexture = loadTexture(sun);<br /><br />      planet.setRenderState(grassTexture);<br />      star.setRenderState(sunTexture);<br />   }<br /><br />   private Sphere createEarth()<br />   {<br />      Sphere s = new Sphere(&quot;Earth&quot;, 5, 10, 15);<br />      s.setLocalTranslation(new Vector3f(0, 0, -40));<br />      s.setModelBound(new BoundingSphere());<br />      s.updateModelBound();<br /><br />      return s;<br />   }<br /><br />   private Sphere createSun()<br />   {<br />      Sphere s = new Sphere(&quot;Sun&quot;, 100, 100, 100);<br />      s.setLocalTranslation(new Vector3f(0, 0, -500));<br />      s.setModelBound(new BoundingSphere());<br />      s.setLocalScale(2);<br />      s.updateModelBound();<br /><br />      return s;<br />   }<br /><br />   private TextureState loadTexture(URL u)<br />   {<br />      TextureState ts = display.getRenderer().createTextureState();<br />      ts.setEnabled(true);<br />      ts.setTexture(TextureManager.loadTexture(u,<br />                                               Texture.MinificationFilter.BilinearNearestMipMap,<br />                                               Texture.MagnificationFilter.Bilinear));<br />      return ts;<br />   }<br />}<br />