Skip to content

Instantly share code, notes, and snippets.

@jcfandino
Created October 16, 2021 00:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcfandino/21b08cf733a60c9e521234dae17b7f24 to your computer and use it in GitHub Desktop.
Save jcfandino/21b08cf733a60c9e521234dae17b7f24 to your computer and use it in GitHub Desktop.
jme bcc hops
package jc.workbench.bullet;
import com.jme3.anim.AnimComposer;
import com.jme3.anim.tween.action.Action;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
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.material.Materials;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import com.jme3.scene.shape.Quad;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.system.AppSettings;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.HeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
/**
* An example of character physics using Oto and BetterCharacterControl.
*
* Press the U/H/J/K keys to walk.
*
* @author Stephen Gold sgold@sonic.net
*/
public class TestOtoBcc
extends SimpleApplication
implements ActionListener {
// *************************************************************************
// fields
private Action standAction;
private Action walkAction;
private AnimComposer composer;
private BetterCharacterControl character;
/**
* true when the U key is pressed, otherwise false
*/
private volatile boolean walkAway;
/**
* true when the H key is pressed, otherwise false
*/
private volatile boolean walkLeft;
/**
* true when the K key is pressed, otherwise false
*/
private volatile boolean walkRight;
/**
* true when the J key is pressed, otherwise false
*/
private volatile boolean walkToward;
final private Node translationNode = new Node("translation node");
// *************************************************************************
// new methods exposed
private float maxHeight = - Float.MIN_VALUE;
private BitmapText text = null;
/**
* Main entry point for the application.
*
* @param ignored array of command-line arguments (not null)
*/
public static void main(String[] ignored) {
TestOtoBcc application = new TestOtoBcc();
// Enable gamma correction for accurate lighting.
boolean loadDefaults = true;
AppSettings settings = new AppSettings(loadDefaults);
settings.setGammaCorrection(true);
application.setSettings(settings);
application.start();
}
// *************************************************************************
// SimpleApplication methods
/**
* Initialize this application.
*/
@Override
public void simpleInitApp() {
addLighting(rootNode);
configureCamera();
configureInput();
PhysicsSpace physicsSpace = configurePhysics();
// Load the Oto model and find its animation actions.
// Spatial oto = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
// composer = oto.getControl(AnimComposer.class);
// standAction = composer.action("stand");
// walkAction = composer.action("Walk");
Spatial oto = new Geometry("oto", new Box(0.5f, 1f,0.5f));
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
mat.setColor("Color", ColorRGBA.Brown);
oto.setMaterial(mat);
// Attach the model model to a translation node.
rootNode.attachChild(translationNode);
translationNode.attachChild(oto);
oto.move(0f, 0.5f, 0f);
// Create the PhysicsControl and add it to the scene and space.
float characterRadius = 0.5f;
float characterHeight = 2f;
float characterMass = 100f;
character = new BetterCharacterControl(characterRadius, characterHeight,
characterMass);
translationNode.addControl(character);
physicsSpace.add(character);
character.warp(new Vector3f(-73.6f, 14.09f, -45.58f));
addGround(physicsSpace, "notterrain");
BitmapFont font = assetManager.loadFont("Interface/Fonts/Default.fnt");
text = new BitmapText(font, false);
text.setLocalTranslation(cam.getWidth() / 2f, cam.getHeight()/2f, 0f);
guiNode.attachChild(text);
flyCam.setDragToRotate(true);
}
/**
* Callback invoked once per frame.
*
* @param tpf the time interval between frames (in seconds, ≥0)
*/
@Override
public void simpleUpdate(float tpf) {
// Determine horizontal directions relative to the camera orientation.
Vector3f away = cam.getDirection();
away.y = 0;
away.normalizeLocal();
Vector3f left = cam.getLeft();
left.y = 0;
left.normalizeLocal();
// Determine the walk velocity from keyboard inputs.
Vector3f direction = new Vector3f();
if (walkAway) {
direction.addLocal(away);
}
if (walkLeft) {
direction.addLocal(left);
}
if (walkRight) {
direction.subtractLocal(left);
}
if (walkToward) {
direction.subtractLocal(away);
}
direction.normalizeLocal();
float walkSpeed = 50f;
Vector3f walkVelocity = direction.mult(walkSpeed);
character.setWalkDirection(walkVelocity);
float current = character.getRigidBody().getPhysicsLocation().getY();
maxHeight = Math.max(maxHeight, current);
text.setText(String.format("Current height: %f\nMax registered: %f", current, maxHeight));
// Update the animation action.
// Action action = composer.getCurrentAction();
// if (walkVelocity.length() < 0.001f) {
// if (action != standAction) {
// composer.setCurrentAction("stand");
// }
// } else {
// character.setViewDirection(direction);
// if (action != walkAction) {
// composer.setCurrentAction("Walk");
// }
// }
}
// *************************************************************************
// ActionListener methods
/**
* Callback to handle keyboard input events.
*
* @param action the name of the input event
* @param ongoing true &rarr; pressed, false &rarr; released
* @param tpf the time per frame (in seconds, &ge;0)
*/
@Override
public void onAction(String action, boolean ongoing, float tpf) {
switch (action) {
case "walk away":
walkAway = ongoing;
return;
case "walk left":
walkLeft = ongoing;
return;
case "walk right":
walkRight = ongoing;
return;
case "walk toward":
walkToward = ongoing;
return;
default:
System.out.println("Unknown action: " + action);
}
}
// *************************************************************************
// private methods
/**
* Add lighting and shadows to the specified scene.
*/
private void addLighting(Spatial scene) {
scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
ColorRGBA ambientColor = new ColorRGBA(0.03f, 0.03f, 0.03f, 1f);
AmbientLight ambient = new AmbientLight(ambientColor);
scene.addLight(ambient);
ambient.setName("ambient");
ColorRGBA directColor = new ColorRGBA(0.3f, 0.3f, 0.3f, 1f);
Vector3f direction = new Vector3f(-7f, -3f, -5f).normalizeLocal();
DirectionalLight sun = new DirectionalLight(direction, directColor);
scene.addLight(sun);
sun.setName("sun");
// Render shadows based on the directional light.
viewPort.clearProcessors();
int shadowMapSize = 2_048; // in pixels
int numSplits = 3;
DirectionalLightShadowRenderer dlsr
= new DirectionalLightShadowRenderer(assetManager,
shadowMapSize, numSplits);
dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
dlsr.setEdgesThickness(5);
dlsr.setLight(sun);
dlsr.setShadowIntensity(0.4f);
viewPort.addProcessor(dlsr);
// Set the viewport's background color to light blue.
ColorRGBA skyColor = new ColorRGBA(0.1f, 0.2f, 0.4f, 1f);
viewPort.setBackgroundColor(skyColor);
}
/**
* Add a heightfield body to the specified PhysicsSpace.
*
* @param physicsSpace (not null)
*/
private void addGround(PhysicsSpace physicsSpace, String groundType) {
Spatial ground;
if (groundType.equalsIgnoreCase("terrain")) {
String assetPath = "Textures/Terrain/splat/mountains512.png";
Texture texture = assetManager.loadTexture(assetPath);
Image image = texture.getImage();
HeightMap heightMap = new ImageBasedHeightMap(image);
heightMap.setHeightScale(0.2f);
heightMap.load();
ground = new TerrainQuad("terrain", 65, 513, heightMap.getHeightMap());
} else {
Mesh quad = new Quad(999f, 999f);
ground = new Geometry("terrain", quad);
ground.move(-500f, 14f, 500f);
ground.rotate(-FastMath.HALF_PI, 0f, 0f);
}
rootNode.attachChild(ground);
Material greenMaterial = createLitMaterial(0f, 0.5f, 0f);
ground.setMaterial(greenMaterial);
// Construct a static RigidBodyControl based on the ground spatial.
CollisionShape shape = CollisionShapeFactory.createMeshShape(ground);
RigidBodyControl rbc = new RigidBodyControl(shape, 0f);
rbc.setPhysicsSpace(physicsSpace);
ground.addControl(rbc);
}
/**
* Configure the Camera during startup.
*/
private void configureCamera() {
flyCam.setMoveSpeed(10f);
cam.setLocation(new Vector3f(-39f, 34f, -47f));
cam.setRotation(new Quaternion(0.183f, -0.68302f, 0.183f, 0.68302f));
}
/**
* Configure keyboard input during startup.
*/
private void configureInput() {
inputManager.addMapping("walk away", new KeyTrigger(KeyInput.KEY_U));
inputManager.addMapping("walk left", new KeyTrigger(KeyInput.KEY_H));
inputManager.addMapping("walk right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("walk toward", new KeyTrigger(KeyInput.KEY_J));
inputManager.addListener(this,
"walk away", "walk left", "walk right", "walk toward");
}
/**
* Configure physics during startup.
*/
private PhysicsSpace configurePhysics() {
BulletAppState bulletAppState = new BulletAppState();
bulletAppState.setDebugEnabled(true);
stateManager.attach(bulletAppState);
PhysicsSpace result = bulletAppState.getPhysicsSpace();
result.setGravity(new Vector3f(0f, -60f, 0f));
return result;
}
/**
* Create a single-sided lit material with the specified reflectivities.
*
* @param red the desired reflectivity for red light (&ge;0, &le;1)
* @param green the desired reflectivity for green light (&ge;0, &le;1)
* @param blue the desired reflectivity for blue light (&ge;0, &le;1)
* @return a new instance (not null)
*/
private Material createLitMaterial(float red, float green, float blue) {
Material result = new Material(assetManager, Materials.LIGHTING);
result.setBoolean("UseMaterialColors", true);
float opacity = 1f;
result.setColor("Ambient", new ColorRGBA(red, green, blue, opacity));
result.setColor("Diffuse", new ColorRGBA(red, green, blue, opacity));
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment