ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

three.js cannon.js物理引擎地形生成器和使用指针锁定控件

2021-01-25 09:36:16  阅读:176  来源: 互联网

标签:控件 CANNON 生成器 controls js new world 0.5


今天郭先生说一说使用cannon.js物理引擎绘制地形和使用指针锁定控件。效果如下图。线案例请点击博客原文

这里面的生成地形的插件和指针锁定控件也是cannon.js的作者schteppe封装的,当然也可以自己写一个这样的小插件。好的我们先说说这两个插件的使用方法,然后结合一个小案例应该他们。

1. 地形生成插件

相信一些同学玩过我的世界这款游戏,它的地形就是由好多个规格相同的正方体组成。就像下面这样

那么VoxelLandscape.js能够很好的实现这样的地形生成,我们先来看看生成地形构造函数所需要的参数

voxels = new VoxelLandscape(world,nx,ny,nz,sx,sy,sz);
  • world —cannon.js中的CANNON.World()实例
  • nx — x方向上地形的块数
  • ny — y方向上地形的块数
  • nz — z方向上地形的块数
  • sx — 小矩形x方向上halfSize
  • sy — 小矩形y方向上halfSize
  • sz — 小矩形z方向上halfSize

这样就能构建出一个地形,由于我们还没有进行其他操作,它看起来就是一整块矩形,但是它为我们提供了很多方法,比如说setFilled方法(其他的方法可以自行测试),这个方法可以设置哪些矩形块需要填充,哪些不需要填充,使用方法如下

voxels.setFilled(i,j,k),filled);
  • i — x方向的第i个
  • j — y方向的第j个
  • k — z方向的第k个
  • filled — 是否需要填充

i,j,k可以确定具体是那一块,filled是一个布尔值,true表示填充,false表示不填充,下面是随机挖空5000次方块的例子。

voxels = new VoxelLandscape(world,58,58,58,0.5,0.5,0.5);
for(let i=0; i<5000; i++) {
    var filled = false;
    voxels.setFilled(Math.floor(Math.random() * 58),Math.floor(Math.random() * 8),Math.floor(Math.random() * 58),filled);
}

这样就可以随心所欲的设置地形了。

2. 指针锁定控件

对于指针锁定控件,three.js已经为我们提供了PointerLockControls方法,它是基于Pointer Lock API实现的,主要用到的方法有请求指针锁定requestPointerLock()、退出指针锁定exitPointerLock()等,下面来说一说这个用于cannon.js的PointerLockControls,他和three的版本又些许区别,看下面代码。

controls = new PointerLockControls( camera , sphereBody );//第一个参数是camera,第二个参数是刚体对象
scene.add( controls.getObject() );//将控制器加入到场景
if(controls) {//如果controls初始化成功
    if(document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element) {//如果element处于锁定中,则打开controls
        controls.enabled = true;//因为默认enabled为false,所以一般都需要手动打开
        this.$refs.info.style.display = 'none';
    } else {
        controls.enabled = false;
        this.$refs.info.style.display = 'inline-block';
    }
}
controls.update(clock.getDelta() * 1000);//在每次更新物理世界的时候调用controls.update()方法

指针锁定控件使用一个刚体作为camera的载体,可以往camera的移动看起来更加生动(拥有物理特性)。

3. 案例

下面直接上主要案例代码

initCannon() {
    world = new CANNON.World();
    world.quatNormalizeSkip = 0;
    world.quatNormalizeFast = false;
    world.gravity.set(0, -9.8, 0);
    world.broadphase = new CANNON.NaiveBroadphase();
    world.solver.iterations = 10;

    physicsMaterial = new CANNON.Material("slipperyMaterial");
    var physicsContactMaterial = new CANNON.ContactMaterial(physicsMaterial, physicsMaterial, {friction: 0.3, restitution: 0.5});//规定相同的physicsMaterial材质之间的发生接触时的物理参数。
    world.addContactMaterial(physicsContactMaterial);

    var nx = 58, ny = 8, nz = 58, sx = 0.5, sy = 0.5, sz = 0.5;

    const radius = 1.6;

    sphereBody = new CANNON.Body({ //使用球形刚体作为相机载体,让相机拥有质量属性
        mass: 5,
        position: new CANNON.Vec3(nx*sx*0.5,ny*sy+radius*2,nz*sz*0.5),
        shape: new CANNON.Sphere(radius),
        material: physicsMaterial
    });
    sphereBody.linearDamping = 0.9;
    world.addBody(sphereBody);

    groundBody = new CANNON.Body({//地面
        mass: 0,
        position: new CANNON.Vec3(0, -0.1, 0),
        shape: new CANNON.Box(new CANNON.Vec3(200, 0.1, 200)),
        material: physicsMaterial
    });
    world.addBody(groundBody);

    voxels = new VoxelLandscape(world,nx,ny,nz,sx,sy,sz);
    
    for(var i=0; i<nx; i++){
        for(var j=0; j<ny; j++){
            for(var k=0; k<nz; k++){
                var filled = true;
                if(Math.abs(Math.sin(i / 6)) < j / 5) {
                    filled = false;
                }
                if(Math.abs(Math.sin(k / 6)) < j / 5) {
                    filled = false;
                }

                voxels.setFilled(i,j,k,filled);

            }
        }
    }
    voxels.update();
},

for(var i=0; i<voxels.boxes.length; i++){//创建地形相应的网格,该数据存储在voxels.boxes数组中
    var b = voxels.boxes[i];
    var voxelGeometry = new THREE.BoxBufferGeometry( voxels.sx*b.nx, voxels.sy*b.ny, voxels.sz*b.nz );
    var voxelMesh = new THREE.Mesh( voxelGeometry, new THREE.MeshPhysicalMaterial({color: 0x666666}) );
    voxelMesh.castShadow = true;
    voxelMesh.receiveShadow = true;
    scene.add( voxelMesh );
    boxMeshes.push( voxelMesh );
}

以上就是地形生成器和使用指针锁定控件的使用方法

 

转载请注明地址:郭先生的博客

标签:控件,CANNON,生成器,controls,js,new,world,0.5
来源: https://www.cnblogs.com/vadim-web/p/14323563.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有