Home >Database >Mysql Tutorial >jMonkeyEngine译文 FlagRush2从你的应用程序中移除SimpleGam

jMonkeyEngine译文 FlagRush2从你的应用程序中移除SimpleGam

WBOY
WBOYOriginal
2016-06-07 15:39:081066browse

注:本系列教程全部翻译完之后可能会以 PDF 的形式发布。 如果有什么错误可以留言或 EMAIL : kakashi9bi@gmail.com 给我。 jME 版本 : jME_2.0.1_Stable 开发工具: MyEclipse8.5 操作系统: Window7/Vista 这个向导中,我们将为 Flag Rush 构建基

注:本系列教程全部翻译完之后可能会以PDF的形式发布。

如果有什么错误可以留言或EMAILkakashi9bi@gmail.com给我。

 

jME版本jME_2.0.1_Stable

开发工具:MyEclipse8.5

操作系统:Window7/Vista

 

 

 

这个向导中,我们将为Flag Rush构建基础。我们将通过自己实现继承BaseGame。我们将使用BaseGame做为父类,但之后可能改为其它的游戏类型,因为BaseGame简单地尽可能快地进行updaterender。我们或许不必或不想使用这种类型的循环。然而,现在BaseGame是一个循环无关的类。在以后,改变BaseGame将不是重点,因为只是传入updaterender方法的值不同而已。

我们将开始创建一个继承自BaseGame的新类。你会注意到有6个需要实现的方法:updaterenderinitSysteminitGamereinit。现在,只需要为它们创建一个存根方法,我们将在后面将自己的逻辑填充进去。

import com.jme.app.BaseGame;

 

publicclass Lesson2 extends BaseGame{

 

    publicstaticvoid main(String[] args) {

    }

 

    protectedvoid cleanup() {

    }

 

    protectedvoid initGame() {

    }

 

    protectedvoid initSystem() {

    }

 

    protectedvoid reinit() {

    }

 

    protectedvoid render(float arg0) {

    }

 

    protectedvoid update(float arg0) {

    }

 

}

2.1Main

那么,让我们从最初开始。我们在这里将再次创建main方法。它很像前一个向导的main方法,除了一个关键的地方不同。这次我们将显示FlagRush的迷人的新logoAbstractGame定义了一对setConfigShowMode方法,其中的一个接受一个URL类用于加载Image。因此,我们将加载FlagRush.png(迷人的logo)并把它传给这个方法。现在,当PropertiesDialog被显示时,它将显示新的Logo

    publicstaticvoid main(String[] args) {

       Lesson2 app = new Lesson2();

       java.net.URL url =

app.getClass().getClassLoader()

.getResource("jmetest/data/images/FlagRush.png");

       app.setConfigShowMode(ConfigShowMode.AlwaysShow,url);

       app.start();

    }

现在,当PropertiesDialog出现时,它将像下面这个一样(你应该在项目中新建一个package——jmetest.data.images,然后里面有一张叫FlagRush.png的图片):

jMonkeyEngine译文 FlagRush2从你的应用程序中移除SimpleGam

2.2InitSystem

现在,你能运行你的应用程序,但它仅仅是显示PropertiesDialog,除此之外不会做更多的工作。我们下一步将实现initSystem方法。这个方法在进入主循环之前由BaseGame调用。这正是我们设置windowdisplay的地方。我们将保存widthheightdepthfrequencyfullscreen标志。我们将在后面使用这些值,假如用户想改变分辨率的时候。所以,首先,让我们创建变量去保存这些值:

 

