Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by Clyssandre

Hello,

Could someone help with the following issue?

I have two entities overlapping each other. The smaller entity (smaller graphics) is 100% on top of the bigger one. I made sure the smaller entity has a higher zIndex. They both have a 'clicked' method defined.
When I click the smaller entity, it's the bigger entity "clicked" method that is triggered and the "clicked" method of the smaller entity is ignored.

Could someone explains this behaviour to me?
Is there a way to make the click trigger only the "clicked" method of the topmost entity ?

I found this but it's 2 years old:
http://pointofimpactjs.com/snippets/view/16/entity-click

Is it still the way to go?

Thank you for any help!

1 decade ago by Joncom

Maybe something like this would work:
ig.module('game.entities.click-event-manager')
.requires('impact.entity')
.defines(function() {

EntityClickEventManager = ig.Entity.extend({
    update: function() {
        if(ig.input.pressed('click')) {
            // Get an array of entities which the mouse is over.
            var entitiesMouseIsOver = [];
            for(var i=0; i<ig.game.entities.length; i++) {
                var entity = ig.game.entities[i];
                if(this.mouseIsOverEntity(entity)) {
                    entitiesMouseIsOver.push(entity);
                }
            }
            // Sort by ".zIndex"
            entitiesMouseIsOver.sort(function(a,b) {return a.zIndex - b.zIndex;});
            // The last entity has the highest zIndex, so call clicked.
            entitiesMouseIsOver[entitiesMouseIsOver.length-1].clicked();
        }
    },
    mouseIsOverEntity: function(entity) {
        var mouseX = ig.game.screen.x + ig.input.mouse.x;
        var mouseY = ig.game.screen.y + ig.input.mouse.y;
        return (
            mouseX >= entity.pos.x &&
            mouseX < entity.pos.x + entity.size.x &&
            mouseY >= entity.pos.y &&
            mouseY < entity.pos.y + entity.size.y
        );
    }
});

});

1 decade ago by noGrip

Nice solution Joncom! Thank you!

I had the same issue a while ago. What I did at the time, was just enabling and disabling the entities that could be clicked according to the state of my game. That way, even if the entities where overlapped, only one of them would react to the click.

But Joncom solution is neater no doubt.

Cheers

Paulo

1 decade ago by Clyssandre

Thank you very very much for your help and sorry I didn't reply before!

I'm going to try this today. I have a question though: it looks like the click event manager checks if the click happened in the "box" containing an entity ( rectangle defined by its width and height). My issue is that my entities graphics are PNG with some transparency, so the containing "box" doesn't necessarily match the click area.

Your method is a very good start, thank you for the share. I'm going to start from this!

1 decade ago by Clyssandre

Ok, so I ended up using a mix of Joncom solution and Impact-ScaledAlphaHitmask plugin.

In case it's of any use for anyone, here is what I do :

Use of Joncom click event manager to click the top most object on the scene, with two modifications: 1) a fix in case there's no entity under the mouse and 2) mouseIsOverEntity checks if the entity has a hitTest method.

ig.module('game.entities.click-event-manager')
    .requires('impact.entity','plugins.scaled-alpha-hitmask')
    .defines(function() {

        EntityClickEventManager = ig.Entity.extend({
            update: function() {
                if(ig.input.pressed('click')) {
                    // Get an array of entities which the mouse is over.
                    var entitiesMouseIsOver = [];
                    for(var i=0; i<ig.game.entities.length; i++) {
                        var entity = ig.game.entities[i];
                        if(this.mouseIsOverEntity(entity)) {
                            entitiesMouseIsOver.push(entity);
                        }
                    }
                    // Sort by ".zIndex"
                    entitiesMouseIsOver.sort(function(a,b) {return a.zIndex - b.zIndex;});
                    // The last entity has the highest zIndex, so call clicked.
                    if (entitiesMouseIsOver.length > 0) {
                        entitiesMouseIsOver[entitiesMouseIsOver.length-1].clicked();
                    }

                }
            },
            mouseIsOverEntity: function(entity) {
                var mouseX = ig.game.screen.x + ig.input.mouse.x;
                var mouseY = ig.game.screen.y + ig.input.mouse.y;
                if (entity.hitTest != null && entity.hitTest != undefined) {
                    return (entity.hitTest());
                } else {
                    return (
                        mouseX >= entity.pos.x &&
                            mouseX < entity.pos.x + entity.size.x &&
                            mouseY >= entity.pos.y &&
                            mouseY < entity.pos.y + entity.size.y
                        );
                }

            }
        });

    });

And here is a sample entity, using the plugin. I added the method HitTest that returns "true" if the mouse coords are within the image and on a pixel that has alpha > 0.

ig.module (
    'game.entities.sign'
)
    .requires(
    'impact.entity',
    'plugins.scaled-alpha-hitmask'
)
    .defines(function() {

        EntitySign = ig.Entity.extend({
            hitmask: null,
            type: ig.Entity.TYPE.B,
            animSheet:new ig.AnimationSheet( 'media/introscreen/intro_blue_arrow.png', 199, 107),
            size: {x:199, y:107 },
            zIndex: 10,

            init: function( x,y,settings) {
                this.addAnim( 'playing', 1, [0]);
                this.hitmask = new ig.ScaledAlphaHitmask();
                // this.hitmask.drawHitmask = true;     // don't draw debug mask over image
                this.hitmask.scale = 1;
                this.hitmask.setImage(this.animSheet.image);
                this.parent( x, y, settings );

            },

            update: function() {
                this.parent();
            },

            clicked: function() {
                if (this.hitmask.entityHittest(this)) {
                    window.alert("Sign blue clicked!");
                } else {
                    window.alert("Sign blue clicked... in transparency");
                }  
            },

            hitTest: function( ) {
                  return this.hitmask.entityHittest(this);
            }

        });

    });

There well might be a better solution for this. I'm brand new to ImpactJS. Don't hesitate to suggest something better...

Thank you again both of you for your answer!
Page 1 of 1
« first « previous next › last »