您的位置:首页 > 其它

jMonkeyEngine译文 FlagRush7(2)——拥抱大地让我们驾驶的不再是Box

2010-10-30 20:19 435 查看
唉,最近有点忙,忘记写Blog咯,喜欢jME的支持。









7.6、源码

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;

import javax.swing.ImageIcon;


import com.jme.app.BaseGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.ChaseCamera;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.shape.Box;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.model.converters.MaxToJme;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.MidPointHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;

public class Lesson7 extends BaseGame{

private int width,height;
private int freq,depth;
private boolean fullscreen;

//我们的camera对象,用于观看scene
private Camera cam;

protected Timer timer;
private Node scene;
private TextureState ts;

private TerrainBlock tb;

private ForceFieldFence fence;
private Skybox skybox;

private Vehicle player;
private ChaseCamera chaser;

private InputHandler input;

//保存terrain的任何一个给出点的法向
private Vector3f normal = new Vector3f();

public static void main(String[] args) {
Lesson7 app = new Lesson7();
java.net.URL url = app.getClass().getClassLoader().getResource("res/logo.png");
app.setConfigShowMode(ConfigShowMode.AlwaysShow,url);
app.start();
}

/*
* 清除texture
*/
protected void cleanup() {
ts.deleteAll();
}

protected void initGame() {
display.setTitle("Flag Rush");
scene = new Node("Scene Graph Node");

ZBufferState buf = display.getRenderer().createZBufferState();
buf.setEnabled(true);
buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
scene.setRenderState(buf);

buildTerrain();
buildLighting();
buildEnvironment();
createSkybox();
buildPlayer();
buildChaseCamera();
buildInput();

CullState cs = display.getRenderer().createCullState();
cs.setCullFace(CullState.Face.Back);
scene.setRenderState(cs);

//更新scene用于渲染
scene.updateGeometricState(0.0f, true);
scene.updateRenderState();
}

private void buildInput() {
input = new FlagRushInputHandler(
player,
settings.getRenderer()
);
}

private void buildChaseCamera() {
Vector3f targetOffset = new Vector3f();
targetOffset.y =
((BoundingBox)player.getWorldBound()).yExtent*1.5f;
HashMap<String, Object> props = new HashMap<String, Object>();
props.put(ThirdPersonMouseLook.PROP_MAXROLLOUT, "6");
props.put(ThirdPersonMouseLook.PROP_MINROLLOUT, "3");
props.put(
ThirdPersonMouseLook.PROP_MAXASCENT,
""+45*FastMath.DEG_TO_RAD
);
props.put(
ChaseCamera.PROP_INITIALSPHERECOORDS,
new Vector3f(5,0,30*FastMath.DEG_TO_RAD)
);
props.put(ChaseCamera.PROP_TARGETOFFSET, targetOffset);

chaser = new ChaseCamera(cam, player, props);
chaser.setMaxDistance(8);
chaser.setMinDistance(2);
}

private void buildPlayer() {
Node model = null;
try {
MaxToJme C1 = new MaxToJme();
ByteArrayOutputStream BO = new ByteArrayOutputStream();
URL maxFile = Lesson7.class.getClassLoader()
.getResource("res/bike.3ds");
C1.convert(
new BufferedInputStream(maxFile.openStream()),
BO
);
model = (Node)BinaryImporter.getInstance().load(
new ByteArrayInputStream(BO.toByteArray())
);
//缩放它,让它比原来更小
model.setLocalScale(.0025f);
model.setModelBound(new BoundingBox());
model.updateModelBound();
} catch (IOException e) {
e.printStackTrace();
}

//设置Vehicle的属性(这些数字能被认为是单元/秒 Unit/S)
player = new Vehicle("Player Node",model);
player.setAcceleration(15);
player.setBraking(25);
player.setTurnSpeed(2.5f);
player.setWeight(25);
player.setMaxSpeed(25);
player.setMinSpeed(15);

player.setLocalTranslation(new Vector3f(100,0, 100));
player.updateWorldBound();
player.setRenderQueueMode(Renderer.QUEUE_OPAQUE);

scene.attachChild(player);
scene.updateGeometricState(0, true);
}

private void createSkybox() {
skybox = new Skybox("skybox",10,10,10);
Texture north = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/north.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);
Texture south = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/south.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);
Texture east = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/east.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);
Texture west = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/west.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);
Texture up = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/top.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);
Texture down = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/texture/bottom.jpg"),
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear
);

skybox.setTexture(Skybox.Face.North, north);
skybox.setTexture(Skybox.Face.West, west);
skybox.setTexture(Skybox.Face.South, south);
skybox.setTexture(Skybox.Face.East, east);
skybox.setTexture(Skybox.Face.Up, up);
skybox.setTexture(Skybox.Face.Down, down);
skybox.preloadTextures();

scene.attachChild(skybox);
}

private void buildEnvironment() {
fence = new ForceFieldFence("forceFieldFence");

//我们将手工做一些调整去让它更好适应terrain
//首先我们将实体“模型”放大
fence.setLocalScale(5);
//现在,让我们移动fence到terrain的高度并有一点陷入它里面
fence.setLocalTranslation(
new Vector3f(25,tb.getHeight(25,25)+10,25)
);

scene.attachChild(fence);
}