publicclass Lesson2 extends BaseGame{

    privateintwidth,height;

    privateintfreq,depth;

privatebooleanfullscreen;

……………………….

 

我们也需要在我们的程序中保存Camera,所以我们也应该为那创建一个变量。

 

    //我们的camera对象,用于观看scene

    private Camera cam;

 

         最后将初始化的一项是TimerTimer将允许我们获取我们的帧率。所以,同样的,这将是一个实例变量。

 

    protected Timer timer;

 

         现在我们已经准备好我们的实例变量,并且我们将在initSystem中初始化它们。

 

    protectedvoid initSystem() {

       //保存属性信息

       width          = settings.getWidth();

       height         = settings.getHeight();

       depth          = settings.getDepth();

       freq           = settings.getFrequency();

       fullscreen    = settings.isFullscreen();

      

       try{

           display = DisplaySystem.getDisplaySystem(

                  settings.getRenderer()

           );

           display.createWindow(

                  width, height, depth, freq, fullscreen

           );

           cam = display.getRenderer().createCamera(width, height);

       }catch(JmeException e){

           e.printStackTrace();

           System.exit(-1);

       }

      

       //设置背景为黑色

       display.getRenderer().setBackgroundColor(ColorRGBA.black);

      

       //初始化摄像机

       cam.setFrustumPerspective(

              45.0f,

              (float)width/(float)height,

              1f,

              1000f

       );

       Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);

       Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);

       Vector3f up = new Vector3f(0.0f,1.0f,0.0f);

       Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);

       //将摄像机移到正确位置和方向

       cam.setFrame(loc, left, up, dir);

      

       //我们改变自己的摄像机位置和视锥的标志

       cam.update();

      

       //获取一个高分辨率用于FPS更新

       timer = Timer.getTimer();

      

       display.getRenderer().setCamera(cam);

       KeyBindingManager.getKeyBindingManager().set(

              "exit",

              KeyInput.KEY_ESCAPE

       );

    }

 

这是一个长的方法,所以,我们将一点一点讨论它。

       //保存属性信息

       width          = settings.getWidth();

       height         = settings.getHeight();

       depth          = settings.getDepth();

       freq           = settings.getFrequency();

       fullscreen    = settings.isFullscreen();

 

首先,我们保存从properties对象(properties是由AbstractGame创建的)获取的值。通过保存这些值,当用户以后从系统菜单改变屏幕设置的时候,我们可以很容易地修改它们中的一个或全部值。

 

       try{

           display = DisplaySystem.getDisplaySystem(

                  settings.getRenderer()

           );

           display.createWindow(

                  width, height, depth, freq, fullscreen

           );

           cam = display.getRenderer().createCamera(width, height);

       }catch(JmeException e){

           e.printStackTrace();

           System.exit(-1);

       }

 

下一步,我们获取新的DisplaySystem,并通过先前获得的屏幕参数创建一个本地窗口。我们接着使用DisplaySystem去创建一个Camera对象。你将注意到那用一个try/catch块包围。如果我们尝试创建一个系统没能力绘制的窗口,异常将在这里出现。目前,它只会退出,但之后,我们将让这个显示得更友好,并通知用户。

 

    //设置背景为黑色

    display.getRenderer().setBackgroundColor(ColorRGBA.black);

      

         我们接着设置了窗口的背景颜色。当没有其它数据被渲染的时候,这是显示的默认颜色。我选择黑色,这是因为它和我们后面将使用的任何文本形成鲜明的对比。不管怎样,这都不是重点,因为当一切正常工作时,屏幕上通常覆盖其它的数据。

//初始化摄像机

       cam.setFrustumPerspective(

              45.0f,

              (float)width/(float)height,

              1f,

              1000f

       );

       Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);

       Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);

       Vector3f up = new Vector3f(0.0f,1.0f,0.0f);

       Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);

       //将摄像机移到正确位置和方向

       cam.setFrame(loc, left, up, dir);

      

       //我们改变自己的摄像机位置和视锥的标志

       cam.update();

      

       display.getRenderer().setCamera(cam);

 

下一步,我设置了camera。我想要一个标准的camera,正常情况下是右手坐标系统(向上是正Y,向右是正X和向屏幕里面是-Z)。我同时设置了透视图为45度视角。这个是大多数游戏里面的公认标准,而它将应用于Flag Rush。在camera数据设置之后,我们调用update,这将设置所有的OpenGL组件,例如视点(下文以ViewPort代替)和Frustum

      

       //获取一个高分辨率用于FPS更新

       timer = Timer.getTimer();

 

         这里只是初始化Timer,从本地Timer获取(例如LWJGLTimer)。

 

KeyBindingManager.getKeyBindingManager().set(

              "exit",

              KeyInput.KEY_ESCAPE

       );

 

最后,我们创建一个新的InputSystem,将它绑定到我们的KeyBindingManager并设置一个输入行为(Input action)。在这个框架中我们只关心一个按键——Escape。在这个例子中,我们设置actionexit”给Escape键。KeyBindingManager是一个单例类,它使用单一的get调用,关注了所有InputSystem组件的初始化。

现在,如果你运行系统你将真正获得一个屏幕显示。它将充满黑色(我们设置的背景颜色),没有任何东西。

 

2.3InitGame

