为什么一个事件没有被另一个元素识别?

Why is an event not being recognized by another element?

我在使用 A 型框架逻辑门类型组件时遇到问题。我正在为一个 7 年级的学校项目做这个(我可能选择了一些非常高级的东西,但我几乎完成了它),但是我在这里找不到错误。

我遇到的问题是连接的组件(在本例中是一扇门,它的子门是门)似乎应该响应来自门的信号。目前,无论按钮的状态如何,门都卡在“关闭”位置,但是应该发生的是当激活的按钮(红色)满足门属性中指定的逻辑条件时,门应该发出指定的事件。门控制的门我之前测试过并且可以使用按钮,这让我认为问题出在逻辑门本身。我已经检查了所有的语法,它似乎是正确的,调试控制台也没有给出任何错误,这使得调试变得更加困难。

<script>
        AFRAME.registerComponent('logic', {
            schema: {
                type: {
                    type: 'string',
                    default: 'and'
                },

                input1: {
                    type: 'string'
                },

                input2: {
                    type: 'string'
                },

                event: {
                    type: 'string'
                }
            },

            init: function () {
                var entity = this.el;
                var scene = entity.sceneEl;
                var event = this.data.event;
                this.activeOut = false;
                this.active1 = false;
                this.active2 = false;
                var type = this.data.type;
                var input1 = this.data.input1;
                var input2 = this.data.input2;
                // Toggle each input
                entity.addEventListener(input1, function (event) {
                    if(!this.active1) {
                        this.active1 = true;
                    }
                    else {
                        this.active1 = false;
                    }
                });
                entity.addEventListener(input2, function (event) {
                    if(!this.active2) {
                        this.active2 = true;
                    }
                    else {
                        this.active2 = false;
                    }
                });
            },

            tick: function (time, timeD) {
                var entity = this.el;
                var scene = entity.sceneEl;
                var event = this.data.event;
                var type = this.data.type;
                var input1 = this.data.input1;
                var input2 = this.data.input2;
                // Detect the gate type and check for the corresponding condition
                switch (type) {
                    case 'and' :
                        if((this.active1 && this.active2) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && !(this.active1 && this.active2)) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;

                    case 'or' :
                        if((this.active1 || this.active2) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && !(this.active1 || this.active2)) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;

                    case 'xor' :
                        if(((this.active1 || this.active2) && !(this.active1 && this.active2)) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && !((this.active1 || this.active2) && !(this.active1 && this.active2))) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;

                    case 'nand' :
                        if(!(this.active1 && this.active2) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && (this.active1 && this.active2)) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;

                    case 'nor' :
                        if(!(this.active1 || this.active2) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && (this.active1 || this.active2)) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;

                    case 'xnor' :
                        if(!((this.active1 || this.active2) && !(this.active1 && this.active2)) && !this.activeOut) {
                            entity.emit(event, {}, true);
                            this.activeOut = true;
                        }
                        else if(this.activeOut && ((this.active1 || this.active2) && !(this.active1 && this.active2))) {
                            entity.emit(event, {}, true);
                            this.activeOut = false;
                        }
                        break;
                }
            }
        });
    </script>

这是 HTML 的门(包括重要的门和按钮):

<a-box
            color="blue"
            door="to: 5 3 -5; toggleEvent: open;"
            position="0 3 -5"
            width="5"
            height="6"
            depth="0.06"
        >
            <a-box
                logic="type: and; input1: button; input2: button2; event: open;"
                position="0 0 0"
                width="0.0001"
                height="0.0001"
                depth="0.0001"
            >
                <a-box
                    color="blue"
                    position="4 1 -2"
                    button="eventOn: button; eventOff: button;"
                ></a-box>

                <a-box
                    color="blue"
                    button="eventOn: button2; eventOff: button2;"
                    position="4 3 -2"
                ></a-box>
            </a-box>
        </a-box>

代码中的格式取决于它在此处的粘贴方式。

event listener functions have this set to the element on which the listener is placed:

this.active1 = false; // "this" refers to the component
entity.addEventListener(input1, function (event) {
  if(!this.active1) {
    this.active1 = true; // "this" refers to "entity"
  } else {
    this.active1 = false; // "this" refers to entity"
  }
});

所以你认为它是相同的 'variable',而实际上你正在设置 entity 的新 属性。

