‘’vr‘’全景抓鸡游戏总结

微众银行和周大福合作了一个项目‘微福贷’,用户可以通过微众银行公众号贷款分期购买周大福产品~~配合运营人员,出了一个vr全景抓小鸡的活动。拿起你的手机,扫起来。分数最高可以获得价值1288的金吊坠一枚。作为差不多两周开发的h5,应该有很多不足,大家体谅~·

输入图片说明

![输入图片说明]

输入图片说明

##1.全景构建

2016可以说是全景h5大爆发,我也做了两个。为了自身(捂)积累(脸),我采用了两种不同的方式实现全景的构建。

  • div+css+js,这个方案主要是要理解css3d和transform。这里我会写一篇文章贴出来,连接后面补。理解原理之后,推荐使用https://github.com/shrekshrek/css3d-engine 这个工具。
  • threejs,threejs是webgl的一个库。webgl是一个通过canvas标签渲染2d、3d交互图形的JavaScript api。虽然浏览器对webgl的支持不是很令人满意,但是如今我们的h5其实主要是在微信里面打开的,而微信内置浏览器的支持是十分友好的。分别见连接:各家浏览器对WEBGL支持情况微信内置浏览器对WEBGL的支持情况因为webgl有硬件加速,因此在配置不是那么好的安卓机上体验比前一种方案好。这里简单介绍下threejs构建全景的方法。

在开始之前,先看一张图片,对threejs有一个宏观了解 输入图片说明

###1.1scene 容器,所有的物体都放置在舞台scene中,当你创建完一个物体,都需要通过 scene.add(object);添加至舞台。 ###1.2camera camera就是我们的眼睛,camera的所见就是我们的所见。在threejs中camera分为透视相机(PerspectiveCamera)和正投影相机(OrthographicCamera)。透视相机符合我们人眼观察东西的规律,即近大远小;而正投影相机则是不管远近,大小一样。

cam1 = new THREE.PerspectiveCamera( fov, aspect, near, far );
cam2 = new THREE.OrthographicCamera( left, right, top, bottom, near, far );

我们肯定使用的是正投影相机,这里简单介绍一下参数的含义。

  • fov:视角大小,视角越大,所能看见的范围就越大,物体就显得越小;
  • aspect:视野的宽高比,一般取window.innerWidth / window.innerHeight
  • near:相机能看见的最近的距离
  • far:相机能看见的最远的距离 下面是我这个项目中取的值
 var camera = new THREE.PerspectiveCamera(140, window.innerWidth / window.innerHeight, 100, 650);

###1.3light 场景中是需要light才能够看见,否则就是黑色的,light的种类很多,不同材质对不同光也是不同的效果,这里就不深入了。我采用的PointLight,这种光是一种单点光,照射所有的方向,而且,如果我们不显式设置的话,这个光的光照强度不会随着距离的变化而变化。

 //light
    var light = new THREE.PointLight('#ffffff');
    light.intensity=1.15;
    light.position.set(0, 0, 0);
    scene.add(light);

你可以改变一下光的颜色和强度感受一下~·

###1.4mesh 在threejs中,mesh是由geometry(几何体)和material(材质)构成的。通常用作全景的mesh是圆柱、立方体、球体。我做过的两个h5,一支是立方体(因为场景是超市购物,所以选择立方体),一支是圆柱体。如果你不是特别需要使用立方体,推荐你使用圆柱。因为圆柱体对设计师十分友好。对于立方体,设计师处理转角特别麻烦,见下图:

