chasecamera.java

来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 542 行 · 第 1/2 页

JAVA
542
字号
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jme.input;

import java.util.HashMap;

import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.scene.Spatial;

/**
 * <p>
 * Camera handler that will smoothly follow a set scene element, allowing for
 * rotation about and zoom on that element.
 * </p>
 * 
 * <p>
 * see the javadoc for update(float time) for information on how positioning
 * works.
 * </p>
 * 
 * @author <a href="mailto:josh@renanse.com">Joshua Slack</a>
 * @version $Revision: 1.25 $
 */

public class ChaseCamera extends InputHandler {
    public static final String PROP_INITIALSPHERECOORDS = "sphereCoords";
    public static final String PROP_DAMPINGK = "dampingK";
    public static final String PROP_SPRINGK = "springK";
    public static final String PROP_TARGETOFFSET = "targetOffset";
    public static final String PROP_WORLDUPVECTOR = "worldUpVec";
    public static final String PROP_ENABLESPRING = "disableSpring";
    public static final String PROP_STAYBEHINDTARGET = "stayBehindTarget";
    public static final String PROP_MAINTAINAZIMUTH = "maintainAzimuth";
    public static final String PROP_MAXDISTANCE = "maxDistance";
    public static final String PROP_MINDISTANCE = "minDistance";

    public static final float DEFAULT_DAMPINGK = 12.0f;
    public static final float DEFAULT_SPRINGK = 36.0f;
    public static final float DEFAULT_MAXDISTANCE = 0f;
    public static final float DEFAULT_MINDISTANCE = 0f;
    public static final boolean DEFAULT_ENABLESPRING = true;
    public static final boolean DEFAULT_STAYBEHINDTARGET = false;
    public static final boolean DEFAULT_MAINTAINAZIMUTH = false;
    public static final Vector3f DEFAULT_WORLDUPVECTOR = Vector3f.UNIT_Y.clone();

    protected Vector3f idealSphereCoords;
    protected Vector3f idealPosition = new Vector3f();
    protected Camera cam;
    protected Vector3f velocity = new Vector3f();
    protected Spatial target;
    
    protected float dampingK;
    protected float springK;
    protected float maxDistance;
    protected float minDistance;
    protected boolean enableSpring;
    protected boolean stayBehindTarget;
    protected boolean looking;
    protected boolean maintainAzimuth;
    protected boolean forceAzimuthUpdate = false;

    protected Vector3f dirVec = new Vector3f();
    protected Vector3f worldUpVec = new Vector3f(DEFAULT_WORLDUPVECTOR);
    protected Vector3f upVec = new Vector3f();
    protected Vector3f leftVec = new Vector3f();
    protected Vector3f targetOffset = new Vector3f();
    protected Vector3f targetPos = new Vector3f();
    protected Vector3f oldCameraDir = new Vector3f();
    protected Vector3f compVect = new Vector3f();

    /** The ThirdPersonMouseLook action, kept as a field to allow easy access to setting speeds and y axis flipping. */
    protected ThirdPersonMouseLook mouseLook;

    protected float speed;

    /**
     * Simple constructor that accepts a Camera and a target and sets all
     * properties to their defaults.
     *
     * @param cam
     *            Camera to control
     * @param target
     *            the target node to chase
     */
    public ChaseCamera(Camera cam, Spatial target) {
        this(cam, target, null);
    }

    /**
     * More involved constructor allowing the setting of all member fields in
     * ChaseCamera and its associated ThirdPersonMouseLook object via a HashMap
     * of properties.
     *
     * @param cam
     *            Camera to control
     * @param target
     *            the target node to chase
     * @param props
     *            a hashmap of properties to set this camera up with. keys are
     *            from the statics ChaseCamera.PROP_XXXX and
     *            ThirdPersonMouseLook.PROP_XXXX
     */
    public ChaseCamera(Camera cam, Spatial target, HashMap<String, Object> props) {
        super();
        this.cam = cam;
        this.target = target;

        setupMouse();
        updateProperties(props);
    }

    /**
     * Set up a relative mouse and the ThirdPersonMouseLook used in this
     * camera's control.
     */
    protected void setupMouse() {
        RelativeMouse mouse = new RelativeMouse("Mouse Input");
        mouse.registerWithInputHandler(this);

        if (mouseLook != null)
            removeAction(mouseLook);

        mouseLook = new ThirdPersonMouseLook(mouse, this, target);
        addAction(mouseLook);
    }