解决此问题的两种常见方法是:

// assing `this` to another variable, which is used in the listener
const self = this;
entity.addEventListener(input1, function (event) {
  self.active1 = false; // this is the components active1 property
})

// use an arrow function, which does not have it's own scope
entity.addEventListener(input1, event => {
  this.active1 = false; // this is the components active1 property
})

一些备注:

  • 如果您确定状态仅在单击按钮时发生变化,则无需每秒检查逻辑 60 次。侦听器可以触发检查当前门状态的功能。
  • 在尝试查找错误时尽可能简化代码。将日志放在具有 one/two 执行路径的代码中会更容易。
  • 记录、记录并再次记录您认为相关的任何内容。条件看起来不错? console.log("and")里面。不触发? console.log(this.active1, this.active2) 在条件之前。总是 falseconsole.log(this.active1) 在事件侦听器中。

<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-event-set-component@4.2.1/dist/aframe-event-set-component.min.js"></script>
<script>
    AFRAME.registerComponent('logic', {
        schema: {
            type: { type: 'string', default: 'and' },
            input1: { type: 'string' },
            input2: { type: 'string' },
            event: { type: 'string' }
        },
        init: function () {
            var entity = this.el;
            var scene = entity.sceneEl;
            var event = this.data.event;
            this.activeOut = false;
            this.active1 = false;
            this.active2 = false;
            var type = this.data.type;
            var input1 = this.data.input1;
            var input2 = this.data.input2;
            // Toggle each input
            entity.addEventListener(input1, (event) => {
                // toggle betweeen true / false
                this.active1 = !this.active1 ? true : false
                console.log(input1, "triggered. active1: ", this.active1)
                this.checkState() // check if the gate is open or closed
            });
            entity.addEventListener(input2, (event) => {
                // toggle betweeen true / false
                this.active2 = !this.active2 ? true : false
                console.log(input2, "triggered. active1: ", this.active2)
                this.checkState() // check if the gate is open or closed
            });
        },
        checkState: function () {
            var entity = this.el;
            var scene = entity.sceneEl;
            var event = this.data.event;
            var type = this.data.type;
            var input1 = this.data.input1;
            var input2 = this.data.input2;
            // Detect the gate type and check for the corresponding condition
            console.log("checkState: active1/2", this.active1, this.active2)
            switch (type) {
                case 'and':
                    if ((this.active1 && this.active2) && !this.activeOut) {
                        console.log("and fullfiled")
                        entity.emit(event, {}, true);
                        this.activeOut = true;
                    } else if (this.activeOut && !(this.active1 && this.active2)) {
                        entity.emit(event, {}, true);
                        this.activeOut = false;
                    }
                    break;
            }
        }
    });
    // set text open/closed depending on the 'open' events from the entity with the logic
    AFRAME.registerComponent("door", {
        init: function () {
            const gate = document.querySelector("[logic]")
            var toggle = false;
            gate.addEventListener("open", evt => {
                toggle = !toggle
                this.el.setAttribute("text", "value", toggle ? "open" : "closed")
            })
        }
    })
    // not sure where this came from, simple toggle between to events on click
    AFRAME.registerComponent("button", {
        schema: {
            eventOn: { type: "string" },
            eventOff: { type: "string" }
        },
        init: function () {
            var toggle = false;
            this.el.addEventListener("click", evt => {
                if (!toggle) {
                    this.el.emit(this.data.eventOn)
                    this.el.setAttribute("color", "red")
                } else {
                    this.el.emit(this.data.eventOff)
                    this.el.setAttribute("color", "blue")
                }
                toggle = !toggle
            })
        }
    })
</script>
<a-scene cursor="rayOrigin: mouse" raycaster="objects: a-box">
    <a-box logic="type: and; input1: button; input2: button2; event: open;" width="0.0001"
        height="0.0001" depth="0.0001">
        <a-box color="blue" position="1 2 -2" button="eventOn: button; eventOff: button;"></a-box>

        <a-box color="blue" button="eventOn: button2; eventOff: button2;" position="-1 2 -2"></a-box>
    </a-box>
    <a-entity door position="0.45 1.8 -0.275" text="color:black; value: closed"></a-entity>
    <a-sky color="#ECECEC"></a-sky>
    <a-entity position="0 1.6 0" camera>
</a-scene>