Sign in to follow this  
Ian_

Shooting projectiles in a specific direction

Recommended Posts

Hi there,

 

I am looking into how projectiles can be fired, my intention is to try and fire in the direction that the cursor is at ( me.input.pointer.pos ).

My first idea was to try and work out if the cursor needs to move in a positive or negative direction, I added `mainPlayer` to the pool, so somehow if I can get the position of them then I can work out which way to shoot in regards to right or left, but I'm not sure how to access the `mainPlayer`.

How would you go about solving this problem? My Entities are below so you can see how they currently react

 

/**
 * Player Entity
 */
game.PlayerEntity = me.Entity.extend({

    /**
     * constructor
     */
    init: function (x, y, settings) {

        settings = settings || {
                image: 'character_default_run',
                height: 32,
                width: 32
            };

        // call the constructor
        this._super(me.Entity, 'init', [x, y, settings]);

        // set the default horizontal & vertical speed (accel vector)
        this.body.setVelocity(1, 1);

        // set the display to follow our position on both axis
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

        // ensure the player is updated even when outside of the viewport
        this.alwaysUpdate = true;

        // define a basic walking animation (using all frames)
        this.renderable.addAnimation("walk", [0, 1, 2, 3, 4, 5, 6, 7]);

        // define a standing animation (using the first frame)
        this.renderable.addAnimation("stand", [0]);

        // set the standing animation as default
        this.renderable.setCurrentAnimation("stand");

        this.body.collisionType = me.collision.types.PLAYER_OBJECT;
    },

    /**
     * update the entity
     */
    update: function (dt) {

        if (me.input.isKeyPressed("action1")) {
            var action = me.pool.pull("iceBeam", this.pos.x, this.pos.y);
            me.game.world.addChild(action);
        }

        if (me.input.isKeyPressed("run")) {
            this.body.setVelocity(2, 2);
        }
        else
            this.body.setVelocity(1, 1);

        if (me.input.isKeyPressed("left")) {
            // update the entity velocity
            this.renderable.flipX(true);

            this.body.vel.x -= this.body.accel.x * me.timer.tick;

            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        } else if (me.input.isKeyPressed("right")) {

            // unflip the sprite
            this.renderable.flipX(false);

            // update the entity velocity
            this.body.vel.x += this.body.accel.x * me.timer.tick;

            // change to the walking animation
            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        }
        else {
            this.body.vel.x = 0;
        }

        if (me.input.isKeyPressed("up")) {
            // update the entity velocity
            this.body.vel.y -= this.body.accel.y * me.timer.tick;

            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        } else if (me.input.isKeyPressed("down")) {
            // update the entity velocity
            this.body.vel.y += this.body.accel.y * me.timer.tick;

            if (!this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        } else {
            this.body.vel.y = 0;
        }

        if (this.body.vel.y === 0 && this.body.vel.x === 0)
            this.renderable.setCurrentAnimation("stand");

        this.body.update(dt);

        // handle collisions against other shapes
        me.collision.check(this);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
    },

    /**
     * colision handler
     * (called when colliding with other objects)
     */
    onCollision: function (response, other) {


        if (other.body.collisionType === me.collision.types.PROJECTILE_OBJECT) {
            return false;
        }
        // Make all other objects solid
        return true;
    }
});

game.Spell = me.Entity.extend({});

game.Spell.Icebeam = game.Spell.extend({

    /**
     * constructor
     */
    init: function (x, y, settings) {

        settings = settings || {
                image: 'short-ray',
                height: 86,
                width: 16
            };

        // call the constructor
        this._super(me.Entity, 'init', [x, y, settings]);

        this.alwaysUpdate = false;

        this.body.collisionType = me.collision.types.PROJECTILE_OBJECT;

        var pos = me.input.pointer.pos;
        this.endX = pos.x;
        this.endY = pos.y;

        console.log('Aiming at', pos);

    },

    update: function (dt) {

        this.body.setVelocity(3,3);

        // If the current position isnt at the endpoint then move it there

        console.log(me.game.world.getChildByName("mainPlayer"));
        // if(this.pos.x <= this.endX && this)
        // {
        //     // Set x velocity
        //     this.body.vel.x += this.body.accel.x * me.timer.tick;
        //
        // }
        // else
        //     me.game.world.destroy(this);

        // handle collisions against other shapes
        me.collision.check(this);

        this.body.update(dt);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
    },

    onCollision: function (response, other) {
        if (other.body.collisionType === me.collision.types.PROJECTILE_OBJECT || other.body.collisionType === me.collision.types.PLAYER_OBJECT) {
            return false;
        }

        me.game.world.removeChild(this);

        return true;
    }
});

Appreciate any pointers, thanks

Share this post


Link to post
Share on other sites

Hey there. In order to have something translate from one point to another, you need to do some calculation to determine the angle. First thing is to grab the angle in radians between both points.

const angle = Math.atan2(targetPos.y - pos.y, targetPos.x - pos.x)

// The ice beam that you're firing, use that angle to set its rotation:
// For some reason we need to offset by 90degrees. I think it's due to the natural orientation of things in the canvas

this.renderable.currentTransform.rotate(angle - 90 * Math.PI / 180)

// then calculate the velocity

this.body.setVelocity(Math.cos(angle) * 3, Math.sin(angle) * 3)

 

Note I haven't tested this with MelonJS. This some older code i pulled out from a game in 2013 i did with melon, and quickly tested the math in a code pen:

You may not need to subtract the 90 degrees from the angle, depending on how the matrix applies the rotation.

Share this post


Link to post
Share on other sites
On 11/29/2017 at 3:18 AM, agmcleod said:

Hey there. In order to have something translate from one point to another, you need to do some calculation to determine the angle. First thing is to grab the angle in radians between both points.


const angle = Math.atan2(targetPos.y - pos.y, targetPos.x - pos.x)

// The ice beam that you're firing, use that angle to set its rotation:
// For some reason we need to offset by 90degrees. I think it's due to the natural orientation of things in the canvas

this.renderable.currentTransform.rotate(angle - 90 * Math.PI / 180)

// then calculate the velocity

this.body.setVelocity(Math.cos(angle) * 3, Math.sin(angle) * 3)

 

Note I haven't tested this with MelonJS. This some older code i pulled out from a game in 2013 i did with melon, and quickly tested the math in a code pen:

You may not need to subtract the 90 degrees from the angle, depending on how the matrix applies the rotation.

 

Sort of works, the angle is indeed now correct, however it doesn't move to it's destination, I think I messed something up, I have updated the code below.

 


game.Spell = me.Entity.extend({});

game.Spell.Icebeam = game.Spell.extend({

    /**
     * constructor
     */
    init: function (x, y, settings) {

        settings = settings || {
            image: 'short-ray',
            height: 86,
            width: 16
        };

        // call the constructor
        this._super(me.Entity, 'init', [x, y, settings]);

        this.alwaysUpdate = true;

        this.body.collisionType = me.collision.types.PROJECTILE_OBJECT;

        var pos = me.input.pointer.pos;
        this.endX = pos.x;
        this.endY = pos.y;

        // then calculate the velocity
        console.log('Aiming at', pos);

    },

    update: function (dt) {
        // If the current position isnt at the endpoint then move it there

        const angle = Math.atan2(this.endY - this.body.pos.y, this.endX - this.body.pos.x);

        // The ice beam that you're firing, use that angle to set its rotation:
        // For some reason we need to offset by 90degrees. I think it's due to the natural orientation of things in the canvas

        this.renderable.currentTransform.rotate(angle - 90 * Math.PI / 180);

        // then calculate the velocity

        this.body.setVelocity(Math.cos(angle) * 3, Math.sin(angle) * 3);
        // If current path of protectile is not at the endpoint move forward

        // The ice beam that you're firing, use that angle to set its rotation:
        // For some reason we need to offset by 90degrees. I think it's due to the natural orientation of things in the canvas


        // handle collisions against other shapes
        me.collision.check(this);

        this.body.update(dt);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
    },

    onCollision: function (response, other) {
        if (other.body.collisionType === me.collision.types.PROJECTILE_OBJECT || other.body.collisionType === me.collision.types.PLAYER_OBJECT) {
            return false;
        }

        console.log('Collision on ice beam other', other.body.collisionType);
        console.log('Collision on ice beam response', response.body.collisionType);

        me.game.world.removeChild(this);

        return true;
    }
});

 

I would also like to note that the IceBeam entitity spins round and round on the spot ONLY when the player moves.

Share this post


Link to post
Share on other sites

Hey sorry for not getting back sooner. You just need to increase the velocity by the accel value:

this.body.vel.x -= this.body.accel.x * me.timer.tick;

this.body.vel.y -= this.body.accel.y * me.timer.tick;

Do that after calling setVelocity, and before the body.update(). If you have a look a the source of setVelocity, you'll see it's setting the acceleration rate: https://github.com/melonjs/melonJS/blob/master/src/physics/body.js#L412

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.