# Plugin

A plugin system based on the interceptor pattern, designed to share reusable code such as more advance collision detection or a 2D physics engine.

    let { registerPlugin, Sprite } = kontra;
    import loggingPlugin from 'path/to/plugin/code.js'

    // register a plugin that adds logging to all Sprites
    registerPlugin(Sprite, loggingPlugin);

    import { registerPlugin, Sprite } from 'path/to/kontra.mjs';
    import loggingPlugin from 'path/to/plugin/code.js'

    // register a plugin that adds logging to all Sprites
    registerPlugin(Sprite, loggingPlugin);

    import { registerPlugin, Sprite } from 'kontra';
    import loggingPlugin from 'path/to/plugin/code.js'

    // register a plugin that adds logging to all Sprites
    registerPlugin(Sprite, loggingPlugin);

## How to Create a Plugin #

A plugin is an object that defines a set of intercept functions that should be run before or after a Kontra objects functions. These functions allow you to modify the code or change the behavior of the intercepted functions.

An intercept function is named the same name as the function it will intercept. The function name is also prefixed with `before` to have the function run before the intercepted function, or `after` to run after the intercepted function.

For example, if you wish to add a function to run after a Sprites `collidesWidth()` function, the name of the intercept function would be `afterCollidesWidth` (note the capitalization of the `collidesWidth` function name). `beforeCollidesWidth` would run before the Sprites `collidesWidth()` function.

A plugin can define any number of before and after intercept functions. When the plugin is registered for a Kontra object, only intercept functions that match a function name in the Kontra object will be intercepted.

As the plugin author, you should not register the plugin yourself. You should only export the plugin object and let the consumer register it.

    // pluginCode.js
    const loggingPlugin = {
      afterCollidesWith(sprite, result, object) {
        console.log('collision between sprites!');
      }
    };
    export default loggingPlugin;

    // consumerCode.js
    let { registerPlugin, Sprite } = kontra;
    import loggingPlugin from pluginCode.js;

    // have the plugin run for all Sprites
    registerPlugin(Sprite, loggingPlugin);

    let sprite1 = Sprite({
      x: 10,
      y: 20,
      width: 10,
      height: 10
    });

    let sprite2 = Sprite({
      x: 15,
      y: 20,
      width: 10,
      height: 10
    });

    sprite1.collidesWith(sprite2);  //=> 'collision between sprites!'; true

    // consumerCode.js
    import { registerPlugin, Sprite } from 'path/to/kontra.mjs';
    import loggingPlugin from pluginCode.js;

    // have the plugin run for all Sprites
    registerPlugin(Sprite, loggingPlugin);

    let sprite1 = Sprite({
      x: 10,
      y: 20,
      width: 10,
      height: 10
    });

    let sprite2 = Sprite({
      x: 15,
      y: 20,
      width: 10,
      height: 10
    });

    sprite1.collidesWith(sprite2);  //=> 'collision between sprites!'; true

    // consumerCode.js
    import { registerPlugin, Sprite } from 'kontra';
    import loggingPlugin from pluginCode.js;

    // have the plugin run for all Sprites
    registerPlugin(Sprite, loggingPlugin);

    let sprite1 = Sprite({
      x: 10,
      y: 20,
      width: 10,
      height: 10
    });

    let sprite2 = Sprite({
      x: 15,
      y: 20,
      width: 10,
      height: 10
    });

    sprite1.collidesWith(sprite2);  //=> 'collision between sprites!'; true

## Before Intercept Functions #

A before intercept function can be used to modify or change the arguments that will be passed to the intercepted function.

The function will be passed the `this` context of the intercepted object as well as all arguments of the original call. The function should either return an Array of the arguments if modifying them or return `null` or nothing if not modifying the arguments.

    class MyObj {
      add(a, b) {
        return a + b;
      }
    }

    // create a plugin that doubles the arguments before passing
    // them to the original add function
    registerPlugin(MyObj, {
      beforeAdd(context, a, b) {
        return [a * 2, b * 2];
      }
    });

    const obj = new MyObj();
    obj.add(1, 2);  //=> 6