![输入图片说明

输入图片说明

 var cylinder = new THREE.CylinderGeometry(637,637,1206,24);
 var aFaces = cylinder.faces.length;
    for(var i=0;i<aFaces;i++) {
        if(i < 48){
            //侧面
            cylinder.faces[i].materialIndex = 1;
        }else if(i > 47 && i < 72){
            //上面
            cylinder.faces[i].materialIndex = 0;
        }else{
            cylinder.faces[i].materialIndex = 2;
        }
    }
 scene.add(cylinderMesh);

因为圆柱的侧面是贴图,而上下面是不同的颜色,因此我们要分开处理。

##2.转动场景 因为相机就是相当于我们的眼睛,所以要做的就是转动相机。因为支持手指滑动和陀螺仪,所以应该给陀螺仪加个开关,在手指转动场景时,屏蔽掉陀螺仪。

  //陀螺仪
    var speedX= 0,speedY= 0,preX= 0,preY= 0,curX= 0,curY=0;
    var o = new Orienter();
    o.handler = function (obj) {  //水平角度 obj.lon 垂直角度 obj.lat
        curX=obj.lon;
        curY=obj.lat;
        speedX=-(curX-preX);
        //speedY=(curY-preY)*0.2;
        speedY=0;
        preX=curX;
        preY=curY;
        if (speedX > 180)
            speedX -= 360;
        if (speedX < -180)
            speedX += 360;
        if(!manualControl&&isBegin2){
            latitude+=speedY;
            longitude+=speedX;
        }
    };
    o.init();
//手指滑动
 function onDocumentTouchMove(event){
        event.preventDefault();
        var temSpeedX=(savedX - event.touches[0].clientX) * 0.1;
        if(manualControl){
            isMove=true;
            longitude = temSpeedX + savedLongitude;
            latitude = (event.touches[0].clientY - savedY) * 0.1 + savedLatitude;
        }
    }
 //限定上下角度
 camera.target.x = 600 * Math.cos(THREE.Math.degToRad(longitude+270));
 //camera.target.y = 600 * Math.cos(THREE.Math.degToRad(90 - latitude));
 camera.target.y = 0;
 camera.target.z = 600 * Math.sin(THREE.Math.degToRad(longitude+270));
 camera.lookAt(camera.target);

产品认为不需要上下转动,因此,我将 camera.target.y设置为0;

_注意:_在给document绑定的touch事件中,一定要使用‘ event.preventDefault();’,因为在ios下面,滑动默认是滚动页面,如果不禁止掉,转动场景就不成功。

##3.实时定位 本来还做了一个点:只有离周大福实体店1km范围内,才会出现一种分值很高的鸡。后面因为只有部分周大福门店支持这个活动,于是被砍掉了。 ###3.1门店经纬度信息 业务会提供一个excel表给我们,里面有周大福180家(只有这180家支持这个活动)门店的具体位置,我们可以通过基于node的一个工具工具连接来操作excel表,得到一个json对象。然后调用百度API得到经纬度。百度地理位置转经纬度API ###3.2坐标转换 因为我们国家的规定,国内的地图信息出版物是不能直接输出标准的经纬度信息的,必须经过转换,于是就有了以下几种坐标

  • 地球坐标:国际标准
  • 火星坐标:国内标准 但是百度坐标了,在火星坐标的基础上再次进行了转化,形成了百度坐标。但是我们的html5获取到的经纬度是地球坐标,因此我们需要将百度坐标进行转换。推荐基于node的工具各种坐标相互转换
var bd09togcj02=coordtransform.bd09togcj02(x,y);//百度坐标到火星坐标
 var gcj02towgs84=coordtransform.gcj02towgs84(bd09togcj02);//火星坐标到地球坐标

###3.3获取用户坐标 需要用到地理位置api,使用这类api需要获得用户允许,你可以先弹窗提示用户为什么要同意允许定位,然后再调用这个方法。

navigator.geolocation.getCurrentPosition(function(position) {
  do_something(position.coords.latitude, position.coords.longitude);
});

###3.4确定范围 之所以做地理位置这个点,就是为了促使用户去门店,说不准就买买买了呢?O(∩_∩)O哈哈~所以我们的范围划分的不是很严格,不是严格的以1公里为半径的圆,而是经纬度差都在1公里以内的矩形。实际操作时,可以先按照纬度从小到大排序,然后利用二分法查找出符合的点。

**注意:**你不能查找到符合的点就return掉了,必须把所有符合的点都找出来。毕竟纬度符合,经度不符合的点还是很多的。

经过纬度过滤得到的就是一些很少的点了,还是同样的操作,最终得到符合的点。

##4.下雪的粒子动画 我很喜欢这个场景配上下雪的感觉,满满的少女心~~在threejs中,它有提供一个粒子系统,使用这个粒子系统可以提高性能。整个雪景,其实就是一个粒子动画。

var particles = new THREE.Geometry;
    for (var p = 0; p <600; p++) {
        var particle = new THREE.Vector3(Math.random() * 500 - 250, Math.random() * 1000+10,
            Math.random() * 500 - 250);
        particles.vertices.push(particle);
    }
    var particleTexture = THREE.ImageUtils.loadTexture('images/snowflake.png');
    var particleMaterial = new THREE.ParticleBasicMaterial({ map: particleTexture, transparent: true, size: 5,opacity:1 });
    var particleSystem = new THREE.ParticleSystem(particles, particleMaterial);
    scene.add(particleSystem);

##5.转动的摩天轮 又是一个少女心满满的东西,这里并没有什么难点,但是这里推荐大家一个工具,dat.gui.js,通过这个库我们可以图形化调整摩天轮各个部分的位置,以及旋转速度。

//plane2,摩天轮ferris-wheel.png
    var planeGeo2=new THREE.PlaneGeometry(400,400);
    var planeTexture2 = THREE.ImageUtils.loadTexture('images/ferris-wheel.png');
    var planeMaterial2=new THREE.MeshLambertMaterial({ map: planeTexture2,transparent:true,opacity:1});
    var planeMesh2=new THREE.Mesh(planeGeo2,planeMaterial2);
    planeMesh2.position.set(-475,150,-304);
    planeMesh2.rotation.y=0.9;
    planeMesh2.material.side = THREE.DoubleSide;
    scene.add(planeMesh2);
    //plane3,摩天轮底座
    var planeGeo3=new THREE.PlaneGeometry(256,256);
    var planeTexture3 = THREE.ImageUtils.loadTexture('images/wheel-font.png');
    var planeMaterial3=new THREE.MeshLambertMaterial({ map: planeTexture3,transparent:true,opacity:1});
    var planeMesh3=new THREE.Mesh(planeGeo3,planeMaterial3);
    planeMesh3.position.set(-447,42,-284);
    planeMesh3.rotation.y=0.9;
    planeMesh3.material.side = THREE.DoubleSide;
    scene.add(planeMesh3);

在requestAnimationFrame中不断增加旋转角度即可。

##6.小鸡的动画 ###6.1小鸡自身的帧动画 小鸡的material是用canvas做的帧动画,提供大家一张图,大家动手试试看。 点击之后点击之前

**注意:**这里有个提高性能的技巧,使用离屏canvas绘制,我是动态创建一个canvas标签,但并没有将它们append到body上。

我们的场景整个是按照每秒40帧的频率刷新的,但是我小鸡的帧动画并不需要那么快,因此我给了个变量,每次加0.1,为整时刷新,canvas的具体控制见以下代码。

SpriteSheetPainter.prototype = {
    advance: function () {
        if (this.cellIndex >=this.cells.length-1) {
            if(this.loop){
                this.cellIndex = 0;
                this.temIndex=0;
            }else{
                this.cellIndex = this.cells.length-1;
                this.temIndex=0;
            }
        }
        else {
            this.temIndex+=0.1;
            this.cellIndex=Math.floor(this.temIndex);
            //this.cellIndex++;
        }
    },
    paint: function () {
        var cell = this.cells[this.cellIndex];
        //console.log(this.cellIndex);
        this.context.clearRect(0,0,this.w,this.h);
        this.context.drawImage(this.img, cell.left, cell.top, cell.width, cell.height, 0,0, cell.width, cell.height);
    }
};

###6.2小鸡在整个场景中的运动轨迹 我利用sin、cos、sin*cos等曲线作为小鸡的运动曲线。 **注意:**要想你的canvas实时更新,一定要加上 object.material.map.needsUpdate = true;

###7.安全限制 以为这次的奖品还是蛮诱人的,我们前端也做了一些措施:rsa加密,提交随机码,每次点击的坐标和时间戳等。 **注意:**RSA加密之后的密文长度会有很小很小的几率不等于秘钥的长度,因此,我们会再做两次判断,基本就可以避免这种情况了。

if(encryptedGrade.length<512){
        encryptedGrade=_rsa.encrypt(totalGrade+'-'+rdCode);
    }
    if(encryptedGrade.length<512){
        encryptedGrade=_rsa.encrypt(totalGrade+'-'+rdCode);
    }

###8.微信中的一个坑 如果用户的分数大于800分,就可以去周大福的页面领取一张代金券,在ios下回来之后大概2s内发到后台的请求它都会使用缓存。如果你的请求必须重新请求,加上时间戳即可

转载于:https://my.oschina.net/xiaoweibaer/blog/826603

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值