首页 > 解决方案 > 如何检测 X 和 Z 位置是否与某个网格相交(不使用鼠标)?- 三.js

问题描述

问题背景

我正在开发一款混合了欧陆风云 4 和帝国时代 3 的游戏。该游戏是用JavaScript制作的,并使用Three.js (r109)库。截至目前,我已经用树木和反射水随机生成了低多边形地形。一开始我希望游戏生成一个海军,以一艘大帆船为代表(在下面的屏幕截图中)。我想这样做,所以当它被调用产卵时,它会在水的范围内选择一个随机位置。水网格由跨越地图大小的半透明平面THREE.Reflector表示 -其下方有一个对象。地形也是一个平面,但已使用SimplexNoise高度图进行了更改。

在此处输入图像描述

问题

如何检测xz位置是否与水网格而不是地形网格相交? THREE.Raycaster似乎对我想做的事情很有用,但我不知道是否有更好的解决方案。如果使用 THREE.Raycaster是最好的选择,我将如何为此目的实施它?THREE.Raycaster我应该为我正在做的每一个对象创建一个个体吗?请记住,我不是用鼠标放置这个对象,我想用一种如上所述检查位置的方法来放置它。

标签: javascriptthree.js

解决方案


在对代码一无所知的情况下很难给出具体的建议,但听起来你需要做的就是为你的有效水面创建一个碰撞列表,然后在你想要生成一些东西时检查它。

一个非常简单的 jsfiddle 在这里。它创建一个“陆地”网格(绿色)和一个“水”网格(蓝色),将“水”网格添加到一个名为collisionList的变量中。然后它调用一个spawn函数来获取两个表面的对角坐标。该函数使用 raycaster 来检查坐标是否在“水”网格上,如果是,则生成一个红色立方体。

这是代码:

window.onload = function() {
    var camera = null, land = null, water = null, renderer = null, lights;
    var collisionList;
    var d, n, scene = null, animID;

    n = document.getElementById('canvas');

    function load() {
            var height = 600, width = 800;

            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(60, width/height, 1, 1000);
            camera.position.set(0, 0, -10);

            camera.lookAt(new THREE.Vector3(0, 0, 0));
            scene.add(camera);

            lights = [];
            lights[0] = new THREE.PointLight(0xffffff, 1, 0);
            lights[1] = new THREE.PointLight(0xffffff, 1, 0);
            lights[2] = new THREE.PointLight(0xffffff, 1, 0);
            lights[0].position.set(0, 200, 0);
            lights[1].position.set(100, 200, 100);
            lights[2].position.set(-100, -200, -100);
            scene.add(lights[0]);
            scene.add(lights[1]);
            scene.add(lights[2]);

            water = new THREE.Mesh(new THREE.PlaneGeometry(7, 7, 10),
                    new THREE.MeshStandardMaterial({
                            color:  0x0000ff,
                            side:   THREE.DoubleSide,
                    }));
            water.position.set(0, 0, 0);
            scene.add(water);

            land = new THREE.Mesh(new THREE.PlaneGeometry(12, 12, 10),
                    new THREE.MeshStandardMaterial({
                            color:  0x00ff00,
                            side:   THREE.DoubleSide,
                    }));
            land.position.set(0, 0, 1);
            scene.add(land);

            renderer = new THREE.WebGLRenderer();
            renderer.setSize(width, height);
            n.appendChild(renderer.domElement);

            collisionList = [ water ];

            for(var i = -6; i < 6; i++)
                    spawn(i);
            
            animate();
    }
    function spawn(x) {
            var dir, intersect, mesh, ray, v;

            v = new THREE.Vector3(x, x, -1);
            dir = new THREE.Vector3(0, 0, 1);
            ray = new THREE.Raycaster(v, dir.normalize(), 0, 100);
            intersect = ray.intersectObjects(collisionList);
            if(intersect.length <= 0)
                    return;
            mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1, 1, 1, 1),
                    new THREE.MeshStandardMaterial({ color: 0xff0000 }));
            mesh.position.set(x, x, 0);
            scene.add(mesh);
    }
    function animate() {
            if(!scene) return;
            animID = requestAnimationFrame(animate);
            render();
            update();
    }
    function render() {
            if(!scene || !camera || !renderer) return;
            renderer.render(scene, camera);
    }
    function update() {
            if(!scene || !camera) return;
    }
    
    load();

至于这是否是一个聪明的方法,这真的取决于你游戏其余部分的设计。

如果您的世界是 procgen,那么首先生成生成点(以及世界的任何其他“功能”部分)并使用它来生成地理而不是相反的方式可能会更有效/更不容易出错。


推荐阅读