// 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;
}