移动端虚拟摇杆控制人物转向移动2

300 阅读2分钟

    // Low Poly Character with Blender Tutorial of Grant Abbitt: https://www.youtube.com/user/mediagabbitt
    // Character animations by Mixamo: https://www.mixamo.com/

    engine.enableOfflineSupport = false;

    // Scene and Camera
    var scene = new BABYLON.Scene(engine);

    var camera1 = new BABYLON.ArcRotateCamera("camera1", Math.PI/3, Math.PI / 4, 10, new BABYLON.Vector3(0, -5, 0), scene);
    scene.activeCamera = camera1;
    scene.activeCamera.attachControl(canvas, true);
    camera1.lowerRadiusLimit = 2;
    camera1.upperRadiusLimit = 10;
    camera1.wheelDeltaPercentage = 0.01;

    // Lights
    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.6;
    light.specular = BABYLON.Color3.Black();

    var light2 = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(0, -0.5, -1.0), scene);
    light2.position = new BABYLON.Vector3(0, 5, 5);

    // Skybox
    var skybox = BABYLON.MeshBuilder.CreateBox("skyBox", { size: 1000.0 }, scene);
    var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
    skyboxMaterial.backFaceCulling = false;
    skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/skybox2", scene);
    skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
    skyboxMaterial.diffuseColor = BABYLON.Color3.Black()
    skyboxMaterial.specularColor = BABYLON.Color3.Black();
    skybox.material = skyboxMaterial;

    // GUI
    var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
    var instructions = new BABYLON.GUI.TextBlock();
    instructions.text = "Move w/ WASD keys, B for Samba, look with the mouse";
    instructions.color = "white";
    instructions.fontSize = 16;
    instructions.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT
    instructions.textVerticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM
    advancedTexture.addControl(instructions);

    // Ground
    var ground = BABYLON.MeshBuilder.CreateGround("ground", { height: 50, width: 50, subdivisions: 4 }, scene);
    var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
    groundMaterial.diffuseTexture = new BABYLON.Texture("textures/wood.jpg", scene);
    groundMaterial.diffuseTexture.uScale = 30;
    groundMaterial.diffuseTexture.vScale = 30;
    groundMaterial.specularColor = new BABYLON.Color3(.1, .1, .1);
    ground.material = groundMaterial;

    // Keyboard events
    var inputMap = {};
    scene.actionManager = new BABYLON.ActionManager(scene);
    scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnKeyDownTrigger, function (evt) {
        inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
    }));
    scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnKeyUpTrigger, function (evt) {
        inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
    }));
    // 创建左侧摇杆
    var leftJoystick = new BABYLON.VirtualJoystick(true);
    BABYLON.VirtualJoystick.Canvas.style.zIndex = "4";

     console.log('alpha',camera1.alpha)
    // Load hero character
    BABYLON.SceneLoader.ImportMesh("", "https://assets.babylonjs.com/meshes/", "HVGirl.glb", scene, function (newMeshes, particleSystems, skeletons, animationGroups) {
        var hero = newMeshes[0];

        //Scale the model down        
        hero.scaling.scaleInPlace(0.1);

        //Lock camera on the character 
        camera1.target = hero;

        //Hero character variables 
        var heroSpeed = 0.03;
        var heroSpeedBackwards = 0.01;
        var heroRotationSpeed = 0.1;

        var animating = true;

        const walkAnim = scene.getAnimationGroupByName("Walking");
        const walkBackAnim = scene.getAnimationGroupByName("WalkingBack");
        const idleAnim = scene.getAnimationGroupByName("Idle");
        const sambaAnim = scene.getAnimationGroupByName("Samba");

        
        
        leftJoystick.reverseLeftRight = true
        //Rendering loop (executed for everyframe)
        scene.onBeforeRenderObservable.add(() => {
            if(leftJoystick.pressed){
            // 计算要移动到的坐标
            // r = 360 - (camera1.alpha*180/Math.PI)
            // let an = camera1.alpha%Math.PI===0?Math.PI:camera1.alpha%Math.PI
            let angle_careme = camera1.alpha
           
            // angle_careme = 0
            // 计算相机偏转角度
            let r = Math.PI - angle_careme 

            // r = Math.PI / 2 
            // r = 0
            // r = -r
            // r = camera1.alpha
            // leftJoystick.deltaPosition.x = 1
            // leftJoystick.deltaPosition.y = 0
            console.log('ori:', leftJoystick.deltaPosition.x,leftJoystick.deltaPosition.y)
            
            
            let moveX = leftJoystick.deltaPosition.x * (engine.getDeltaTime()/1000) * -2;
            let moveZ = leftJoystick.deltaPosition.y * (engine.getDeltaTime()/1000) * -2;
            
            // let moveX = 1
            // let moveZ = 0
            // 计算偏转公式
            let d_x1 = moveX * Math.cos(r) - moveZ*Math.sin(r)
            let d_y1 = moveX*Math.sin(r) + moveZ*Math.cos(r)

            console.log('d_x1 d_y1:',d_x1,d_y1)
            // 再计算旋转方向
            let angle = Math.atan2(d_y1, d_x1);
            console.log('angle', angle)
            // 加上相机的偏转角度,这样观察的时候人物总是在正面?
            // angle += camera1.rotation.y;
            // angle = Math.abs(camera1.alpha%Math.PI - angle)
            // 使用四元数代替弧度值,避免万向锥问题
            let targ = BABYLON.Quaternion.FromEulerAngles(0, angle, 0);
            hero.rotationQuaternion = BABYLON.Quaternion.Slerp(hero.rotationQuaternion, targ, 0.5);
            // hero.position.x += d_x1;
            // hero.position.z += d_y1
            hero.moveWithCollisions(hero.forward.scaleInPlace(heroSpeed));
            // console.log(leftJoystick.deltaPosition)
            
        }
            var keydown = false;
            //Manage the movements of the character (e.g. position, direction)
            if (inputMap["w"]) {
                hero.moveWithCollisions(hero.forward.scaleInPlace(heroSpeed));
                keydown = true;
            }
            if (inputMap["s"]) {
                hero.moveWithCollisions(hero.forward.scaleInPlace(-heroSpeedBackwards));
                keydown = true;
            }
            if (inputMap["a"]) {
                hero.rotate(BABYLON.Vector3.Up(), -heroRotationSpeed);
                keydown = true;
            }
            if (inputMap["d"]) {
                hero.rotate(BABYLON.Vector3.Up(), heroRotationSpeed);
                keydown = true;
            }
            if (inputMap["b"]) {
                keydown = true;
            }

            //Manage animations to be played  
            if (keydown) {
                if (!animating) {
                    animating = true;
                    if (inputMap["s"]) {
                        //Walk backwards
                        walkBackAnim.start(true, 1.0, walkBackAnim.from, walkBackAnim.to, false);
                    }
                    else if
                        (inputMap["b"]) {
                        //Samba!
                        sambaAnim.start(true, 1.0, sambaAnim.from, sambaAnim.to, false);
                    }
                    else {
                        //Walk
                        walkAnim.start(true, 1.0, walkAnim.from, walkAnim.to, false);
                    }
                }
            }
            else {

                if (animating) {
                    //Default animation is idle when no key is down     
                    idleAnim.start(true, 1.0, idleAnim.from, idleAnim.to, false);

                    //Stop all animations besides Idle Anim when no key is down
                    sambaAnim.stop();
                    walkAnim.stop();
                    walkBackAnim.stop();

                    //Ensure animation are played only once per rendering loop
                    animating = false;
                }
            }
        });
    });
// Create button to toggle joystick overlay canvas
    var btn = document.createElement("button")
    btn.innerText = "Enable/Disable Joystick"
    btn.style.zIndex = 10;
    btn.style.position = "absolute"
    btn.style.bottom = "30px"
    btn.style.right = "0px"
    // btn.style.height = "100%"
    // btn.style.width = "50%"
    document.body.appendChild(btn)

    // Button toggle logic
    btn.onclick = ()=>{
        if(BABYLON.VirtualJoystick.Canvas.style.zIndex == "-1"){
            BABYLON.VirtualJoystick.Canvas.style.zIndex = "4";
            // camera1.alpha += Math.PI/2
        }else{
            BABYLON.VirtualJoystick.Canvas.style.zIndex = "-1";
        }
    }

    // Dispose button on rerun
    scene.onDisposeObservable.add(()=>{
        BABYLON.VirtualJoystick.Canvas.style.zIndex = "-1";
        document.body.removeChild(btn)
    })
    return scene;
}