    /**
     * <code>updateProperties</code> allows you to update all properties of
     * this chase camera and its related mouse look class.
     *
     * @param props
     */
    public void updateProperties(HashMap<String, Object> props) {
        if (mouseLook != null)
            mouseLook.updateProperties(props);

        if (idealSphereCoords == null && mouseLook != null)
            idealSphereCoords = new Vector3f(
                    (mouseLook.getMaxRollOut() - mouseLook.getMinRollOut()) / 2f,
                    0, mouseLook.getMaxAscent() * .5f);
        else
            idealSphereCoords = new Vector3f(
                    0,
                    0, 0);
        idealSphereCoords = ((Vector3f)getObjectProp(props, PROP_INITIALSPHERECOORDS, idealSphereCoords));

        worldUpVec = (Vector3f)getObjectProp(props, PROP_WORLDUPVECTOR, DEFAULT_WORLDUPVECTOR);
        targetOffset = (Vector3f)getObjectProp(props, PROP_TARGETOFFSET, new Vector3f());

        dampingK = getFloatProp(props, PROP_DAMPINGK, DEFAULT_DAMPINGK);
        springK = getFloatProp(props, PROP_SPRINGK, DEFAULT_SPRINGK);
        maxDistance = getFloatProp(props, PROP_MAXDISTANCE, DEFAULT_MAXDISTANCE);
        minDistance = getFloatProp(props, PROP_MINDISTANCE, DEFAULT_MINDISTANCE);

        enableSpring = getBooleanProp(props, PROP_ENABLESPRING, DEFAULT_ENABLESPRING);
        stayBehindTarget = getBooleanProp(props, PROP_STAYBEHINDTARGET, DEFAULT_STAYBEHINDTARGET);
        maintainAzimuth = getBooleanProp(props, PROP_MAINTAINAZIMUTH, DEFAULT_MAINTAINAZIMUTH);
    }

    public void setCamera(Camera cam) {
        this.cam = cam;
    }

    public Camera getCamera() {
        return cam;
    }

    /**
     * <p>
     * <code>update</code> repositions the camera based on the current
     * position and an ideal position using spherical coordinates.
     * </p>
     *
     * <p>
     * The new position is determined by checking where the target has moved to
     * and getting an offset in relation to the XZ plane. Using this, the ideal
     * spherical coordiantes for the camera are updated for the angle around the
     * up axis (azimuth). Thus, ideal height and distance from the target are
     * still the same regardless of how far the target has moved.
     * </p>
     *
     * <p>
     * Next, we using a spring system to move from the camera's current position
     * to the calculated "ideal position". This is done by accelerating towards
     * the ideal position using the amount of that distance and the springK
     * factor. This acceleration is damped by the dampingK factor amplified by
     * the magnitude of the current velocity of the camera.
     * </p>
     *
     * <p>
     * The springK and dampingK factors can be expressed as a damping ratio:
     * </p>
     *
     * <pre>
     * ratio = dampingK / (2 * sqrt(springK))
     * </pre>
     *
     * <p>
     * Typically you want the ratio to come out equal to 1. Values less than 1
     * will ocillate before coming to rest. Values over 1 will take longer than
     * necessary to come to equilibrium.
     * </p>
     *
     * <p>
     * Note that if disableSpring is true, the currentPosition is always set to the idealPosition.
     * </p>
     *
     * <p>
     * <i>See Game programming Gems #4 pgs 303-307 for more in-depth information
     * on the technique.</i>
     * </p>
     *
     * @param time
     *            amount of time since last update (in seconds)
     * @see com.jme.input.InputHandler#update(float)
     */
    public void update(float time) {
        if ( !isEnabled() ) return;

        super.update(time);
        Vector3f camPos = cam.getLocation();
        updateTargetPosition(camPos);

        if (!Vector3f.isValidVector(camPos) || !Vector3f.isValidVector(targetPos))
            return;

        updateIdealAzimuth(time, camPos);

        convertIdealSphereToCartesian();

        updateCameraPosition(time, camPos);

        enforceMinMaxDistance(camPos);

        // Look at our target
        cam.lookAt(targetPos, worldUpVec);

        if (maintainAzimuth)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?