hyperandroid / CAAT

Canvas Advanced Animation Toolkit
hyperandroid.github.com/CAAT
MIT License
727 stars 117 forks source link

behavior listener events not launched if setVisible false #126

Open rehanog opened 11 years ago

rehanog commented 11 years ago

Not sure if this issue represents a feature or a bug, i.e., not sure if you intended to switch off listeners for invisible objects. To me, it makes sense if behavior listeners are active, even if an actor is not visible.

The goal of the sample code below is for the actor to become visible and perform relevant behaviour once the mouse is clicked.

Code that works:

Using this code, "something happens" is output on the console log when I click the button


this.oMyActor.setVisible( false );

this.oMyBehavior.addListener( {
   behaviorStarted : function( behavior, time, actor ) {
      console.log( "Something happened" );
   }
} );

this.oMyButton.mouseClick.mouseClick = function( mouseEvent ) {
   that.oMyActor.setVisible( true );
   that.oMyBehavior.setFrameTime( that.scene.time, 2000 );
};

this.oMyActor.addBehavior( oMyBehavior );

Code I would prefer:

Using this code, nothing happens when I click the button

this.oMyActor.setVisible( false );

this.oMyBehavior.addListener( {
   behaviorStarted : function( behavior, time, actor ) {
      actor.setVisible( true );
      console.log( "Something happened" );
   }
} );

this.oMyButton.mouseClick = function( mouseEvent ) {
   that.oMyBehavior.setFrameTime( that.scene.time, 2000 );
};

this.oMyActor.addBehavior( oMyBehavior );
hyperandroid commented 11 years ago

This is the intended behavior. Something invisible, or out of the timeline, should not spend any system resource, and if it is a Container instance, none of its children either. It is a big deal having one single actor:

Could you think of any other way of achieving your expected results ?

thanks.

fracasula commented 11 years ago

Similar issue here, I have a main ActorContainer called TilesGrid with many Tiles (actors) inside. TilesGrid is biggest than canvas size, so I need a dragging functionality to offer an "explore" mode to the user.

I need a mouseClick listener (tile selection) and a mouseDrag listener (tiles exploration), so the two listeners are attached to the single tile (CAAT.Tile).

CAAT.Tile.prototype.mouseUp = function (mouseEvent) {
    console.log('hex up', this.Id);

    // trying to reattach listeners to the "new" tiles on mouseUp - didn't work
    for (var i in this.parent.Hexes) {
        this.parent.Hexes[i].enableEvents(true);
        this.parent.Hexes[i].mouseUp = CAAT.Tile.prototype.mouseUp;
        this.parent.Hexes[i].mouseDrag = CAAT.Tile.prototype.mouseDrag;
        this.parent.Hexes[i].mouseClick = CAAT.Tile.prototype.mouseClick;
    }
};

CAAT.Tile.prototype.mouseClick = function (mouseEvent) {
    console.log('hex click', this.Id);
    this.selected = !this.selected;
};

CAAT.Tile.prototype.mouseDrag = function (mouseEvent) {
    if (!this.oldDragX || !this.oldDragY) {
        this.oldDragX = mouseEvent.screenPoint.x;
        this.oldDragY = mouseEvent.screenPoint.y;
    } else {
        var speedX = parseInt(this.oldDragX - mouseEvent.screenPoint.x, 10),
            speedY = parseInt(this.oldDragY - mouseEvent.screenPoint.y, 10);

        if (speedX < 0) {
            speedX *= -1;
        }

        if (speedY < 0) {
            speedY *= -1;
        }

        if (this.oldDragX < mouseEvent.screenPoint.x) {
            this.parent.x += speedX;
        } else if (this.oldDragX > mouseEvent.screenPoint.x) {
            this.parent.x -= speedX;
        }

        if (this.oldDragY < mouseEvent.screenPoint.y) {
            this.parent.y += speedY;
        } else if (this.oldDragY > mouseEvent.screenPoint.y) {
            this.parent.y -= speedY;
        }

        this.oldDragX = mouseEvent.screenPoint.x;
        this.oldDragY = mouseEvent.screenPoint.y;
    }
};

