Как определить, пересекается ли позиция X и Z с определенной сеткой (без использования мыши)? — Three.js

#javascript #three.js

Вопрос:

Предыстория вопроса

Я работаю над игрой, представляющей собой смесь Europa Universalis 4 и Age of Empires 3. Игра сделана на JavaScript и использует Three.js (r109) библиотека. На данный момент я создал случайно сгенерированную низкополигональную местность с деревьями и отражающей водой. В начале я хочу, чтобы в игре появился флот, представленный галеоном (на скриншоте ниже). Я хочу сделать так, чтобы, когда его вызовут на нерест, он выбрал случайное место в пределах воды. Водная сетка представлена полупрозрачной плоскостью размером с карту-с THREE.Reflector объектом под ней. Рельеф также является плоскостью, но был изменен с помощью карты высоты симплексного шума.

введите описание изображения здесь

вопрос

Как определить, пересекается ли позиция x и z с сеткой воды, а не с сеткой местности? THREE.Raycaster кажется, это полезно для того, что я пытаюсь сделать, но я не хочу знать, есть ли лучшее решение. Если использование THREE.Raycaster является лучшим вариантом, как бы я реализовал его для этой цели? Должен ли я создавать индивидуальность THREE.Raycaster для каждого объекта, с которым я это делаю? Имейте в виду, что я не размещаю этот объект с помощью мыши, я хочу разместить его с помощью метода, который проверяет положение, как указано выше.

Ответ №1:

Трудно дать конкретный совет, ничего не зная о вашем коде, но похоже, что все, что вам нужно сделать, это создать список столкновений для ваших допустимых водных поверхностей, а затем проверить это, когда вы захотите что-то создать.

Здесь находится очень простой jsfiddle. Он создает сетку «земля» (зеленая) и сетку «вода» (синяя), добавляет сетку «вода» в переменную под названием collisionList. Затем он вызывает функцию порождения для координат по диагонали на обеих поверхностях. Функция использует 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, то может быть более эффективным/менее подверженным ошибкам сначала генерировать точки появления (и любые другие «функциональные» части мира) и использовать их для создания географии, а не наоборот.

Комментарии:

1. Я заставил элементы вашей скрипки работать для моей игры. Идеальное решение для того, о чем я просил. Извините, что не дал свой код, я просто не думал, что это будет полезно из-за того, что я прошу быть довольно общим. Но все же вы дали мне ответ и решение, в которых я нуждался.