Рамка: не допускать перекрытия двух объектов.

После демоверсии Minecraft. Как я могу сделать так, чтобы блоки не появлялись в одном месте? Это сценарий, который порождает коробки.

Есть два подхода, которые я могу придумать:

  1. Создайте список отслеживания координат, который я установил для поля, и не создавайте его, если точка пересечения совпадает (или близка к порогу).
  2. Проверьте, соответствует ли сетка ограничивающему прямоугольнику (используя Box3 Threejs, который я не знаю, как использовать).

Есть идеи о том, как лучше подойти к этому?

1 ответ

Решение

Это мой ответ на #2: я создал массив. Этот массив будет содержать точки evt.detail.intersection.point. Перед вставкой нового объекта я применяю Пифагор (точки x и z) и сравниваю его с порогом. Только если он выше порога, я позволяю ему продолжать и сохраняю новые точки в нем.

Весь код ниже, с комментариями:

Я использовал здесь TypeScript, я не буду его включать, чтобы он охватывал более широкую аудиторию.

Я обернул компонент intersection-spawn классом ES2015 только для разделения кода. Я не знаю родного способа создания A-Frame через ES2015.

Это основной класс "intersection-spawn.js"

export default class IntersectionSpawn {
    constructor(lamp) {
        //The array that will track the position. 
        this.positionHistory = new Array();
        //The spacing which it will allow to span another light.
        this.minSpacing = 2;
        //Captures the class' *this* so it can be used in the 
        //Event Listener.
        const _this = this;
        //Dependency Injection. Injects the lamp class that manages
        //the lamp creation. 
        this.lamp = lamp;

        AFRAME.registerComponent('intersection-spawn', {
            schema: {
                default: '',
                parse: AFRAME.utils.styleParser.parse
            },

            init: function () {
                //This data comes from the HTML's <a-entity> attribute
                const data = this.data;
                //References the current element. This comes from A-Frame.
                const el = this.el;
                //Reducing the code a little bit.
                //This will create an event listener and pass it to the
                //intersection method.
                el.addEventListener(data.event, evt => {
                    _this.intersection(evt, el, data)
                });
            }
        });
    }

    //This takes care of create the element and insert it. 
    intersection(evt, el, data) {

        //Just a safeguard. If the event data doesn't contain 
        //the intersection property, then I can't do anything. 
        if (evt.detail.hasOwnProperty("intersection") === false)
            return;
        //Define a position object to keep hold of everything.
        //Note that in here I'm just selecting points x and z
        //because in my app, those are the only ones which interests
        //me. "y" is also available by using vt.detail.intersection.point.y
        let pos = {
            x: evt.detail.intersection.point.x,
            z: evt.detail.intersection.point.z
        };

        //If true then it continues, and adds the element. 
        //Otherwise exit. 
        if (!this.canAddToGrid(pos))
            return;

        //Creates a new lamp to be inserted. 
        const elem = this.lamp.generate(data, pos);
        el.sceneEl.appendChild(elem);
        this.appendToHistory(pos);
    }
    //Adds to the current history to be tracked. 
    appendToHistory(pos) {
        this.positionHistory.push(pos);
    }

    /**
     * Checks whether it's posisble to add to the grid or not.
     * This will check if the distance of the current insertion point
     * is equal or smaller to the distance to any of the cylinders. 
     * If that's the case, it will return false. Otherwise it will return
     * true.
     * The position of the current object to be inserted.
     * @param pos 
     */
    canAddToGrid(pos) {
        for (let position of this.positionHistory) {
            if (this.calcDistance(pos.x, pos.z, position.x, position.z) <= this.minSpacing) {
                return false;
            }
        }
        return true;
    }

    /**
     * Calculates the distance from the center of the lamp to the center 
     * of the insertion points.
     * 
     * @param x1 Position x of the object to be inserted
     * @param z1 Position z of the object to be inserted
     * @param x2 Position x of the object inside the array
     * @param z2 Position z of the object inside the array
     */
    calcDistance(x1, z1, x2, z2) {
        return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((z2 - z1), 2));
    }

}

Это lamp.js (тот, который создает объект лампы) и добавляется в класс intersectionSpawn:

export default class Lamp {
    constructor() {

    }
    /**
     * Creates the Lamp. Right now it's a cylinder. 
     * @param pos The positions you want the lamp to be in.
     */
    create(pos) {
        let elem = (document.createElement("a-cylinder"));
        elem.setAttribute('width', "1");
        elem.setAttribute('height', "4");
        elem.setAttribute('depth', "1");
        elem.setAttribute('position', `${pos.x} 0 ${pos.z}`);
        return elem;
    }

    /**
     * This works like a decorator. this was originaly in the intersection-spawn.
     * I do not know a lot what it does, but it's necessary for the element to work.
     * @param elem The generated element from the create(pos) method.
     * @param data Comes from A-Frame's data. 
     */
    AddAframeUtils(elem, data) {
        Object.keys(data).forEach(name => {
            if (name === 'event') { return; }
            AFRAME.utils.entity.setComponentProperty(elem, name, data[name]);
        });

        return elem;

    }

    /**
     * The public method which generates a fully functional element. 
     * @param data This comes from A-Frame's data.
     * @param position The position in which I want to create the element.
     */
    generate(data, position) {
        return this.AddAframeUtils(this.create(position), data);
    }
}

script.js, который включает оба класса:

import Lamp from './js/lamp/lamp';
import IntersectionSpawn from './js/components/intersection-spawn';

new IntersectionSpawn(new Lamp());

А теперь index.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
    <script src="https://rawgit.com/mayognaise/aframe-mouse-cursor-component/master/dist/aframe-mouse-cursor-component.min.js"></script>
    <script src="script.js"></script>
</head>

<body>
    <a-scene>
        <a-sky color="#ECECEC"></a-sky>
        <a-camera>
            <!-- We include the intersection-spawn in here:-->
            <a-cursor intersection-spawn="event: click;"></a-cursor>
        </a-camera>
    </a-scene>
</body>

</html>
Другие вопросы по тегам