package net.jmecn;
import com.jme3.anim.AnimClip;
import com.jme3.scene.debug.Arrow;
import com.jme3.input.ChaseCamera;
import com.jme3.anim.AnimComposer;
import com.jme3.anim.Armature;
import com.jme3.anim.SkinningControl;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.HttpZipLocator;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.animation.DynamicAnimControl;
import com.jme3.bullet.animation.LinkConfig;
import com.jme3.bullet.animation.RangeOfMotion;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.collision.shapes.HullCollisionShape;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.KeyInput;
import com.jme3.input.CameraInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
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.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.CameraNode;
import com.jme3.scene.plugins.bvh.BoneMapping;
import com.jme3.scene.plugins.bvh.SkeletonMapping;
import com.jme3.ui.Picture;
import java.io.File;
import jme3utilities.wes.AnimationEdit;
/**
* 按键发射小球轰击砖墙。
*
* @author yanmaoyuan
*
*/
public class CharacterControlDemo extends SimpleApplication implements ActionListener {
/**
* 开火,发射小球。鼠标左键触发。
*/
public final static String FIRE = "fire";
public final static String FORWARD = "forward";
public final static String BACKWARD = "backward";
public final static String LEFT = "left";
public final static String RIGHT = "right";
public final static String V = "v";
public final static String JUMP = "jump";
public int v1= 0;
//方向控制器
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private Vector3f walkDirectioni = new Vector3f();
private boolean left = false, right = false, up = false, down = false, v=false;
/**
* 显示或隐藏BulletAppState的debug形状。按空格键触发。
*/
public final static String DEBUG = "debug";
// 临时变量,用于保存摄像机的方向。避免在simpleUpdate中重复创建对象。
private Vector3f camDir = new Vector3f();
private Vector3f camLeft = new Vector3f();
/** 砖块的尺寸 */
private static final float brickLength = 0.48f;
private static final float brickWidth = 0.24f;
private static final float brickHeight = 0.12f;
private AnimComposer control;
private BulletAppState bulletAppState;
private Node character;
private ChaseCamera chaseCam;
private CameraInput cameraInput;
private DynamicAnimControl dac;
@Override
public void simpleInitApp() {
createArrow(new Vector3f(5, 0, 0), ColorRGBA.Green);
createArrow(new Vector3f(0, 5, 0), ColorRGBA.Red);
createArrow(new Vector3f(0, 0, 5), ColorRGBA.Blue);
// cam.setLocation(new Vector3f(0, 4f, 6f));
// cam.lookAt(new Vector3f(2, 2, 0), Vector3f.UNIT_Y);
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(true);
// 初始化按键
initKeys();
// 初始化光照
initLight();
// 初始化场景
initScene();
}
/**
* 创建一个箭头
*
* @param vec3 箭头向量
* @param color 箭头颜色
*/
private void createArrow(Vector3f vec3, ColorRGBA color) {
// 创建材质,设定箭头的颜色
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", color);
// 创建几何物体,应用箭头网格。
Geometry geom = new Geometry("arrow", new Arrow(vec3));
geom.setMaterial(mat);
// 添加到场景中
rootNode.attachChild(geom);
}
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (DEBUG.equals(name) && isPressed) {
boolean debugEnabled = bulletAppState.isDebugEnabled();
bulletAppState.setDebugEnabled(!debugEnabled);
} else if (LEFT.equals(name)) {
left = isPressed;
if (isPressed) {
System.err.println("按下W");
control.setCurrentAction("Walk");
control.setGlobalSpeed(1f);
} else {
System.err.println("弹起W");
control.setCurrentAction("Stand");
control.setGlobalSpeed(1f);
}
} else if (RIGHT.equals(name)) {
right = isPressed;
if (isPressed) {
System.err.println("按下W");
control.setCurrentAction("Walk");
control.setGlobalSpeed(1f);
} else {
System.err.println("弹起W");
control.setCurrentAction("Stand");
control.setGlobalSpeed(1f);
}
} else if (FORWARD.equals(name)) {
up = isPressed;
if (isPressed) {
System.err.println("按下W");
control.setCurrentAction("Walk");
control.setGlobalSpeed(1f);
} else {
System.err.println("弹起W");
control.setCurrentAction("Stand");
control.setGlobalSpeed(1f);
}
} else if (BACKWARD.equals(name)) {
down = isPressed;
if (isPressed) {
System.err.println("按下W");
control.setCurrentAction("Walk");
control.setGlobalSpeed(1f);
} else {
System.err.println("弹起W");
control.setCurrentAction("Stand");
control.setGlobalSpeed(1f);
}
}else if(V.equals(name)) {
if(!isPressed){
switch(v1){
case 0 :
v1++;chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, 0f)); v1=0;
break; //可选
case 1 :
chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, -2.5f).add(camLeft)); v1=0;
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
}
v = isPressed;
}else if (JUMP.equals(name) && isPressed) {
if(player.onGround()==true){
player.jump();
}
System.err.println(player.onGround());
}
}
/**
* 初始化按键输入
*/
private void initKeys() {
inputManager.addMapping(FIRE, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping(DEBUG, new KeyTrigger(KeyInput.KEY_F1));
inputManager.addMapping(LEFT, new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping(RIGHT, new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping(FORWARD, new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping(BACKWARD, new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping(JUMP, new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping(V, new KeyTrigger(KeyInput.KEY_V));
inputManager.addListener(this, FIRE, DEBUG,LEFT,RIGHT,FORWARD,BACKWARD,JUMP,V);
}
/**
* 初始化光照
*/
private void initLight() {
// 环境光
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1f));
// 阳光
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1, -2, -3).normalizeLocal());
rootNode.addLight(ambient);
rootNode.addLight(sun);
}
/**
* 初始化场景
*/
private void initScene() {
model();
makeFloor();
}
/**
* 制作地板
*/
private void makeFloor() {
// 网格
float radius = 100f;// 胶囊半径0.3米
float height = 0.1f;// 胶囊身高1.8米
float stepHeight = 100f;// 角色步高0.5米
Box floor = new Box(radius, height, stepHeight);
floor.scaleTextureCoordinates(new Vector2f(3, 6));
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
tex.setWrap(WrapMode.Repeat);
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("floor", floor);
geom.setMaterial(mat);
geom.setLocalTranslation(0, -1.8f, 0);// 将地板下移一定距离,让表面和xoz平面重合。
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(0);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new BoxCollisionShape(new Vector3f(radius, height, stepHeight)));
rigidBody.setFriction(10f);
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
private void model() {
float radius = 0.5f;// 胶囊半径0.3米
float height = 3.3f;// 胶囊身高1.8米
float stepHeight = 0.5f;// 角色步高0.5米
//模型
File file = new File("lina.zip");
if (file!=null) {
assetManager.registerLocator(
"https://www.icyboxs.com/icyboxs/lina.zip",
HttpZipLocator.class);
} else {
assetManager.registerLocator("lina.zip", ZipLocator.class);
}
character = new Node("Character");
Node model = (Node)assetManager.loadModel("Walk.gltf");
Node Stand = (Node)assetManager.loadModel("Stand.gltf");
model.move(0, -(height/2+radius), 0);
//model.scale(1.8f);
AnimComposer StandControl=Stand.getChild(0).getControl(AnimComposer.class);
character.attachChild(model);// 挂到角色根节点下
rootNode.attachChild(character);
control = model.getChild(0).getControl(AnimComposer.class);
control.setCurrentAction("Walk");
control.setGlobalSpeed(1f);
// AnimClip newClip = AnimUtils.retargetClip(control1.getAnimClip("Walk"), model, false, "Walk");
SkeletonMapping skeletonMapping=new SkeletonMapping();
SkinningControl modelSkinningControl = ((Node)model).getChild(0).getControl(SkinningControl.class);
SkinningControl WalkSkinningControl = ((Node)Stand).getChild(0).getControl(SkinningControl.class);
Armature armature = modelSkinningControl.getArmature();
Armature armature1 = WalkSkinningControl.getArmature();
modelSkinningControl.getArmature().getJointList().forEach(joint ->
skeletonMapping.addMapping(new BoneMapping(joint.getName(), joint.getName())));
AnimClip newClip1 = AnimationEdit.retargetAnimation(StandControl.getAnimClip("Stand"), armature1,armature , skeletonMapping, "Stand");
// retargetAnimation(control1.getAnimClip("Walk"), Walk, model, skeletonMapping, "Walk");
control.addAnimClip(newClip1);
LinkConfig defaultConfig = new LinkConfig();
RangeOfMotion defaultRom = new RangeOfMotion(1f);
dac = new DynamicAnimControl();
dac.link("Bip001-Head", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-R-Thigh", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-L-Thigh", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-R-Calf", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-L-Calf", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-R-UpperArm", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-L-UpperArm", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-L-Forearm", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-R-Forearm", defaultConfig, defaultRom); // right elbow
dac.link("Bip001-Spine", defaultConfig, defaultRom);
dac.link("ShotSkirt_04_Bone", defaultConfig, defaultRom); // right wrist
dac.link("ShotSkirt_03_Bone", defaultConfig, defaultRom); // right wrist
dac.link("ShotSkirt_01_Bone", defaultConfig, defaultRom); // right wrist
dac.link("ShotSkirt_02_Bone", defaultConfig, defaultRom); // right wrist
// NOTE: Complete configuration BEFORE adding control to a model.
// ninjaModel.addControl(dac);
model.getChild(0).addControl(dac);
dac.setPhysicsSpace(bulletAppState.getPhysicsSpace());//Dynamic
// 使用胶囊体作为玩家的碰撞形状
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(radius, height, 1);
// 使用CharacterControl来控制玩家物体
player = new CharacterControl(capsuleShape, stepHeight);
player.setJumpSpeed(10f);// 起跳速度
player.setFallSpeed(20f);// 坠落速度
player.setGravity(9.8f * 3);// 重力加速度
character.addControl(player);
bulletAppState.getPhysicsSpace().add(player);
for (PhysicsRigidBody body : dac.listRigidBodies()) {
player.getCharacter().addToIgnoreList(body);
}
chaseCam = new ChaseCamera(cam, character, inputManager);
inputManager.deleteMapping(CameraInput.CHASECAM_ZOOMOUT);
//to disable zoom in
inputManager.deleteMapping(CameraInput.CHASECAM_ZOOMIN);
flyCam.setEnabled(false);
chaseCam.setLookAtOffset(new Vector3f(0, 1.5f, 0));
chaseCam.setDragToRotate(false); //把鼠标锁定在窗口里
chaseCam.setMinVerticalRotation(-1.570625f);
}
/**
主循环
**/
@Override
public void simpleUpdate(float tpf) {
inputManager.setCursorVisible(false);
camDir.set(cam.getDirection()).multLocal(0.1f);
camLeft.set(cam.getLeft()).multLocal(0.1f);
camDir.y = 0;
camLeft.y = 0;
walkDirection.set(0, 0, 0);
// 计算运动方向
boolean changed = false;
if (left) {
walkDirectioni.addLocal(camLeft);
walkDirection.addLocal(camLeft);
changed = true;
}
if (right) {
walkDirectioni.addLocal(camLeft.negate());
walkDirection.addLocal(camLeft.negate());
changed = true;
}
if (up) {
walkDirectioni.addLocal(camDir);
walkDirection.addLocal(camDir);
changed = true;
}
if (down) {
walkDirectioni.addLocal(camDir.negate());
walkDirection.addLocal(camDir.negate());
changed = true;
}
if (v) {
// player.setViewDirection(walkDirectioni);
if(v){
}else{
}
// System.err.println();
changed = true;
}
if (changed) {
walkDirectioni.y = 0.0f;// 将行走速度的方向限制在水平面上。
walkDirectioni.normalizeLocal();// 单位化
walkDirectioni.multLocal(3f);// 改变速率
walkDirection.y = 0;// 将行走速度的方向限制在水平面上。
walkDirection.normalizeLocal();// 单位化
walkDirection.multLocal(0.3f);// 改变速率
}
if (walkDirection.length() != 0f) {
player.setViewDirection(walkDirection);
}
chaseCam.setDefaultDistance((-chaseCam.getVerticalRotation()/-1.57f-1f)*5f);
player.setWalkDirection(walkDirection);
}
/**
* 在指定位置放置一个物理砖块
*
* @param loc
* 砖块的位置
*/
private void makeBrick(Vector3f loc) {
// 网格
Box box = new Box(brickLength, brickHeight, brickWidth);
box.scaleTextureCoordinates(new Vector2f(1f, .5f));
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("brick", box);
geom.setMaterial(mat);
geom.setLocalTranslation(loc);// 把砖块放在指定位置
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(2f);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new BoxCollisionShape(new Vector3f(brickLength, brickHeight, brickWidth)));
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
/**
* 从摄像机所在位置发射一个小球,初速度方向与摄像机方向一致。
*/
private void shootBall() {
// 网格
Sphere sphere = new Sphere(32, 32, 0.4f, true, false);
sphere.setTextureMode(TextureMode.Projected);
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("cannon ball", sphere);
geom.setMaterial(mat);
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(1f);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new SphereCollisionShape(0.5f));
rigidBody.setPhysicsLocation(cam.getLocation());// 位置
rigidBody.setLinearVelocity(cam.getDirection().mult(50));// 初速度
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
public static void main(String[] args) {
CharacterControlDemo app = new CharacterControlDemo();
app.start();
}
}
I can’t really describe my problem, but this is a demo that requires Minie, you can create a class and get started