Now, all works fine, clicking and dragging, but when I drag the tiles grid, new tiles are shown, and the listeners on these "new" tiles didn't work.

How can I force the listeners for the new tiles shown?

hyperandroid commented 11 years ago

If i get the question right, you'd expect an invisible actor to have input sent ? like a 'ghost' element on screen ? or Francesco, do you think this is a bug ? could you post some code i could take a look at ?

thanks.

2013/4/6 Francesco Casula notifications@github.com

Similar issue here, I have a main ActorContainer called TilesGrid with many Tiles (actors) inside. TilesGrid is biggest than canvas size, so I need a dragging functionality to offer an "explore" mode to the user.

I need a mouseClick listener (tile selection) and a mouseDrag listener (tiles exploration), so the two listeners are attached to the single tile (CAAT.Tile).

CAAT.Tile.prototype.mouseUp = function (mouseEvent) { console.log('hex up', this.Id);

// trying to reattach listeners to the "new" tiles on mouseUp - didn't work
for (var i in this.parent.Hexes) {
    this.parent.Hexes[i].enableEvents(true);
    this.parent.Hexes[i].mouseUp = CAAT.Tile.prototype.mouseUp;
    this.parent.Hexes[i].mouseDrag = CAAT.Tile.prototype.mouseDrag;
    this.parent.Hexes[i].mouseClick = CAAT.Tile.prototype.mouseClick;
}

};

CAAT.Tile.prototype.mouseClick = function (mouseEvent) { console.log('hex click', this.Id); this.selected = !this.selected; };

CAAT.Tile.prototype.mouseDrag = function (mouseEvent) { if (!this.oldDragX || !this.oldDragY) { this.oldDragX = mouseEvent.screenPoint.x; this.oldDragY = mouseEvent.screenPoint.y; } else { var speedX = parseInt(this.oldDragX - mouseEvent.screenPoint.x, 10), speedY = parseInt(this.oldDragY - mouseEvent.screenPoint.y, 10);

    if (speedX < 0) {
        speedX *= -1;
    }

    if (speedY < 0) {
        speedY *= -1;
    }

    if (this.oldDragX < mouseEvent.screenPoint.x) {
        this.parent.x += speedX;
    } else if (this.oldDragX > mouseEvent.screenPoint.x) {
        this.parent.x -= speedX;
    }

    if (this.oldDragY < mouseEvent.screenPoint.y) {
        this.parent.y += speedY;
    } else if (this.oldDragY > mouseEvent.screenPoint.y) {
        this.parent.y -= speedY;
    }

    this.oldDragX = mouseEvent.screenPoint.x;
    this.oldDragY = mouseEvent.screenPoint.y;
}

};

Now, all works fine, clicking and dragging, but when I drag the tiles grid, new tiles are shown, and the listeners on these "new" tiles didn't work.

— Reply to this email directly or view it on GitHubhttps://github.com/hyperandroid/CAAT/issues/126#issuecomment-15997733 .

fracasula commented 11 years ago

In my opinion this can be considered as a bug because, after the dragging operation, the new tiles are shown and visible (but aren't clickable/draggable). In the first screenshot you can see the starting screen. In the lower right-hand corner there is the L30 tile.

Screenshot 1: screen1

If the user clicks on this tile and drag in the "top-left" direction, new tiles are shown and visible (screenshot 2). The new visible tiles (screenshot 2) aren't clickable and draggable (except for the L30 in the higher left-hand corner).

Screenshot 2:

screen2

You can find all the code involved in this issue in my first comment (above):

Thanks in advance and congrats for CAAT :+1:

hyperandroid commented 11 years ago

I see. The problem may be, that your container is the size of the screen (scene or director), but not the size of a bounding box containing all its children. You can make the container conform to its children size by calling new CAAT.Foundation.ActorContainer(true) If this is not your case, this is definitely a bug.

On the other hand, this is tricky, since organizing such a container, with hundreds of children can be low performant. My advice would be using the builtin quadtree, and overriding the paint method to draw only the selected group of tiles visible on the screen. I can set up a basic huge map with quadtree capabilities if after setting the container conform to its children size you get low performance.

Let me know if this is your case. Thanks for the heads up :)

fracasula commented 11 years ago

You're right, the problem was the parent size :+1:

Now all works fine, the performance is good on desktop but too lower on mobile. I tested it on Android (Samsung Galaxy S2) and on huge maps it's unusable, with little maps it has a low framerate but it's usable. The framerate is still low with maps that fit the screen (without new tiles printing) with a tiles grid of only 12x10, so I'm thinking about a new explore system (like one button on each side to scroll in a single direction for X tiles).

But, before I try to code a new explore system... do you have any advice to improve performance? Can we try with the quadtree capabilities?

EDIT: for mobile tests I'm using the Ludei cocoonjs cloud compiler, but my app seems to be like the left side of this video: http://vimeo.com/60235958

Thank you very much!

arnuschky commented 10 years ago

I just found SpriteImage.initializeFromMap(image, map), which answers my question. Does anyone know if I can nest sprite images? Ie, I have a large map of images, and some of them are in themselves image maps (ie, a bunch of buttons). Does that work with CAAT, or do I need to break things up?

Arne

On Sat, 06 Apr 2013 08:12:13 -0700 Francesco Casula notifications@github.com wrote:

Similar issue here, I have a main ActorContainer called TilesGrid with many Tiles (actors) inside. TilesGrid is biggest than canvas size, so I need a dragging functionality to offer an "explore" mode to the user.

I need a mouseClick listener (tile selection) and a mouseDrag listener (tiles exploration), so the two listeners are attached to the single tile (CAAT.Tile).

CAAT.Tile.prototype.mouseUp = function (mouseEvent) { console.log('hex up', this.Id);

  // trying to reattach listeners to the "new" tiles on

mouseUp - didn't work for (var i in this.parent.Hexes) { this.parent.Hexes[i].enableEvents(true); this.parent.Hexes[i].mouseUp = CAAT.Tile.prototype.mouseUp; this.parent.Hexes[i].mouseDrag = CAAT.Tile.prototype.mouseDrag; this.parent.Hexes[i].mouseClick = CAAT.Tile.prototype.mouseClick; } };

CAAT.Tile.prototype.mouseClick = function (mouseEvent) { console.log('hex click', this.Id); this.selected = !this.selected; };

CAAT.Tile.prototype.mouseDrag = function (mouseEvent) { if (!this.oldDragX || !this.oldDragY) { this.oldDragX = mouseEvent.screenPoint.x; this.oldDragY = mouseEvent.screenPoint.y; } else { var speedX = parseInt(this.oldDragX - mouseEvent.screenPoint.x, 10), speedY = parseInt(this.oldDragY - mouseEvent.screenPoint.y, 10);

      if (speedX < 0) {
          speedX *= -1;
      }

      if (speedY < 0) {
          speedY *= -1;
      }

      if (this.oldDragX < mouseEvent.screenPoint.x)

{ this.parent.x += speedX; } else if (this.oldDragX > mouseEvent.screenPoint.x) { this.parent.x -= speedX; }

      if (this.oldDragY < mouseEvent.screenPoint.y)

{ this.parent.y += speedY; } else if (this.oldDragY > mouseEvent.screenPoint.y) { this.parent.y -= speedY; }

      this.oldDragX = mouseEvent.screenPoint.x;
      this.oldDragY = mouseEvent.screenPoint.y;
  }

};

Now, all works fine, clicking and dragging, but when I drag the tiles grid, new tiles are shown, and the listeners on these "new" tiles didn't work.


Reply to this email directly or view it on GitHub: https://github.com/hyperandroid/CAAT/issues/126#issuecomment-15997733