import settings from "./utils/settings.js" export default class Charactor { constructor(newMeshes, particleSystems, skeletons, animationGroups) { this.mesh = newMeshes[0] this.particleSystem = particleSystems[0] this.skeleton = skeletons[0] this.modelData = { newMeshes, particleSystems, skeletons, animationGroups } // 设置人物动画权重 this.animation = {} animationGroups.forEach((ani, index) => { this.animation[ani.name] = ani ani.play(true) if(index == 0) { ani.setWeightForAllAnimatables(1); this.actionType = ani.name + "-" + ani.name } else ani.setWeightForAllAnimatables(0); }) // 动画沙漏, 用于人物模型动画权重转换 this.aniHourglass = { upper: 0, lower: 1, } // 人物行走数据,通过startWalk更新 this.walkData = { pathArr: [], currentPoint: 0 } } set visible(isVisible) { this.modelData.newMeshes.forEach(mesh => mesh.isVisible = isVisible) } get visible() { return this.mesh.isVisible } updateAniTrans() { // 实时更新角色模型动画 if(this.aniHourglass.upper > 0) { // 10帧动画过渡 this.aniHourglass.upper = (this.aniHourglass.upper * 10 - 1) / 10 this.aniHourglass.lower = (this.aniHourglass.lower * 10 + 1) / 10 let fromAni = this.actionType.split("-")[0] let toAni = this.actionType.split("-")[1] this.animation[fromAni].setWeightForAllAnimatables(this.aniHourglass.upper); this.animation[toAni].setWeightForAllAnimatables(this.aniHourglass.lower); } } AniTransfromTo(aniName) { let lastAniName = this.actionType.split("-")[1] if(lastAniName == aniName) return // 颠倒沙漏 this.aniHourglass = { upper: 1, lower: 0, } this.actionType = lastAniName + "-" + aniName } startWalk(pathArr, charactorManager) { this.walkData = { pathArr: pathArr, currentPoint: -1 } if(pathArr.length >= 2 && this.actionType.split("-")[1] != "Walking") { this.walkData.currentPoint = 0 let video = pathArr[0].video if(video.isLoaded) { this.AniTransfromTo("Walking") this.walkByPath(charactorManager) } else { video.onloadeddata = () => { this.AniTransfromTo("Walking") this.walkByPath(charactorManager) } } } } walkByPath(charactorManager) { let charactor = this let { pathArr, currentPoint } = charactor.walkData // 更新房间的视频贴图 let video = pathArr[currentPoint].video charactorManager.app.updateHouseVideo(video) let nextPos = pathArr[currentPoint+1].point // console.error(pathArr, video) // 立即获取下一个点的旋转视频,防止中途旋转导致行走停止 let endPointId = pathArr[currentPoint+1].id console.log("[3D] send(getRotateVideoUrl): ", endPointId + "/" + endPointId) window.connection.socket.emit("getRotateVideoUrl", { videoPath: endPointId + "/" + endPointId, sceneCode: settings.sceneCode, roomId: settings.roomId, userId: settings.userId, }); window.connection.socket.emit("getRotateVideoUrl", { videoPath: endPointId + "/" + endPointId + "_rotate", sceneCode: settings.sceneCode, roomId: settings.roomId, userId: settings.userId, }); // 要跳转的位置与当前位置相同的话,就直接跳过,否则动画会出bug if(nextPos.x == this.mesh.position.x && nextPos.z == this.mesh.position.z) { console.warn("跳转点位与当前点位相同, 已跳过!") let nextPointData = charactor.walkData.pathArr[++charactor.walkData.currentPoint] if(nextPointData && nextPointData.video) { charactor.walkByPath(charactorManager) } else { charactor.AniTransfromTo("Idle") charactorManager.app.cameraController.lockCamera(false) } return } let startingPoint = charactor.mesh.position.clone(); startingPoint.y = nextPos.y; let walkDirc = nextPos.subtract(startingPoint).normalize(); // 行走动画 const walkAni = new BABYLON.Animation("walk", "position", settings.video.frameRate, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE); let walkFrameNum = settings.video.frameRate * video.duration const walkKeyFrames = [{ frame: 0, value: charactor.mesh.position },{ frame: walkFrameNum, value: nextPos }]; walkAni.setKeys(walkKeyFrames); // 转身动画 const newQuar = BABYLON.Quaternion.FromUnitVectorsToRef(new BABYLON.Vector3(0, 0, 1), walkDirc, new BABYLON.Quaternion()) const turnAroundAni = new BABYLON.Animation("turnAround", "rotationQuaternion", settings.video.frameRate, BABYLON.Animation.ANIMATIONTYPE_QUATERNION, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE); let turnAroundFrameNum = settings.video.frameRate * 0.2 // 0.2秒的帧数 const turnAroundFrames = [{ frame: 0, value: charactor.mesh.rotationQuaternion },{ frame: turnAroundFrameNum, value: newQuar }]; turnAroundAni.setKeys(turnAroundFrames); charactorManager.app.scene.beginDirectAnimation(charactor.mesh, [walkAni, turnAroundAni], 0, Math.max(walkFrameNum, turnAroundFrameNum), false, 1, () => { // 如果还有下一个点位就继续走,否则变为站立 let nextPointData = charactor.walkData.pathArr[++charactor.walkData.currentPoint] if(nextPointData && nextPointData.video) { charactor.walkByPath(charactorManager) } else { charactor.AniTransfromTo("Idle") charactorManager.app.cameraController.lockCamera(false) } }); } }