quadtree-ts

2.2.2

Class Extension Example

The recommended way to integrate the built-in primitives into your own code is by inheritance.
In ES6, this can easily be done by using classes and the extends keyword.

The crucial part to make objects Quadtree-compatible is to implement the Indexable interface – that means to provide a qtIndex() method, that returns the quadrant of the object for any given Quadtree node. All Indexable objects can be inserted or used for retrieval.

The following code is reduced to the most important parts. View the full script.js of this example on GitHub.

HTML

<canvas id="canvas" width="640" height="480"></canvas>

Player.JS

// The Player class will inherit the `qtIndex` method from Rectangle
class Player extends Quadtree.Rectangle {
    
    constructor(color) {

        // Call the super constructor to set x, y, width and height initially
        super({
            x: Math.random() * 640,
            y: Math.random() * 480,
            width: 32,
            height: 32,
        });

        // Store the color
        this.color = color;

        // Store a movement target position
        this.moveTargetX = this.x;
        this.moveTargetY = this.y;
    }

    // Draw the player
    draw(ctx) {

        // Draw the movement path
        ctx.beginPath();
        ctx.moveTo(this.x, this.y);
        ctx.lineTo(this.moveTargetX, this.moveTargetY);
        ctx.strokeStyle = this.color;
        ctx.stroke();

        // Draw the player
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }

    // Update the player position
    update() {
        const dx = this.moveTargetX - this.x;
        const dy = this.moveTargetY - this.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        // Move towards the target position
        if (distance > 1) {
            this.x += dx / distance;
            this.y += dy / distance;
        // Else, if the player is close enough, set a new target
        } else {
            this.moveTargetX = Math.random() * 640;
            this.moveTargetY = Math.random() * 480;
        }
    }
}

Script.JS

// Create a new Quadtree
const tree = new Quadtree({
	width: 640,
	height: 480,
});

// Create a red and blue player
const redPlayer = new Player('red');
const bluePlayer = new Player('blue');

// Store all objects in an array
const myObjects = [];

// Create some objects
for(let i=0;i<50;i++) {
    const rectangle = new Quadtree.Rectangle({
        x: Math.random() * (canvas.width-32),
        y: Math.random() * (canvas.height-32),
        width: 4 + Math.random() * 28,
        height: 4 + Math.random() * 28,
        data: {
            checkRed: false,
            checkBlue: false,
        }
    });

    tree.insert(rectangle);

    myObjects.push(rectangle);
}

// Main loop
function loop() {

    // Reset check flags
    myObjects.forEach(obj => obj.data.checkRed = obj.data.checkBlue = false);

    // Update players
    redPlayer.update();
    bluePlayer.update();
    
    // Retrieve all objects that share nodes with the players
    // Since the players extend Quadtree.Rectangle, we can use them with the retrieve function
    const redCandidates = tree.retrieve(redPlayer);
    const blueCandidates = tree.retrieve(bluePlayer);

    // Flag retrieved objects
    redCandidates.forEach(obj => obj.data.checkRed = true);
    blueCandidates.forEach(obj => obj.data.checkBlue = true);

    // Draw scene
    draw();
    
    window.requestAnimationFrame(loop);
};

loop();

To see the full example code please check the page source or visit this page on github.