private void buildLighting() {
/* 设置一个基础、默认灯光 */
DirectionalLight light = new DirectionalLight();
light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
light.setDirection(new Vector3f(1, -1, 0));
light.setEnabled(true);

LightState lightState = display.getRenderer().createLightState();
lightState.setEnabled(true);
lightState.attach(light);

scene.setRenderState(lightState);
}

/**
* 创建heightmap和terrainBlock
*/
private void buildTerrain() {
//生成随机地形数据
MidPointHeightMap heightMap = new MidPointHeightMap(64,1f);

//缩放数据
Vector3f terrainScale = new Vector3f(4, .0575f, 4);

//创建一个terrain block
tb = new TerrainBlock(
"terrain",
heightMap.getSize(),
terrainScale,
heightMap.getHeightMap(),
new Vector3f(0, 0, 0)
);
tb.setModelBound(new BoundingBox());
tb.updateModelBound();

//通过三个纹理生成地形纹理
ProceduralTextureGenerator pt =
new ProceduralTextureGenerator(heightMap);

pt.addTexture(
new ImageIcon(
getClass().getClassLoader()
.getResource("res/grassb.png")
),
-128, 0, 128
);
pt.addTexture(
new ImageIcon(
getClass().getClassLoader()
.getResource("res/dirt.jpg")
),
0, 128, 256
);
pt.addTexture(
new ImageIcon(
getClass().getClassLoader()
.getResource("res/highest.jpg")
),
128, 256, 384
);
pt.createTexture(32);

//将纹理赋予地形
ts = display.getRenderer().createTextureState();
Texture t1 = TextureManager.loadTexture(
pt.getImageIcon().getImage(),
Texture.MinificationFilter.Trilinear,
Texture.MagnificationFilter.Bilinear,
true
);
ts.setTexture(t1, 0);


//加载细节纹理并为2个terrain的texture设置组合模型
Texture t2 = TextureManager.loadTexture(
Lesson7.class.getClassLoader()
.getResource("res/Detail.jpg"),
Texture.MinificationFilter.Trilinear,
Texture.MagnificationFilter.Bilinear
);
ts.setTexture(t2, 1);

t2.setWrap(Texture.WrapMode.Repeat);

t1.setApply(Texture.ApplyMode.Combine);
t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Modulate);
t1.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
t1.setCombineSrc1RGB(Texture.CombinerSource.PrimaryColor);
t1.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);

t2.setApply(Texture.ApplyMode.Combine);
t2.setCombineFuncRGB(Texture.CombinerFunctionRGB.AddSigned);
t2.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
t2.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
t2.setCombineSrc1RGB(Texture.CombinerSource.Previous);
t2.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);


tb.setRenderState(ts);
tb.setDetailTexture(1, 16);

tb.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
scene.attachChild(tb);
}

protected void 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,
5000f
);
Vector3f loc = new Vector3f(200f,1000f,200f);
cam.setLocation(loc);
// Vector3f left = new Vector3f(-0.5f,0.0f,0.5f);
// Vector3f up = new Vector3f(0.0f,1.0f,0.0f);
// Vector3f dir = new Vector3f(-0.5f,0.0f,-0.5f);
// //将摄像机移到正确位置和方向
// cam.setFrame(loc, left, up, dir);

//我们改变自己的摄像机位置和视锥的标志
cam.update();

//获取一个高分辨率用于FPS更新
timer = Timer.getTimer();

display.getRenderer().setCamera(cam);
KeyBindingManager.getKeyBindingManager().set(
"exit",
KeyInput.KEY_ESCAPE
);
}

/*
* 如果分辨率改变将被调用
*/
protected void reinit() {
display.recreateWindow(width, height, depth, freq, fullscreen);
}

/*
* 绘制场景图
*/
protected void render(float interpolation) {
//清除屏幕
display.getRenderer().clearBuffers();
display.getRenderer().draw(scene);
}

/*
* 在update期间,我们只需寻找Escape按钮
* 并更新timer去获取帧率
*/
protected void update(float interpolation) {
//更新timer去获取帧率
timer.update();
interpolation = timer.getTimePerFrame();

input.update(interpolation);
chaser.update(interpolation);

fence.update(interpolation);

//我们想让skybox一直在我们的视野内,所以让它和camera一起移动
skybox.setLocalTranslation(cam.getLocation());

//我们不想chase camera走到世界下面,因此让它一直在水平面上2个单元。
if(cam.getLocation().y < (tb.getHeight(cam.getLocation())+2)) {
cam.getLocation().y = tb.getHeight(cam.getLocation()) + 2;
cam.update();
}

//确保当玩家离开平面时我们不会坠落。
//当我们增加冲突时,fence将做它自己的工作并保持玩家在里面。
float characterMinHeight =
tb.getHeight(player.getLocalTranslation()) +
((BoundingBox)player.getWorldBound()).yExtent;
if(
!Float.isInfinite(characterMinHeight) &&
!Float.isNaN(characterMinHeight)
)
player.getLocalTranslation().y = characterMinHeight;


//获取terrain在我们当前位置的normal。
//我们然后将它应用到player上面。
tb.getSurfaceNormal(
player.getLocalTranslation(),
normal
);
if(normal != null) {
player.rotateUpTo(normal);
}


//当Escape被按下时,我们退出游戏
if(KeyBindingManager.getKeyBindingManager()
.isValidCommand("exit")
){
finished = true;
}

//由于我们改变了场景(移动skybox),我们需要更新scene graph
scene.updateGeometricState(interpolation, true);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: