Alberto
Alberto

Reputation: 163

Custom events dispatch in Backbone.js

I want to write a simple JavaScript animation that makes some balls move inside a canvas. I want to detect collisions with custom events handled with Backbone.js instead of having a nested for loop that checks for collisions between each pair of balls.

var j;
for (j = 0; j < N_BALLS; j++) {
    ball_center = new Point(..., ...);
    ball_shape = new Circle(ball_center, ball_radius);
    ball_velocity = ...;
    ball_ID = j;
    balls[j] = new Ball(ball_shape, ball_velocity, ball_ID);
    _.extend(balls[j], Backbone.Events);
    balls[j].on("imhere", balls[j].event_handler);
}

function animate() {
    if (!paused) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        var j;
        for (j = 0; j < N_BALLS; j++){
            balls[j].updatePosition();
            balls[j].trigger("imhere", balls[j].shape, balls[j].ID);
        }
        for (j = 0; j < N_BALLS; j++)
           balls[j].draw(context, '#0000ff');
        window.requestNextAnimationFrame(animate);
    }
}

The event_handler is a member method of each Ball object

Ball.prototype.event_handler = function(shape, ID) {
    console.log("ball " + this.ID + " caught message from ball " + ID);
};

I would expect that sometimes a ball catches one message from another one, but this is NEVER the case.

I would like to arrange things in such a way where the event handler can:

Upvotes: 1

Views: 155

Answers (1)

Emile Bergeron
Emile Bergeron

Reputation: 17430

Backbone events

this.ID is probably undefined because Backbone .on() needs the context as the last param unless you're already binding the context to the function elsewhere manually.


You're also registering the event on the Ball itself, and triggering on the ball as well.

Events aren't global within Backbone, you need to create a global event channel yourself or use a plugin. Look for event bus, or event aggregator, etc.

A quick example could be as simple as:

var GlobalEvents = _.extend({}, Backbone.Events);

Backbone itself is a an object that extends the Backbone.Events functionality, but it's best to create a local event channel for your use-case.


Speaking of using the Backbone.Events object, you're extending each instances of a Ball when you really should be extending the Ball prototype once.

_.extend(Ball.prototype, Backbone.Events);

You should favor listenTo over on.

When destroying a ball, you could call ball.stopListening() and you would avoid memory leaks. It would also solve the context problem within the event_handler callback.

So, with a global event aggregator:

balls[j].listenTo(GlobalEvents, "imhere", balls[j].event_handler);

Backbone events are not DOM events and they're not bubbling up and down, so there's no stopPropagation or preventDefault. In the background, it's just vanilla JS for Backbone.


Collision detection

Now that we've covered the events part, let me just say that it's not the best solution for collision detection.

It's exactly the same as if you would call a isCollindingWith(ball) function on every other ball when updating the position. That's what's going on with the events, but with the loops hidden in the events implementation.

Tackling an optimized collision detection algorithm in this answer would be too broad, so I'll just link to this great article on 2D collision detection.

The interesting part is at the end, where they talk about spacial data structures like Quad Trees, R-Trees or Spacial Hashmaps.

Upvotes: 1

Related Questions