参考资料
EarthSDK在线示例:路径-车辆运动
EarthSDK:XE
EarthSDK API:Earth (重点关注 interaction)
EarthSDK API:MVVM(重点关注 MVVM.watch)
EarthSDK API:Path
EarthSDK API:Tree(重点关注 $refs 及 节点创建方法)
EarthSDK API:XbsjCzmObj
概述
实现效果:点击门->播放开门动画->等待数秒后->播放关门动画
最终效果录屏
推拉门动画(开、关)
绘制路径
使用“标绘-高级-路径动画”在模型中绘制路径,在“路径属性”面板中可根据实际情况修改相关属性。
将动画加载至模型中
在线查看路径代码
选中“路径动画”图层,右键,在弹出的选项中选择“查看加载代码”,即可看到路径的代码,重点是获取路径的position数据,在这里获取的路径动画的positions是不精确的,还需要在代码中去调整。
通过JS控制动画的执行与结束
在线查看路径代码之后,需要参考EarthSDK API将室内、门的模型加载到场景树中,并控制开关门动画的执行与结束。
项目关键代码示例(React)
const leafJson = [{"czmObject": {"xbsjType": "Tileset","xbsjGuid": "a341be0f-d5df-48c3-9c36-8af547e64000","name": "室内","url": "...", // 此处为 室内模型 3dtiles数据地址"xbsjPosition": [2.044452086968357,0.6398399028959787,271.22052428840794],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "leftDoor","czmObject": {"xbsjType": "Tileset","xbsjGuid": "8848caa9-7310-4fa3-8f05-959a26605c54","name": "入口左侧门","url": "...", // 此处为 门模型 3dtiles数据地址"xbsjPosition": [2.04445030673252,0.6398409361655967,271.5950337444273],"xbsjRotation": [1.5707963267948966,0,1.5707963267948966],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "openPath","czmObject": {"xbsjType": "Path","xbsjGuid": "791ba4ac-a022-4f04-8e36-66dff64aa24d","name": "开门路径动画","positions": [[2.04445030673252,0.6398409361655967,271.5950337444273],[2.04445030673252,0.6398411909207626,271.5950337444273]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "closePath","czmObject": {"xbsjType": "Path","xbsjGuid": "0a1e9f7e-18fb-4996-bd1a-1303a2fcc6cc","name": "关门路径动画","positions": [[2.04445030673252,0.6398411909207626,271.5950337444273],[2.04445030673252,0.6398409361655967,271.5950337444273]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}}];export default leafJson;
import leafJson from "./leafJson"; // 引入路径可根据实际情况调整class pathAnimationDemo extends Component{constructor(props) {super(props);this.earth = null;},componentDidMount() {XE.ready().then(()=>{// 加载标绘插件 js...}).then(()=>{this.startUp();})},startUp = ()=>{// 创建 Earth实例this.earth = new XE.Earth("earthContainer");// 开启拾取(鼠标点击事件)this.earth.interaction.picking.enabled = true;// 通过JSON配置创建节点this.earth.sceneTree.root.children.push(...leafJson);// 获取节点下挂接的对象const leftDoor = this.earth.sceneTree.$refs.leftDoor.czmObject;const openPath = this.earth.sceneTree.$refs.leftDoor.openPath;const closePath = this.earth.sceneTree.$refs.leftDoor.closePath;// 给对象添加点击事件leftDoor.onclick = () => {// 点击门时播放开门动画openPath.playing = true;/* MVVM.watch() 对响应式属性对象的监控,需要三个参数。*第一个参数是监控的对象;* 第二个参数是该对象的属性,注意要用字符串表示;*第三个参数是一个回调函数,当属性的值发生变化时,该函数会响应;*/XE.MVVM.watch(openPath, "currentPosition", openPosition => {leftDoor.xbsjPosition = [...openPosition];/** 如果已经移动到开门路径的终点,数秒钟后开始执行关门动画*/if (openPosition[1] === openPath.positions[1][1]) {// 如果currentPosition 和 开门路径终点相等, 停止播放开门动画// 有时候openPosition[1]会比openPath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证// 出现上述问题之后,需要打印一下openPosition[1],将openPath.positions[1][1]的值改成openPosition[1]的值即可// 如果还不行,就将openPath.positions[1][1]的值往上或往下调一调openPath.playing = false;// 5s之后,执行关门动画setTimeout(()=>{closePath.playing = true;XE.MVVM.watch(closePath, "currentPosition", closePosition => {leftDoor.xbsjPosition = [...closePosition];if (closePosition[1] === closePath.positions[1][1]) {// 如果currentPosition 和 关门路径终点相等, 停止播放关门动画// 有时候closePosition[1]会比closePath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证// 出现上述问题之后,需要打印一下closePosition[1],将closePath.positions[1][1]的值改成closePosition[1]的值即可// 如果还不行,就将closePath.positions[1][1]的值往上或往下调一调closePath.playing = false;}})}, 5000)}})}}return (<div id="earthContainer"></div>)}export default pathAnimationDemo;
问题记录
判断开门/关门动画是否执行完毕时,position[1]和path.positions[1][1]会出现一点差别:有时候position[1]会比path.positions[1][1]多几位小数或者稍微大一点,具体原因待考证。
出现上述问题之后,需要打印一下position[1],将path.positions[1][1]的值改成position[1]的值即可。如果还不行,就将path.positions[1][1]的值往上或往下调一调试试。
