JME基础教程代码分析9 碰撞、刚体、场景加载

package com.hello;


import com.jme3.app.SimpleApplication;

import com.jme3.asset.TextureKey;

import com.jme3.asset.plugins.ZipLocator;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.collision.shapes.CollisionShape;

import com.jme3.bullet.control.CharacterControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.bullet.util.CollisionShapeFactory;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.AmbientLight;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.texture.Texture;

 

/**

 * Example 9 - How to make walls and floors solid.

 * This version uses Physics and a custom Action Listener.

 * @author normen, with edits by Zathras

 */

public class HelloCollision extends SimpleApplication

  implements ActionListener {

 

  private Spatial sceneModel;

  private BulletAppState bulletAppState;

  private RigidBodyControl landscape;

  private CharacterControl player;

  private Vector3f walkDirection = new Vector3f();

  private boolean left = false, right = false, up = false, down = false;

  

  private boolean isTrans = false;

 

  private Geometry geom;

  

  public static void main(String[] args) {

    HelloCollision app = new HelloCollision();

    app.start();

  }

 

  public void simpleInitApp() {

    /** Set up Physics */

  //设置物理状态,声明一个弹道应用状态

    bulletAppState = new BulletAppState();

    //将弹道应用状态附加给状态管理对象

    stateManager.attach(bulletAppState);

    

    Box b = new Box(new Vector3f(0f, 4f, 0f), 1, 1, 1);

    geom = new Geometry("Box", b);

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    TextureKey key = new TextureKey("/zw.jpg");

    key.setGenerateMips(true);

    Texture tex = assetManager.loadTexture(key);

    mat.setTexture("ColorMap", tex);

    geom.setMaterial(mat);

    rootNode.attachChild(geom);

    

    // We re-use the flyby camera for rotation, while positioning is handled by physics

    //为旋转视角再次使用飞行相机,它是通过物理方法定位的

    //viewPort是视角范围,设置天空的颜色

    viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));

    //飞行相机的移动速度

    flyCam.setMoveSpeed(100);

    setUpKeys();

    setUpLight();

 

    // We load the scene from the zip file and adjust its size.

    //加载场景文件,这里是个.zip文件,包含了场景模型所有文件

    assetManager.registerLocator("town.zip", ZipLocator.class.getName());

    //加载模型的起始文件名

    sceneModel = assetManager.loadModel("main.scene");

    sceneModel.setLocalScale(2f);

 

    // We set up collision detection for the scene by creating a

    // compound collision shape and a static physics node with mass zero.

    //使用场景文件创建一个符合碰撞造型

    CollisionShape sceneShape =

      CollisionShapeFactory.createMeshShape((Node) sceneModel);

    //刚体控制对象,第一个参数是要设置的刚体对象,第二个参数是他的质量,质量为零表示不受物理引力影响,呵呵,效果是悬浮着的

    landscape = new RigidBodyControl(sceneShape, 0);

    sceneModel.addControl(landscape);

 

    // We set up collision detection for the player by creating

    // a capsule collision shape and a physics character node.

    // The physics character node offers extra settings for

    // size, stepheight, jumping, falling, and gravity.

    // We also put the player in its starting position.

    //这段有点不好理解,可以说是一个胶囊形状的“人”,步幅高度是0.05f,跳跃速度是20,下落速度是30,所受重力是30,并设置了物理位置

    //有一点必须注意,这个胶囊“人”没有被渲染,无论如何都无法被看到的。

    CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);

    player = new CharacterControl(capsuleShape, 0.05f);

    player.setJumpSpeed(20);

    player.setFallSpeed(30);

    player.setGravity(30);

    player.setPhysicsLocation(new Vector3f(0, 10, 0));

    // We attach the scene and the player to the rootnode and the physics space,

    // to make them appear in the game world.

    //附加场景模型到根节点,弹道物理应用状态加载空间对象和player对象到物理空间

    rootNode.attachChild(sceneModel);

    //加载顺序是无关紧要的,不会因为先加载player,就受重力影响而下落,但是y轴方向的加载位置比较重要,如果没有加载到空间刚体对象的上方,就会无奈的受到重力影响了。

    bulletAppState.getPhysicsSpace().add(landscape);

    bulletAppState.getPhysicsSpace().add(player);

  }

 

    private void setUpLight() {

        // We add light so we see the scene

     //加载两组光线,环境光,定向光

        AmbientLight al = new AmbientLight();

        al.setColor(ColorRGBA.White.mult(1.3f));

        rootNode.addLight(al);

 

        DirectionalLight dl = new DirectionalLight();

        dl.setColor(ColorRGBA.White);

        dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());

        rootNode.addLight(dl);

    }

 

  /** We over-write some navigational key mappings here, so we can

   * add physics-controlled walking and jumping: */

  private void setUpKeys() {

    inputManager.addMapping("Lefts",  new KeyTrigger(KeyInput.KEY_A));

    inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));

    inputManager.addMapping("Ups",    new KeyTrigger(KeyInput.KEY_W));

    inputManager.addMapping("Downs",  new KeyTrigger(KeyInput.KEY_S));

    inputManager.addMapping("Jumps",  new KeyTrigger(KeyInput.KEY_SPACE));

    

    inputManager.addMapping("Scale", new KeyTrigger(KeyInput.KEY_C));

    inputManager.addMapping("Min", new KeyTrigger(KeyInput.KEY_M));

    

    inputManager.addListener(this, "Lefts");

    inputManager.addListener(this, "Rights");

    inputManager.addListener(this, "Ups");

    inputManager.addListener(this, "Downs");

    inputManager.addListener(this, "Jumps");

    

    inputManager.addListener(this, "Scale");

    inputManager.addListener(this, "Min");

  }

 

  /** These are our custom actions triggered by key presses.

   * We do not walk yet, we just keep track of the direction the user pressed. */

  public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals("Lefts")) {

      left = value;

    } else if (binding.equals("Rights")) {

      right = value;

    } else if (binding.equals("Ups")) {

      up = value;

    } else if (binding.equals("Downs")) {

      down = value;

    } else if (binding.equals("Jumps")) {

      player.jump();

    } else if (binding.equals("Scale")) {

     isTrans = false;

     transPic(geom.getMaterial());

     geom.setLocalScale(2);

    } else if (binding.equals("Min")) {

     isTrans = true;

     transPic(geom.getMaterial());

     geom.setLocalScale(1);

    }

    

  }

 

  /**

   * This is the main event loop--walking happens here.

   * We check in which direction the player is walking by interpreting

   * the camera direction forward (camDir) and to the side (camLeft).

   * The setWalkDirection() command is what lets a physics-controlled player walk.

   * We also make sure here that the camera moves with player.

   */

  @Override

  public void simpleUpdate(float tpf) {

    Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);

    Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);

    walkDirection.set(0, 0, 0);

    if (left)  { walkDirection.addLocal(camLeft); }

    if (right) { walkDirection.addLocal(camLeft.negate()); }

    if (up)    { walkDirection.addLocal(camDir); }

    if (down)  { walkDirection.addLocal(camDir.negate()); }

    player.setWalkDirection(walkDirection);

    cam.setLocation(player.getPhysicsLocation());

    Quaternion qt = new Quaternion();

qt.fromAngles(0, FastMath.HALF_PI/4*tpf, 0);

geom.rotate(qt);

  }

  

  private Material transPic(Material src) {

  String picname;

  if(isTrans) {

  picname = "/zw.jpg";

  } else {

  picname = "/mypic.jpg";

  }

  TextureKey key = new TextureKey(picname);

    key.setGenerateMips(true);

    Texture tex = assetManager.loadTexture(key);

    src.setTexture("ColorMap", tex);

  return src;

  }

}

posted on 2011-08-12 11:30  苏桓(osbert)  阅读(839)  评论(0编辑  收藏  举报

导航