components/LogicAngularMovement.js

import {arrayCache} from '../utils/array.js';
import createComponentClass from '../factory.js';

export default (function () {
    return createComponentClass(/** @lends platypus.components.LogicAngularMovement.prototype */{
        
        id: 'LogicAngularMovement',
        
        properties: {
            /**
             * The max velocity.
             *
             * @property maxVelocity
             * @type Number
             * @default 3
             */
            maxVelocity: 3,

            /**
             * The rate of acceleration.
             *
             * @property acceleration
             * @type Number
             * @default 0.01
             */
            acceleration: 0.01,

            /**
             * The offset between the rotation value of the entity and the rotation of the art.
             *
             * @property visualOffset
             * @type Number
             * @default 0
             */
            visualOffset: 0,

            /**
             * The starting heading at which the entity will accelerate. In radians.
             *
             * @property startAngle
             * @type Number
             * @default 0
             */
            startAngle: 0
        },

        publicProperties: {

        },

        /**
         * This component moves the entity in the direction of an internally stored angle value. When moving, the entity constantly accelerates the entity in a direction up to a max velocity.
         *
         * @memberof platypus.components
         * @uses platypus.Component
         * @constructs
         * @listens platypus.Entity#handle-logic
         * @listens platypus.Entity#move
         * @listens platypus.Entity#set-angle
         * @listens platypus.Entity#set-max-velocity
         * @listens platypus.Entity#stop
         */
        initialize: function () {
            this.angle     = this.startAngle;
            this.v         = arrayCache.setUp(0, 0);
            this.moving    = false;
            this.piOverTwo = Math.PI / 2;
            this.owner.rotation = this.owner.rotation || this.visualOffset;
        },

        events: {
            "handle-logic": function (tick) {
                var PI  = Math.PI,
                    sin = Math.sin,
                    cos = Math.cos,
                    min = Math.min,
                    max = Math.max,
                    delta        = tick.delta,
                    currentAngle = 0;
                
                if (this.moving) {
                    this.v[0] += this.acceleration * cos(this.angle) * delta;
                    this.v[1] += this.acceleration * sin(this.angle) * delta;
                    if (this.v[0] === 0) {
                        if (this.v[1] > 0) {
                            currentAngle = this.piOverTwo;
                        } else if (this.v[1] < 0) {
                            currentAngle = -this.piOverTwo;
                        } else {
                            currentAngle = this.angle;
                        }
                    } else {
                        currentAngle = Math.atan(this.v[1] / this.v[0]);
                        if (this.v[0] < 0) {
                            currentAngle = PI + currentAngle;
                        }
                    }
                    if (this.v[0] >= 0) {
                        this.v[0] = min(this.v[0], this.maxVelocity * cos(currentAngle));
                    } else {
                        this.v[0] = max(this.v[0], this.maxVelocity * cos(currentAngle));
                    }
                    if (this.v[1] >= 0) {
                        this.v[1] = min(this.v[1], this.maxVelocity * sin(currentAngle));
                    } else {
                        this.v[1] = max(this.v[1], this.maxVelocity * sin(currentAngle));
                    }
                    
                    this.owner.x += this.v[0];
                    this.owner.y += this.v[1];

                    this.owner.rotation = (currentAngle * (180 / PI)) + this.visualOffset;
                }
            },
            /**
             * Sets the internal heading angle in the component.
             *
             * @event platypus.Entity#set-angle
             * @param angle {Number} The value you want to set the angle to.
             */
            "set-angle": function (angle) {
                this.angle = angle;
            },

            /**
             * Start the entity accelerating toward the heading angle.
             *
             * @event platypus.Entity#move
             */
            "move": function () {
                this.moving = true;
            },

            "stop": function () {
                this.moving = false;
                this.v[0] = 0;
                this.v[1] = 0;
            },

            /**
             * Set the max velocity.
             *
             * @event platypus.Entity#set-max-velocity
             * @param newMaxV {Number} The max velocity value.
             */
            "set-max-velocity": function (newMaxV) {
                this.maxVelocity = newMaxV;
            }
        },
        
        methods: {
            destroy: function () {
                this.v.recycle();
            }
        }
    });
}());