159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * To change this template, choose Tools | Templates
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * and open the template in the editor.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.bullet.control;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bullet.PhysicsSpace;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bullet.collision.shapes.CollisionShape;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.bullet.objects.PhysicsCharacter;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.InputCapsule;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeExporter;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.JmeImporter;
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.OutputCapsule;
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Quaternion;
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f;
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.renderer.RenderManager;
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.renderer.ViewPort;
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Spatial;
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.control.Control;
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException;
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author normenhansen
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class CharacterControl extends PhysicsCharacter implements PhysicsControl {
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Spatial spatial;
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean enabled = true;
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean added = false;
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected PhysicsSpace space = null;
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Vector3f viewDirection = new Vector3f(Vector3f.UNIT_Z);
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean useViewDirection = true;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean applyLocal = false;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public CharacterControl() {
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public CharacterControl(CollisionShape shape, float stepHeight) {
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super(shape, stepHeight);
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isApplyPhysicsLocal() {
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return applyLocal;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * When set to true, the physics coordinates will be applied to the local
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * translation of the Spatial
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param applyPhysicsLocal
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        applyLocal = applyPhysicsLocal;
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private Vector3f getSpatialTranslation() {
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (applyLocal) {
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return spatial.getLocalTranslation();
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return spatial.getWorldTranslation();
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Control cloneForSpatial(Spatial spatial) {
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        CharacterControl control = new CharacterControl(collisionShape, stepHeight);
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setCcdMotionThreshold(getCcdMotionThreshold());
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setCollideWithGroups(getCollideWithGroups());
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setCollisionGroup(getCollisionGroup());
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setFallSpeed(getFallSpeed());
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setGravity(getGravity());
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setJumpSpeed(getJumpSpeed());
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setMaxSlope(getMaxSlope());
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setPhysicsLocation(getPhysicsLocation());
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setUpAxis(getUpAxis());
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setApplyPhysicsLocal(isApplyPhysicsLocal());
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        control.setSpatial(spatial);
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return control;
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setSpatial(Spatial spatial) {
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (getUserObject() == null || getUserObject() == this.spatial) {
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            setUserObject(spatial);
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.spatial = spatial;
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (spatial == null) {
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (getUserObject() == spatial) {
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                setUserObject(null);
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return;
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setPhysicsLocation(getSpatialTranslation());
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setEnabled(boolean enabled) {
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.enabled = enabled;
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (space != null) {
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (enabled && !added) {
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (spatial != null) {
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    warp(getSpatialTranslation());
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                space.addCollisionObject(this);
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                added = true;
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if (!enabled && added) {
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                space.removeCollisionObject(this);
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                added = false;
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isEnabled() {
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return enabled;
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setViewDirection(Vector3f vec) {
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        viewDirection.set(vec);
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Vector3f getViewDirection() {
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return viewDirection;
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isUseViewDirection() {
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return useViewDirection;
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setUseViewDirection(boolean viewDirectionEnabled) {
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.useViewDirection = viewDirectionEnabled;
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void update(float tpf) {
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (enabled && spatial != null) {
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Quaternion localRotationQuat = spatial.getLocalRotation();
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vector3f localLocation = spatial.getLocalTranslation();
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (!applyLocal && spatial.getParent() != null) {
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                getPhysicsLocation(localLocation);
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                localLocation.subtractLocal(spatial.getParent().getWorldTranslation());
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                localLocation.divideLocal(spatial.getParent().getWorldScale());
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation);
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                spatial.setLocalTranslation(localLocation);
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (useViewDirection) {
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    localRotationQuat.lookAt(viewDirection, Vector3f.UNIT_Y);
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    spatial.setLocalRotation(localRotationQuat);
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else {
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                spatial.setLocalTranslation(getPhysicsLocation());
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                localRotationQuat.lookAt(viewDirection, Vector3f.UNIT_Y);
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                spatial.setLocalRotation(localRotationQuat);
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void render(RenderManager rm, ViewPort vp) {
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (enabled && space != null && space.getDebugManager() != null) {
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (debugShape == null) {
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                attachDebugShape(space.getDebugManager());
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            debugShape.setLocalTranslation(getPhysicsLocation());
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            debugShape.updateLogicalState(0);
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            debugShape.updateGeometricState();
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            rm.renderScene(debugShape, vp);
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setPhysicsSpace(PhysicsSpace space) {
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (space == null) {
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (this.space != null) {
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                this.space.removeCollisionObject(this);
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                added = false;
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (this.space == space) {
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return;
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            space.addCollisionObject(this);
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            added = true;
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.space = space;
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public PhysicsSpace getPhysicsSpace() {
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return space;
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void write(JmeExporter ex) throws IOException {
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.write(ex);
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        OutputCapsule oc = ex.getCapsule(this);
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(enabled, "enabled", true);
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(applyLocal, "applyLocalPhysics", false);
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(useViewDirection, "viewDirectionEnabled", true);
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(viewDirection, "viewDirection", new Vector3f(Vector3f.UNIT_Z));
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(spatial, "spatial", null);
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void read(JmeImporter im) throws IOException {
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        super.read(im);
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        InputCapsule ic = im.getCapsule(this);
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        enabled = ic.readBoolean("enabled", true);
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        useViewDirection = ic.readBoolean("viewDirectionEnabled", true);
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        viewDirection = (Vector3f) ic.readSavable("viewDirection", new Vector3f(Vector3f.UNIT_Z));
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        applyLocal = ic.readBoolean("applyLocalPhysics", false);
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        spatial = (Spatial) ic.readSavable("spatial", null);
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        setUserObject(spatial);
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
209