jme学习笔记例10

这个程序介绍了声音节点,天空盒,声音API控制,你将学习
如何去播放声音,创建文本,制作你的controller和输入handler.而且介绍了简单的碰撞检测.
  
可编译声音继承soundspatial extends objext
因此可编程声音不是一个在trimesh或者geometry或者node的"spatial",它不能被普通的渲染环境渲染,它由声音系统渲染,对象被显示系统渲染。在这个系统里,我们打算使用一个programmable 声音 一个programmable sound是一个有各自url连接的节点。每个url关联的声音可以被某个事件触发,我们的激光声音的事件id是1,这个数字不实很重要,我将在以后提及如何使用它,但我们首先了解如何建立声音:

/** init sound API acording to the rendering enviroment you're using
*/
SoundAPIController.getSoundSystem(properties.getRenderer());
/** Set the 'ears' for the sound API */
SoundAPIController.getRenderer().setCamera(cam);

第一行创建了声音系统,声音不能设置为默认,我们创建
一个具体要渲染的声音的系统。如果我们使用Lwjgl库那么它将创建lWJGL的声音系统。下一步我们设置“耳朵”来配置声音在摄像机的位置,随后我们创建我们的声音对象
snode = new SoundNode();
/** Create program sound */
targetSound = new ProgrammableSound();
/** Make the sound softer */
targetSound .setLooping(false);
targetSound.setMaxDistance(140f);
在这里设置了一个距离我们140单位远的不会循环播放的声音对象。同样我们设置激光的声音对象,但不需要给他一个距离:
  laserSound = new ProgrammableSound();
  laserSound.setLooping(false);
下一步。我们把声音对象绑定到声音节点:
  /** locate laser and register it with the prog sound. */
laserURL = HelloIntersection.class.getClassLoader().getResource(
"jmetest/data/sound/laser.ogg");
hitURL = HelloIntersection.class.getClassLoader().getResource(
"jmetest/data/sound/explosion.ogg");
// Ask the system for a program id for this resource
int programid = SoundPool.compile(new URL[] { laserURL });
int hitid = SoundPool.compile(new URL[] { hitURL });
// Then we bind the programid we received to our laser event id.
laserSound.bindEvent(laserEventID, programid);
targetSound.bindEvent(hitEventID, hitid);
snode.attachChild(laserSound);
snode.attachChild(targetSound);

SoundPool.compile 接收一个url数组并编译到一个soundpool,这些声音由整数指定,在编译后,我们告诉snode是否lasereventid事件被调用,它将播放在soundpool中的指定programid的声音,无论何时hitevetnid事件被触发,就会播放hitid指定的声音,我们只使用一个声音,但我们能容易制造一个激光声音邦定到我们的programid通过使用2个url数组,在制造了声音之后,我们把十字光标放到屏幕上

/** Create a + for the middle of the screen */
Text cross = new Text("Crosshairs", "+");
// 8 is half the width of a font char
/** Move the + to the middle */
cross.setLocalTranslation(new Vector3f(display.getWidth() / 2f - 8f,
display.getHeight() / 2f - 8f, 0));
fpsNode.attachChild(cross);

text扩展了geometry,这意味着text需要一个名字,我们叫它“crosshairs”,text就显示到屏幕上,这里显示一个“+”,这个转换的text不是真实世界的坐标像其他时候,
这个坐标是实际的屏幕坐标,setLocalTranslation 方法的Z轴被忽略因此是0,设置我们的+到屏幕的中间,
你将注意我没有分配到rootnode而是fpsnode,fpsnode是被simplegame创建并有一个默认的孩子节点,这个孩子节点就是你看见的在屏幕的底部,我分配我的cross到fpsnode因为fpsnode有一个特定的纹理,让我们看这个纹理:

  text exttext将把ascII匹配到图片的一个位置,显示每个字母,把握这一点,你可以容易地更改一个图片文件获取任何text你想要得到的,在创建+后,我创建skybox到我的世界:
/** Create a skybox to suround our world */
sb = new Skybox("skybox", 200, 200, 200);
URL monkeyLoc = HelloIntersection.class.getClassLoader().getResource(
"jmetest/data/texture/clouds.png");
TextureState ts = display.getRenderer().createTextureState();
59
ts.setTexture(TextureManager.loadTexture(monkeyLoc,
Texture.MM_LINEAR,
Texture.FM_LINEAR, true));
sb.setRenderState(ts);
  这样简单地创建一个200x200x200单位的框。这个箱子出现这样的纹理。我分配云到纹理中,最后我们绑定按键到action中

