接触 Cocos Creator 已经一年多, 体验是酸甜苦辣俱全, 不过仍然要夸一下这东西确实神作, 可以让我这种网页小白靠着Unity开发经验直接上手. 到目前为止的 Cocos Creator 编辑器版本(v2.4.3), 对移动端的运动传感器支持仍然是有限, 只提供了一个加速度数据接口, 加速度数据可以提供重力方向, 动作力度, 轨迹识别, 算法好一点的还能粗略做个惯性导航. 但是, 可惜, 缺少了关键的陀螺仪传感器接口, 应用程序无法得知手机的3D姿态, 在某些应用中这是个必备的数据, 例如网页运行 VR游戏 和 Panorama(全景图片). 于是需要自己开发脚本组件实现.

根据以前开发 Android 原生VR应用的经验, 推测 Cocos Creator 不提供陀螺仪数据接口的原因, 可能是为了引擎稳定性和兼容性更好? 因为不是所有手机都有陀螺仪. 首先要搞清楚加速度传感器(Accelerometer)和陀螺仪传感器(Gyrometer)是两个独立的硬件设备, 有些低端手机是只有加速度传感器没有陀螺仪传感器(陀螺仪传感器更贵), 壕们可能很少见到这样的手机, 然而这种手机我就用过好几个. 奇葩的是这两个数据又是放在同一个HTML5事件传回的, 所以在自己开发的组件里, 首先要实现检测用户设备是否支持陀螺仪数据接口, 然后再实现功能和填各种坑.

加速度数据和陀螺仪数据在 HTML5 中统一由事件 DeviceMotionEvent 传回, 具体用法可以直接参考网上资料, DeviceMotionEvent - Web API 接口参考 | MDN (mozilla.org). 看了文档才知道, 事件传回数据中只包含了采样数据和时间戳, 如果设备没有陀螺仪传感器, 事件对象中的 "rotationRate" 是不存在的, JS代码中就是 "undefined", 通过检测 "rotationRate" 是否"undefined"可以判断陀螺仪设备是否存在.

如果是运行在 iPhone 手机上, 因为 iOS 系统对传感器权限的严格控制, DeviceMotionEvent 需要用户授权才能传出数据, 通过调试代码发现 iOS 系统里的 DeviceMotionEvent 有个 requestPermission 静态函数, 需要先调用一下这个静态函数, 弹出提示用户授权对话框, 用户选择允许后, 页面才能获得 DeviceMotion 事件和数据. Android 系统目前没有这种限制(估计以后也会有).

iPhone 上还有更严格的权限限制, requestPermission 必须在某个UI交互事件的回调函数中调用才能弹出请求授权对话框, 例如某个按钮的 OnClick, 如果在页面onload或场景初始化代码中悄无声息的 requestPermission 没有任何效果. Cocos Creator 程序可以在 Button 组件的 OnClick 事件处理代码中调用 requestPermission, 就可以在 iPhone 上成功弹出授权对话框. 解决授权问题扒了很多资料, 一直扒到了 DeviceOrientation Event Specification (w3c.github.io), 总算查清这个问题, 如果想看通俗易懂的总结可以看 在IOS中DeviceMotion及DeviceOrientation事件不触发的问题_greenwishing的专栏-CSDN博客.

其它小坑, 比如运行需要 HTTPS 协议, iPhone 手机上重力方向需要颠倒, iPhone 手机上传感器刷新时间的单位要转换等, 一一踩平...

搞清楚了以上问题和要点, 就可以自己实现一个运动传感器功能组件了, 展示的代码是被做成了名为 DeviceMotionEvent 的组件, 方便使用. 在编辑器里直接拖放脚本到 Node 对象即可, 多个 Node 对象可以各自拥有一个 DeviceMotionEvent 而互不影响.

/*** DeviceMotionEvent component* * MatrixLife's component for getting device motion data in Cocos Creator.** E-Mail:  lv_ximing@qq.com* Version: 0.1?* Done-At: 2020.11.28*/cc.Class({extends: cc.Component,statics:{EVENT_INITIALIZE:   'MATRIXLIFE_DEVICEMOTION_INITIALIZE_EVENT',EVENT_UNINITIALIZE: 'MATRIXLIFE_DEVICEMOTION_UNINITIALIZE_EVENT',},properties:{_SampleInterval:  0,_HasAcceleration: false,_HasGravityState: false,_HasGyrometer:    false,_LastEventTimeStamp: 0.0,_Acceleration:       null,_GravityState:       null,_GyroState:          null,_GravityNeedInvert:  false,_DeviceMotionFirstInstance: null,_DeviceMotionEventInstance: null,HasAcceleration:{type: cc.Boolean,get(){return this._HasAcceleration;},},HasGravityState:{type: cc.Boolean,get(){return this._HasGravityState;},},HasGyrometer:{type: cc.Boolean,get(){return this._HasGyrometer;},},Acceleration:{type: cc.Vec3,get(){return this._Acceleration;},},GravityState:{type: cc.Vec3,get(){return this._GravityState;},},GyroState:{type: cc.Quat,get(){return this._GyroState;},},},_OnDeviceMotionFirst(e){var ua_text = navigator.userAgent;if((ua_text.indexOf('iPhone') >= 0) || (ua_text.indexOf('Mac OS X') >= 0)){this._SampleInterval = e.interval;this._GravityNeedInvert = true;}else{this._SampleInterval = e.interval / 1000.0;this._GravityNeedInvert = false;}this._LastEventTimeStamp = e.timeStamp;if(e.acceleration && e.acceleration.x && e.acceleration.y && e.acceleration.z){this._HasAcceleration = true;this._Acceleration.x = e.acceleration.x;this._Acceleration.y = e.acceleration.y;this._Acceleration.z = e.acceleration.z;}if(e.accelerationIncludingGravity && e.accelerationIncludingGravity.x && e.accelerationIncludingGravity.y && e.accelerationIncludingGravity.z){this._HasGravityState = true;this._GravityState.x = e.accelerationIncludingGravity.x;this._GravityState.y = e.accelerationIncludingGravity.y;this._GravityState.z = e.accelerationIncludingGravity.z;}var gv_init = new cc.Vec3(this._GravityState.x, this._GravityState.y, this._GravityState.z);if(this._GravityNeedInvert){gv_init.x = -(gv_init.x);gv_init.y = -(gv_init.y);gv_init.z = -(gv_init.z);}cc.Vec3.normalize(gv_init, gv_init);cc.Quat.rotationTo(this._GyroState, gv_init, cc.Vec3.UP);if(e.rotationRate && e.rotationRate.alpha && e.rotationRate.beta && e.rotationRate.gamma){this._HasGyrometer = true;var rot_x = new cc.Quat();var rot_y = new cc.Quat();var rot_z = new cc.Quat();cc.Quat.rotateX(rot_x, cc.Quat.IDENTITY, e.rotationRate.alpha * this._SampleInterval * Math.DEG_TO_RAD);cc.Quat.rotateY(rot_y, cc.Quat.IDENTITY, e.rotationRate.beta  * this._SampleInterval * Math.DEG_TO_RAD);cc.Quat.rotateZ(rot_z, cc.Quat.IDENTITY, e.rotationRate.gamma * this._SampleInterval * Math.DEG_TO_RAD);cc.Quat.multiply(this._GyroState, this._GyroState, rot_z);cc.Quat.multiply(this._GyroState, this._GyroState, rot_x);cc.Quat.multiply(this._GyroState, this._GyroState, rot_y);}this.node.emit('MATRIXLIFE_DEVICEMOTION_INITIALIZE_EVENT', this);window.removeEventListener('devicemotion', this._DeviceMotionFirstInstance);window.addEventListener('devicemotion', this._DeviceMotionEventInstance);},_OnDeviceMotionEvent(e){var dt = (e.timeStamp - this._LastEventTimeStamp) / 1000.0;this._LastEventTimeStamp = e.timeStamp;if(this._HasAcceleration){this._Acceleration.x = e.acceleration.x;this._Acceleration.y = e.acceleration.y;this._Acceleration.z = e.acceleration.z;}if(this._HasGravityState){this._GravityState.x = e.accelerationIncludingGravity.x;this._GravityState.y = e.accelerationIncludingGravity.y;this._GravityState.z = e.accelerationIncludingGravity.z;}if(this._HasGyrometer){var rot_x = new cc.Quat();var rot_y = new cc.Quat();var rot_z = new cc.Quat();cc.Quat.rotateX(rot_x, cc.Quat.IDENTITY, e.rotationRate.alpha * dt * Math.DEG_TO_RAD);cc.Quat.rotateY(rot_y, cc.Quat.IDENTITY, e.rotationRate.beta  * dt * Math.DEG_TO_RAD);cc.Quat.rotateZ(rot_z, cc.Quat.IDENTITY, e.rotationRate.gamma * dt * Math.DEG_TO_RAD);cc.Quat.multiply(this._GyroState, this._GyroState, rot_z);cc.Quat.multiply(this._GyroState, this._GyroState, rot_x);cc.Quat.multiply(this._GyroState, this._GyroState, rot_y);}},TryInitialize(){if(window.DeviceMotionEvent){if(window.DeviceMotionEvent.requestPermission){var _THIS = this;window.DeviceMotionEvent.requestPermission().then(function(ps){window.addEventListener('devicemotion', _THIS._DeviceMotionFirstInstance);},);}else{window.addEventListener('devicemotion', this._DeviceMotionFirstInstance);}}},TryUninitialize(){if(window.DeviceMotionEvent){window.removeEventListener('devicemotion', this._DeviceMotionFirstInstance);window.removeEventListener('devicemotion', this._DeviceMotionEventInstance);}this._SampleInterval = 0;this._HasAcceleration = false;this._HasGravityState = false;this._HasGyrometer = false;this.node.emit('MATRIXLIFE_DEVICEMOTION_UNINITIALIZE_EVENT', this);},// LIFE-CYCLE CALLBACKS:onDestroy(){this.TryUninitialize();},onLoad(){if(Math.DEG_TO_RAD == undefined) Math.DEG_TO_RAD = Math.PI / 180.0;if(Math.RAD_TO_DEG == undefined) Math.RAD_TO_DEG = 180.0 / Math.PI;if(cc.Quat.IDENTITY == undefined) cc.Quat.IDENTITY = new cc.Quat(0.0, 0.0, 0.0, 1.0);this._Acceleration = new cc.Vec3(0.0, 0.0, 0.0);this._GravityState = new cc.Vec3(0.0, 9.8, 0.0);this._GyroState = cc.Quat.clone(cc.Quat.IDENTITY);this._DeviceMotionFirstInstance = this._OnDeviceMotionFirst.bind(this);this._DeviceMotionEventInstance = this._OnDeviceMotionEvent.bind(this);},
});

然后返回 Cocos Creator, 新建一个空场景, 可以写个简易测试看看效果(比较简单就不放代码了). 运行请求传感器数据的页面需要服务器提供 HTTPS 连接, 如果是在 Windows 系统上, 可以利用 Windows 专业版自带的 IIS 在内网开一个 HTTPS 站点, 如果没有 IIS 可以下载安装免费的 IIS Express. 找来 IIS 是因为它自带一个给开发者测试用的SSL证书, 避免了搞证书问题头疼. 最后, 找个传感器齐全的中高档手机测试, 成功收到所有运动数据:

Cocos Creator 获得手机陀螺仪(Gyrometer)数据相关推荐

  1. cocos creator 实现手机震动的效果(最全说明)

    cocos creator 实现手机震动的效果(最全说明) 之前在做creator时,需要打包调用安卓震动,看了许多其他博客的方法,虽然意思说明了但是东西不全,因此也花了不少时间.然后自己总结了套最全 ...

  2. cocosjs微信头像本地服务器,Cocos creator游戏接入微信开放数据域,实现好友排行榜功能...

    微信小游戏加入排行榜功能,可以增加游戏微信好友参与,增加分数竞争氛围,官方的说明文档不怎么详细,也有坑.本文实战以cocos creator v2.2版本为例,供大家参考. 结果显示: 前提: 1.创 ...

  3. cocos creator 实现手机震动的效果

    目前需要wx, android,ios三个平台发布 android 平台下: 将项目打包发布形成build文件夹,用Android studio 打开如下目录:***\build\jsb-link\f ...

  4. 手机陀螺仪的注册监听事件

    最近在公司做了一个VR视频的遥控器,目的在于利用手机充当遥控器角色,控制电视端VR视频的播放,我主要开发体感功能,也就是调用手机陀螺仪的数据,以下为具体操作: 在画面中增加一个体感功能的开关,绑定点击 ...

  5. Cocos Creator 从下载图片到手机本地相册

    在游戏中难免会有使用保存图片到本地的功能 比如二维码等 但是creator的方法是保存在他的游戏目录里 如果手机没有root是无法查看的 这个方法就是 把图片下载到游戏目录 然后在通过目录查找图片 然 ...

  6. Cocos Creator 重力球游戏制作教程

    本文首发于:一枚小工(caizj_cn) Cocos 经授权转载,感谢作者创作 游戏玩法 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏结 ...

  7. 光影的魔法!Cocos Creator 实现屏幕空间的环境光遮蔽(SSAO)

    引言: 本文作者 alpha 从事游戏前端开发已经5年,毕业后他先是入职了腾讯无线大连研发中心,而后开启了北漂生涯,在北京的这3年一直都在使用 Cocos Creator,对前端业务,包体.内存优化有 ...

  8. 022 - cocos creator 3D

    #cocos creator 3D warning 报错:"project:///assets/main.js,将https中的export注视掉重试一遍 知识点 scrollview组件添 ...

  9. Cocos Creator:高效率内容生产,引领全平台制霸!

    「深圳站」沙龙已经圆满落下帷幕,很高兴和大家因为同一个理念:「让游戏开发更简单」而得缘相聚于此. 在此,我要代表 Cocos 特别感谢不远万里专程赶来参会的朋友:感谢探娱和独角兽两位协办方的赞助和大力 ...

最新文章

  1. Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现
  2. Linux下编译opencv
  3. FORTRAN学习记录(持续更新)
  4. butterknife 插件_知道这个插件,能让你的项目里少写1000行代码
  5. 【dlib opencv - detector landmark】 ubuntu上针对dlib-hog和opencv haar人脸检测与landmar-68在不同平台上运行时间实验结果汇总
  6. Win7+VMware10.0+CentOS 6.4+Tomcat,Win7访问不了CentOS6.4上的Tomcat
  7. 一家典型的云原生企业,如何在创业早期数次“弯道超车”?
  8. 区块链100讲:ERC20 中文版
  9. Python项目实践:天天向上的力量
  10. 数组操作--微信小程序学习教程
  11. 《为iPad而设计:打造畅销App》——用iPad发布报纸和杂志
  12. PyKDL---正运动学和逆运动学
  13. QtDesigner中的styleSheet
  14. dota2自定义地图服务器,RPG DOTA2 自定义地图制作指南——构建模型
  15. 关于gis中坐标系:WGS84,EPSG4326,EPSG3857,墨卡托。EPSG:4490
  16. Tanzu 学习系列之TKGm for vSphere 快速部署
  17. ubuntu20.04下opencv4.4编译、给图片加中文标注及tensorflow的问题记录、ubuntu下使用cv::text::OCRTesseract模块字符识别
  18. Key was created with errors:报错
  19. #读书笔记# 《人类简史》Chapter7
  20. 百度云安装mysql_mysql5.7 安装版本配置教程+百度云资源分享

热门文章

  1. 《军师联盟》把三国带跑偏 是时候温习下这五部剧了
  2. linux下删除以-开头的文件
  3. 2021牛年大吉,红包敬上
  4. Centos7 网卡做 bond 以及 team
  5. 概率论学习二、样本空间与事件
  6. mysql prefix_mysql改变innodb_large_prefix
  7. 完美二叉树、满二叉树、完全二叉树
  8. Verilog中 reg和wire 用法 以及always和assign的区别
  9. SSO单点登录解决方案——Filter方式
  10. JSTL标签库动态生成表格