现在,我们拥有一个窗口和OpenGL上下文环境,我们将加载我们的游戏数据(如上面前个向导的Sphere

 

protectedvoid initGame() {

       scene = new Node("Scene Graph Node");

      

       //创建我们的球体

       Sphere s = new Sphere("sphere", 30, 30, 25);

       s.setLocalTranslation(new Vector3f(0, 0, -40));

       s.setModelBound(new BoundingBox());

       s.updateModelBound();

      

       ts = display.getRenderer().createTextureState();

       ts.setEnabled(true);

       ts.setTexture(

              TextureManager.loadTexture(

                     Lesson2.class.getClassLoader()

.getResource("res/logo.png"),

                     Texture.MinificationFilter.Trilinear,

                     Texture.MagnificationFilter.Bilinear

              )

       );

       s.setRenderState(ts);

       scene.attachChild(s);

      

       //更新scene用于渲染

       scene.updateGeometricState(0.0f, true);

       scene.updateRenderState();

}

 

我们现在保存我们自己的Scene Graph结点,我已经选择把它命名为scene,但实际上怎样命名都是没关系。因为这是scene的根节点,它也是一个实例变量而它和其他实例变量一样被声明:

 

    private Node scene;

 

这个Node接着被实例化。接着我们创建了一个SphereTextureState(就像上一个的向导)。Sphere接着被attachscene。这个看起来将和我们上一个向导所做的很相似。然而,现在,我们还调用updateGeometricStateupdateRenderState。这些方法为SceneGraph updates调用。updateGeometricState是必须的,不管场景图(Scene Graph)结构在何时改变(设置一个新的,改变另一个的参数,等等),在我们的例子中,我增加了一个sphere到到scene。不管RenderState在什么时候以何种方式发生改变,updateRenderState都应该被调用(比如创建一个新的RenderState、改变它的参数等等),在我们的例子中,我们增加了TextureState

我们现在拥有游戏中的数据,但它仍然没被渲染到屏幕。

 

2.4Renderupdate

既然我们已经初始化了窗口并加载了数据,如果能看到它将更好。那就是render方法的到来。BaseGame调用update并根据它的能力尽可能快地renderrender的调用需要处理所有绘画调用,而update应该处理任何的游戏逻辑。在我们的例子中,我们想要update做一点游戏逻辑,退出游戏。为了简单退出游戏,我们将设置finished布尔值为true

 

/*

     * update期间,我们只需寻找Escape按钮

     * 并更新timer去获取帧率

     */

    protectedvoid update(float interpolation) {

       //更新timer去获取帧率

       timer.update();

       interpolation = timer.getTimePerFrame();

      

       //Escape被按下时,我们退出游戏

       if(KeyBindingManager.getKeyBindingManager()

              .isValidCommand("exit")

       ){

           finished = true;

       }

    }

 

你也将注意到update获取最新的timer读数并为此设置插值(interpolation)。BaseGame通常在调用update时发送-1,所以我们将继续并重用这个值去保存每帧真正的时间。

    接下来,我们将渲染。

 

    /*

     * 绘制场景图

     */

    protectedvoid render(float interpolation) {

       //清除屏幕

       display.getRenderer().clearBuffers();

       display.getRenderer().draw(scene);

    }

 

这个直截了当。我们使用clearBuffers清除屏幕。我们接着画了scene,这是包含我们Sphere的树。

    你现在能运行程序并看到:

         正是和前一课的显示一样,只不过没了灯光。

jMonkeyEngine译文 FlagRush2从你的应用程序中移除SimpleGam

2.5reinitcleanup

最后我们将覆盖的2个方法是reinitcleanup。当窗口需要重建时,Reinit应该被调用,就像参数发生了变化。而在关闭的时候调用cleanup

/*

     * 如果分辨率改变将被调用

     */

    protectedvoid reinit() {

       display.recreateWindow(width, height, depth, freq, fullscreen);

    }

我们在这里所做的就只是传递新的值给DisplaySystem处理。仅此而已。

 

    /*

     * 清除texture

     */

    protectedvoid cleanup() {

       ts.deleteAll();

    }

 

这简单确保了texture被删除。这不是特别必须的,因为OpenGL在它退出时将处理这个。但“宁可事先谨慎有余,切莫事后追悔莫及”。

 

2.6、总结

很好,就是那样。我们现在有一个很基本、可工作的框架。通过创建我们自己的应用程序类型,我们能完全保持对我们场景中一切的控制。随着向导的继续,我们将很明确地增强并构建基于这个类的程序。

 

2.7、源码

 

import com.jme.app.BaseGame;

import com.jme.bounding.BoundingBox;

import com.jme.image.Texture;

import com.jme.input.KeyBindingManager;

import com.jme.input.KeyInput;

import com.jme.math.Vector3f;

import com.jme.renderer.Camera;

import com.jme.renderer.ColorRGBA;

import com.jme.scene.Node;

import com.jme.scene.shape.Sphere;

import com.jme.scene.state.TextureState;

import com.jme.system.DisplaySystem;

import com.jme.system.JmeException;

import com.jme.util.TextureManager;

import com.jme.util.Timer;

 

publicclass Lesson2 extends BaseGame{

 

    privateintwidth,height;

    privateintfreq,depth;

    privatebooleanfullscreen;

   

    //我们的camera对象,用于观看scene

    private Camera cam;

   

    protected Timer timer;

    private Node scene;

    private TextureState ts;

   

    publicstaticvoid main(String[] args) {

       Lesson2 app = new Lesson2();

       java.net.URL url = app.getClass().getClassLoader().getResource("res/logo.png");

       app.setConfigShowMode(ConfigShowMode.AlwaysShow,url);

       app.start();

    }

 

    /*

     * 清除texture

     */

    protectedvoid cleanup() {

       ts.deleteAll();

    }

 

    protectedvoid initGame() {

       scene = new Node("Scene Graph Node");

      

       //创建我们的球体

       Sphere s = new Sphere("sphere", 30, 30, 25);

       s.setLocalTranslation(new Vector3f(0, 0, -40));

       s.setModelBound(new BoundingBox());

       s.updateModelBound();

      

       ts = display.getRenderer().createTextureState();

       ts.setEnabled(true);

       ts.setTexture(

              TextureManager.loadTexture(

                     Lesson2.class.getClassLoader().getResource("res/logo.png"),

                     Texture.MinificationFilter.Trilinear,

                     Texture.MagnificationFilter.Bilinear

              )

       );

       s.setRenderState(ts);

      

       scene.attachChild(s);

      

       //更新scene用于渲染

       scene.updateGeometricState(0.0f, true);

       scene.updateRenderState();

    }

 

    protectedvoid initSystem() {

       //保存属性信息

       width      = settings.getWidth();

       height     = settings.getHeight();

       depth      = settings.getDepth();

       freq       = settings.getFrequency();

       fullscreen    = settings.isFullscreen();

      

       try{

           display = DisplaySystem.getDisplaySystem(

                  settings.getRenderer()

           );

           display.createWindow(

                  width, height, depth, freq, fullscreen

           );

           cam = display.getRenderer().createCamera(width, height);

       }catch(JmeException e){

           e.printStackTrace();

           System.exit(-1);

       }

      

       //设置背景为黑色

       display.getRenderer().setBackgroundColor(ColorRGBA.black);

      

       //初始化摄像机

       cam.setFrustumPerspective(

              45.0f,

              (float)width/(float)height,

              1f,

              1000f

       );

       Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);

       Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);

       Vector3f up = new Vector3f(0.0f,1.0f,0.0f);

       Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);

       //将摄像机移到正确位置和方向

       cam.setFrame(loc, left, up, dir);

      

       //我们改变自己的摄像机位置和视锥的标志

       cam.update();

      

       //获取一个高分辨率用于FPS更新

       timer = Timer.getTimer();

      

       display.getRenderer().setCamera(cam);

       KeyBindingManager.getKeyBindingManager().set(

              "exit",

              KeyInput.KEY_ESCAPE

       );

    }

 

    /*

     * 如果分辨率改变将被调用

     */

    protectedvoid reinit() {

       display.recreateWindow(width, height, depth, freq, fullscreen);

    }

 

    /*

     * 绘制场景图

     */

    protectedvoid render(float interpolation) {

       //清除屏幕

       display.getRenderer().clearBuffers();

       display.getRenderer().draw(scene);

    }

 

    /*

     * update期间,我们只需寻找Escape按钮

     * 并更新timer去获取帧率

     */

    protectedvoid update(float interpolation) {

       //更新timer去获取帧率

       timer.update();

       interpolation = timer.getTimePerFrame();

      

       //Escape被按下时,我们退出游戏

       if(KeyBindingManager.getKeyBindingManager()

              .isValidCommand("exit")

       ){

           finished = true;

       }

    }

 

}

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn