您好,欢迎访问一九零五行业门户网

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

注:本系列教程全部翻译完之后可能会以 pdf 的形式发布。 如果有什么错误可以留言或 email : kakashi9bi@gmail.com 给我。 jme 版本 : jme_2.0.1_stable 开发工具: myeclipse8.5 操作系统: window7/vista 这个向导中,我们将为 flag rush 构建基
注:本系列教程全部翻译完之后可能会以pdf的形式发布。
如果有什么错误可以留言或email:kakashi9bi@gmail.com给我。
jme版本:jme_2.0.1_stable
开发工具:myeclipse8.5
操作系统:window7/vista
这个向导中,我们将为flag rush构建基础。我们将通过自己实现继承basegame。我们将使用basegame做为父类,但之后可能改为其它的游戏类型,因为basegame简单地尽可能快地进行update和render。我们或许不必或不想使用这种类型的循环。然而,现在basegame是一个循环无关的类。在以后,改变basegame将不是重点,因为只是传入update和render方法的值不同而已。
我们将开始创建一个继承自basegame的新类。你会注意到有6个需要实现的方法:update、render、initsystem、initgame和reinit。现在,只需要为它们创建一个存根方法,我们将在后面将自己的逻辑填充进去。
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.1、main那么,让我们从最初开始。我们在这里将再次创建main方法。它很像前一个向导的main方法,除了一个关键的地方不同。这次我们将显示flagrush的迷人的新logo。abstractgame定义了一对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的图片):
2.2、initsystem现在,你能运行你的应用程序,但它仅仅是显示propertiesdialog,除此之外不会做更多的工作。我们下一步将实现initsystem方法。这个方法在进入主循环之前由basegame调用。这正是我们设置window和display的地方。我们将保存width,height,depth,frequency和fullscreen标志。我们将在后面使用这些值,假如用户想改变分辨率的时候。所以,首先,让我们创建变量去保存这些值:
publicclass lesson2 extends basegame{
    privateintwidth,height;
    privateintfreq,depth;
privatebooleanfullscreen;
……………………….
我们也需要在我们的程序中保存camera,所以我们也应该为那创建一个变量。
//我们的camera对象,用于观看scene
    private camera cam;
最后将初始化的一项是timer,timer将允许我们获取我们的帧率。所以,同样的,这将是一个实例变量。
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。在这个例子中,我们设置action“exit”给escape键。keybindingmanager是一个单例类,它使用单一的get调用,关注了所有inputsystem组件的初始化。
现在,如果你运行系统你将真正获得一个屏幕显示。它将充满黑色(我们设置的背景颜色),没有任何东西。
2.3、initgame现在,我们拥有一个窗口和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接着被实例化。接着我们创建了一个sphere和texturestate(就像上一个的向导)。sphere接着被attach到scene。这个看起来将和我们上一个向导所做的很相似。然而,现在,我们还调用updategeometricstate和updaterenderstate。这些方法为scenegraph updates调用。updategeometricstate是必须的,不管场景图(scene graph)结构在何时改变(设置一个新的,改变另一个的参数,等等),在我们的例子中,我增加了一个sphere到到scene。不管renderstate在什么时候以何种方式发生改变,updaterenderstate都应该被调用(比如创建一个新的renderstate、改变它的参数等等),在我们的例子中,我们增加了texturestate。
我们现在拥有游戏中的数据,但它仍然没被渲染到屏幕。
2.4、render和update既然我们已经初始化了窗口并加载了数据,如果能看到它将更好。那就是render方法的到来。basegame调用update并根据它的能力尽可能快地render。render的调用需要处理所有绘画调用,而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的树。
    你现在能运行程序并看到:
正是和前一课的显示一样,只不过没了灯光。
2.5、reinit和cleanup最后我们将覆盖的2个方法是reinit和cleanup。当窗口需要重建时,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;
       }
    }
}
其它类似信息

推荐信息