事件系统

Crafty 使用组件进行通信。

基本思想是将函数绑定到命名事件。当事件被触发时,函数会被直接调用。这里有一个简单的例子:

// Create a red square
var square = Crafty.e("2D, Canvas, Color")
        .attr({x:10,y:10, w:30, h:30})
        .color("blue");

// When a "Blush" event is triggered, turn pink
square.bind("Blush", function() {
    // the function will be called in the context of the entity
    this.color("pink")
});

// Trigger the event, causing the square to turn pink
square.trigger("Blush");

在上边,我们为实体绑定了一个事件,然后立刻触发它。更典型的情况是,我们在游戏逻辑的其他地方来触发它。您可以将多个函数绑定到同一事件,但一般不应依赖它们按特定顺序执行。

每个实体都有一些与事件有关的方法,这在文档 Crafty Core. 有详细的介绍。

传递数据

很多事件都会传递数据给绑定的函数。让我们修改上边的代码来定义一个更通用的 "ChangeColor" 事件:

square.bind("ChangeColor", function(color) {
    this.color(color);
});

square.trigger("ChangeColor", "pink"); // Turn pink

当你触发事件时,第二个参数可以传递一个值。这不会对你造成限制,因为你也可以传递一个对象 —— 例如,你想 "ChangeColor" 使用 RGB 值来代替颜色名称:

// Assume that color is an object
square.bind("ChangeColor", function(color) {
    this.color(color.r, color,g, color.b);
})

// Specify the RGB values corresponding to pink
square.trigger("ChangeColor", {r:255, g:192, b:203});

解绑事件

要解绑一个事件,你需要绑定函数的引用,所以它不能是匿名的。修改我们之前的例子:

var turnPink = function() { 
    this.color("pink");
}

// Bind the function to an event
square.bind("Blush", turnPink);

// Immediately unbind it!
square.unbind("Blush", turnPink);

有时候你希望函数只被触发一次,这时,你可以使用 .one() 来代替 .bind() 进行绑定:

// Use the .one() method instead of .bind()
square.one("JumpRight", function() {
    // Move 10 px to the right
    this.x += 100;
});

// If we trigger the event twice, the bound function will be called only the first time
square.trigger("JumpRight");
square.trigger("JumpRight");

内置事件

很多 Crafty 内置的组件都会触发事件,大部分有用的事件都可以在 API 文档中找到。例如, 2D 组件 在位置改变的时候会触发 "Move" 事件 , 并且该事件会传递一个表示旧位置的对象。

// Bind a function to the "Move" event
// It will log the initial and new x position anytime the entity moves
square.bind("Move", function(oldPosition) {
    console.log(oldPosition._x, this.x);
});

square.x = 100; // Will print "10, 100"

在 Crafty 的 API 文档中,内置事件都是高亮的绿色。

全局事件

到目前为止,我们讨论的所有事件都是针对某个特定实体的。但事件也可以在全局触发 —— 将在所有实体上触发。

// Define two entities at x=5 and x=10
var varrick = Crafty.e("2D").attr({x:5});
var xhuli = Crafty.e("2D").attr({x:10});

// Bind to an event called "Thing"
varrick.bind("Thing", function() { this.x += 20; });
xhuli.bind("Thing", function() { this.x += 10; });

// Do the thing!
// varrick and xhuli will *both* move to the right
Crafty.trigger("Thing");

// You can still trigger the same events directly on an entity
xhuli.trigger("Thing");

你也可以直接在 Crafty 对象上绑定事件:

Crafty.bind("Thing", function() {
    console.log("Crafty does the thing.")
});

在全局绑定的函数中,上下文 this 为全局的 Crafty 对象(this === Crafty)。

和你想的一样,Crafty.unbind()Crafty.one() 也是这样!

你将在 游戏循环 章节中,了解到一个非常重要的事件 "EnterFrame"。