input.addKeyboardAction("firebullet", KeyInput.KEY_F,
new FireBullet());

输入创建一个简单的游戏,它是一个inputhandler类,
默认地,游戏给输入信息需要去做鼠标和键盘的处理,这里,我增加key_F去绑定到AWT,这个简单的状态当你压了F key,FireBullet.performAction将被调用,让我们看
子弹的构造器:

FireBullet() {
setAllowsRepeats(false);
}
这个功能是如果我们按下F,你不会看到上千个子弹在屏幕中交在一起,如果你要变成自动发射,你设置true就可以了,注意FireBullet extends AbstractInputAction,这样允许我们绑定键盘的action,下面介绍performaction:

System.out.println("BANG");
/** Create bullet */
Sphere bullet = new Sphere("bullet" + numBullets++, 8, 8, .25f);
bullet.setModelBound(new BoundingSphere());
bullet.updateModelBound();
/** Move bullet to the camera location */
bullet.setLocalTranslation(new Vector3f(cam.getLocation()));
bullet.setRenderState(bulletMaterial);

无论什么时候按下f,首先创建子弹,紧接着我移动它到摄像机的位置(就是子弹初始的位置),然后把子弹设成绿色
bullet.updateGeometricState(0, true);

调用这个方法因为我需要更新几何信息(重要的是他的包裹体),这给子弹正确的世界绑定使它能够立即被bulletmover()更新,子弹开始与updateGeometricState 被调用,因为这个方法是子弹的孩子,方法的背后是每个simplegame的帧调用rootNode.updateGeometricState(time_per_frame,true)去移动和更新全部的子节点,下面,我给移动子弹的controller:

/**
* Add a movement controller to the bullet going in the camera's
* direction
*/
bullet.addController(new BulletMover(bullet, new Vector3f(cam
.getDirection())));

移动这个子弹沿着摄像机的方向,我们得到子弹的下一位置,但先让我们完成F的按键
rootNode.attachChild(bullet);
bullet.updateRenderState();

下面我们分配到这个节点和调用 updateRenderState(),
再一次 updateRenderState() 被调用在simpleInitGame()之后,这个方法将全部的渲染状态应用到spatial,
包括所有的子状态,如果没有更新渲染状态子弹将是红色的,最后,我通知programsound初始化lasereventid,记住邦定到laser sound
   /** Signal our sound to play laser during rendering */
laserSound.setPosition(cam.getLocation());
snode.onEvent(laserEventID);
现在,让我们看下BulletMover(),注意 它是一个controller像KeyframeController 和SpatialController
一样,他移动spatial在给定的方向,每次updateGeometricState()被调用或者子弹的根节点,这个方法起更新全部的子弹状态,让我们看update()

public void update(float time) {
更新时间是在相连帧之间的时间,为什么?因为那是updateGeometricState()给出的浮点值,下面我们可以移动子弹
lifeTime -= time;
/** If life is gone, remove it */
if (lifeTime < 0) {
rootNode.detachChild(bullet);
bullet.removeController(this);
return;
}
如果子弹的存在超过5秒,我把它干掉,很简单对吧?
下面,我移动子弹沿着它的方向
/** Move bullet */
Vector3f bulletPos = bullet.getLocalTranslation();
bulletPos.addLocal(direction.mult(time * speed));
bullet.setLocalTranslation(bulletPos);
这个时间的浮点值是update()给予的,速度是常量,下面,我检查子弹有无射到他的目标
/** Does the bullet intersect with target? */
if (Intersection.intersection(bullet.getWorldBound(), target
.getWorldBound())) {
注意那是检查子弹的世界约束边界和目标的边界
约束量可以比实际的网的边界更大,这意味着两个边界
可以相交,我将增加更复杂的方法在两个trimesh对象相交,但现在我们要保持简单,我简单地移动目标和干掉子弹,这是 simpleRender 和 simpleUpdate要做的
/**
* Called every frame for rendering
*/
protected void simpleRender() {
// Give control to the sound in case sound changes are needed.
SoundAPIController.getRenderer().draw(snode);
}
/**
* Called every frame for updating
*/
protected void simpleUpdate() {
// Let the programmable sound update itself.
snode.updateGeometricState(tpf, true);
}
我还要更新和渲染声音象一个简单的游戏,这就是我要做的,变量tpf被simplegame创建,它是每帧的次数
它更新每一帧

 








你可能感兴趣的:(游戏,编程,制造,F#)