Multiple before intercept functions can be registered for the same function. All functions will be run in the order they were registered. The functions return value will be passed to the next function. If the function doesn't modify the arguments (returned `null` or nothing) then the functions parameters will be passed to the next function instead.

    class MyObj {
      add(a, b) {
        return a + b;
      }
    }

    // log the arguments of the call and pass them unchanged to
    // the next plugin
    registerPlugin(MyObj, {
      beforeAdd(context, a, b) {
        console.log(`add passed: ${a}, ${b}`);
      }
    });

    registerPlugin(MyObj, {
      beforeAdd(context, a, b) {  // receives a=1 and b=2
        return [a * 2, b * 2];
      }
    });

    const obj = new MyObj();
    obj.add(1, 2);  //=> 'add passed: 1, 2'; 6

## After Intercept Functions #

An after intercept function can be used to modify or change the results of the intercepted function.

The function will be passed the `this` context of the intercepted object, the result of the intercepted function, and the final arguments passed to the intercepted function. The function should either return a value if modifying the result or return `null` or nothing if not modifying the result.

    class MyObj {
      add(a, b) {
        return a + b;
      }
    }

    // create a plugin that doubles the result
    registerPlugin(MyObj, {
      afterAdd(context, result, a, b) {
        return result * 2;
      }
    });

    const obj = new MyObj();
    obj.add(1, 2);  //=> 6

Multiple after intercept functions can be registered for the same function. All functions will be run in the order they were registered. Each functions return value will be passed to the next function. If the function doesn't modify the result (returned `null` or nothing) then the functions parameters will be passed to the next function instead.

    class MyObj {
      add(a, b) {
        return a + b;
      }
    }

    // log the arguments of the call and pass them unchanged to
    // the next plugin
    registerPlugin(MyObj, {
      afterAdd(context, result, a, b) {
        console.log(`add passed: ${a}, ${b} and returned ${result}`);
      }
    });

    registerPlugin(MyObj, {
      afterAdd(context, result, a, b) {  // receives result=3
        return result * 2;
      }
    });

    const obj = new MyObj();
    obj.add(1, 2);  //=> 'add passed: 1, 2 and returned 3'; 6

## extendObject(​kontraObj, properties) #

Safely extend the functionality of a Kontra object. Any properties that already exist on the Kontra object will not be added.

    let { extendObject, Vector } = kontra;

    // add a subtract function to all Vectors
    extendObject(Vector, {
      subtract(vec) {
        return Vector(this.x - vec.x, this.y - vec.y);
      }
    });

    import { extendObject, Vector } from 'path/to/kontra.mjs';

    // add a subtract function to all Vectors
    extendObject(Vector, {
      subtract(vec) {
        return Vector(this.x - vec.x, this.y - vec.y);
      }
    });

    import { extendObject, Vector } from 'kontra';

    // add a subtract function to all Vectors
    extendObject(Vector, {
      subtract(vec) {
        return Vector(this.x - vec.x, this.y - vec.y);
      }
    });

### extendObject Parameters

`kontraObj`

  Object. Kontra object to extend

`properties`

  Object. Properties to add.

## registerPlugin(​kontraObj, pluginObj) #

Register a plugin to run a set of functions before or after the Kontra object functions.

### registerPlugin Parameters

`kontraObj`

  Object. Kontra object to attach the plugin to.

`pluginObj`

  Object. Plugin object with before and after intercept functions.

## unregisterPlugin(​kontraObj, pluginObj) #

Unregister a plugin from a Kontra object.

### unregisterPlugin Parameters

`kontraObj`

  Object. Kontra object to detach plugin from.

`pluginObj`

  Object. The plugin object that was passed during registration.