clifftm Posted June 23, 2020 Share Posted June 23, 2020 (edited) Hello. If u paste this code (just a source code with a little modifications) here https://pixijs.io/examples/#/plugin-dragonbones/robot.js const app = new PIXI.Application({ antialias: true }); document.body.appendChild(app.view); //That will help with fps, but all children become not interactive //app.stage.interactiveChildren = false; app.stop(); // load spine data PIXI.Loader.shared .add('skeleton', 'examples/assets/pixi-dragonbones/robot/mecha_1002_101d_show_ske.json') .add('texture_json', 'examples/assets/pixi-dragonbones/robot/mecha_1002_101d_show_tex.json') .add('texture_png', 'examples/assets/pixi-dragonbones/robot/mecha_1002_101d_show_tex.png') .load(onAssetsLoaded); function onAssetsLoaded(loader, res) { const factory = dragonBones.PixiFactory.factory; factory.parseDragonBonesData(res.skeleton.data); factory.parseTextureAtlasData(res.texture_json.data, res.texture_png.texture); let scale = 0.1; for (let i = 0; i < 10; i++) for (let j = 0; j < 10; j++) { const armatureDisplay = factory.buildArmatureDisplay('mecha_1002_101d', 'mecha_1002_101d_show'); let lb = armatureDisplay.getLocalBounds(); //That makes better fps if uncomment //armatureDisplay.hitArea = new PIXI.Rectangle(lb.x, lb.y, lb.width, lb.height); armatureDisplay.pivot.set(lb.x, lb.y); armatureDisplay.scale.set(scale, scale); armatureDisplay.position.set( lb.width*i*armatureDisplay.scale.x, lb.height*j*armatureDisplay.scale.y); armatureDisplay.interactive = true; armatureDisplay.on('click',()=>{console.log(i*10+j)}); armatureDisplay.animation.play('idle'); app.stage.addChild(armatureDisplay); } app.start(); } and then move a mouse over a canvas FPS drops from ~20-25 frames to 1 frame. How can i avoid that dropping? As i understand ParticleContainer not working with DB or Spine. I'v tried disable mousemove events app.view.addEventListener('mousemove',(e)=> {e.stopPropagation()}) but that not helped. if i set app.stage.interactiveChildren = false; that helps with FPS a little, but in that case armatureDisplay.interactive = true will discarded and can't register any on('click') events , like armatureDisplay.on('click',()=>{console.log(i*31+j)}); I can agree that 900 dragonbones objects reduce total FPS from 60 to 30, but don't understand why it falls down on mouse move events. Probably the main problem is in hitArea, because setting it to the rounding box of the robot makes fps drops much smaller. If that true, how can i setup to check hitArea only on click, not on mouseMove? Thanks Edited June 24, 2020 by clifftm Quote Link to comment Share on other sites More sharing options...
clifftm Posted June 23, 2020 Author Share Posted June 23, 2020 Found a solution but it seems very rude window.document.removeEventListener('mousemove', app.renderer.plugins.interaction.onPointerMove, true); window.document.removeEventListener('pointermove', app.renderer.plugins.interaction.onPointerMove, true); is there any way to do this more softly? Quote Link to comment Share on other sites More sharing options...
clifftm Posted June 24, 2020 Author Share Posted June 24, 2020 So many developers on forum and no one has encountered a large number of objects and the problem of moving the cursor? Quote Link to comment Share on other sites More sharing options...
Exca Posted June 24, 2020 Share Posted June 24, 2020 The interaction plugin tries to find target it moves over on and if you have lots of interactive elements to search from with complex hitareas then movement will slow things down as it has to iterate lot of stuff and see if they are under the pointer. You could try setting the armatures interactiveChildren to false to prevent them from going deeper into the armature. Quote Link to comment Share on other sites More sharing options...
Exca Posted June 24, 2020 Share Posted June 24, 2020 If you want to make sure it's the interacitonmanagers search that is at fault you should take a profile when moving the mouse to see if that part of the code has issues. Quote Link to comment Share on other sites More sharing options...
themoonrat Posted June 24, 2020 Share Posted June 24, 2020 The reason the hitArea helps is because it uses that instead of searching through children to find the hittable areas. So if you require interactivity, hitAreas are the way to go. I'm not sure why this wasn't acceptable in your opening post? What issue were you having with them? They work on all events. In any case, for really complex scenes, what you could do is have an extra layer, where you put either transparent sprites, graphics or containers with their own hitarea - which are purely for hit areas for the scene below? So instead of stage --> armatureDisplay you have stage --> interactivity layer --> armatureDisplay Nothing below interactivity layer is actually interactive... just items in the layer above, which consist of very simple objects which mirror the size and shape of what is below. Quote Link to comment Share on other sites More sharing options...
clifftm Posted June 24, 2020 Author Share Posted June 24, 2020 14 minutes ago, Exca said: The interaction plugin tries to find target it moves over on Yes, but how to disable that? Let IM found target only when mousedown, not on every pointer move. Setting interactiveChildren to armature makes it not responsible for clicks at all, even if armature.interactive = true; Again. You have 900 robots from pixi example, that have different animations (idle, run, jump, death). You need determine what robot was clicked. They can overlap if their position is near. So creating a container around each robot like this: let boundContainer = new PIXI.Container(); boundContainer.interactive = true; boundContainer.interactiveChildren = false; boundContainer.addChild(armatureDisplay); boundContainer.position.set( lb.width*i*armatureDisplay.scale.x*0.5, lb.height*j*armatureDisplay.scale.y*0.5); boundContainer.hitArea = boundContainer.getLocalBounds(); boundContainer.on('click',()=>{console.log(i*10+j)}); app.stage.addChild(boundContainer); You cant determine which robot was actually clicked left or right or upper or you just clicked in black space: That will appear even with "interactivity layer". The animations can be complex, for example like death animation, and that bound box container should be recalculated every armature animation frame. I have nothing against how IM determine object on click. Let him check all objects. But figuratively i'm interacting with robots only with mouseclick, and IM forcibly checks hitArea on every mousemove. I can give you another analogy of what's happening. You have an antivirus with a button => onClick(check all computer for viruses). When pressing it, the process is starting. At the same time that process will also starting on every mouse move. And you just recommend me to exclude all folders from checking or just to check parent forlders on the disk without subfolders on each mousemove. And I just want to check computer only by pressing a button Thanks Quote Link to comment Share on other sites More sharing options...
Exca Posted June 24, 2020 Share Posted June 24, 2020 If you dont have a need for pointer/touchmovement at all you could either fork the interactionmanager and use your own interactionplugin, remove the listeners or make the handling function do nothing. (game.renderer.plugins.interaction.processPointerMove = () => {} in v4, dont have a v5 project at hand to check how it would go there). Currently the interactionplugin does not have properties for ignoring certain events. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted June 24, 2020 Share Posted June 24, 2020 (edited) Its easy enough to override treeSearch in latest pixi-v5. There are so many ways to optimize that thing, but each one also has side-effects or deoptimizations in other cases, so we really cant just change default, that's why we prettied up the code for everyone to override for their game. If you happen to know how to optimize it for most of cases and not make code difficult - please share it, we are waiting for a hero. Edited June 24, 2020 by ivan.popelyshev Quote Link to comment Share on other sites More sharing options...
clifftm Posted June 24, 2020 Author Share Posted June 24, 2020 2 minutes ago, Exca said: game.renderer.plugins.interaction.processPointerMove = () => {} Yes, that's another variant of disabling event. But that 2 solutions looks like: "Doctor i have a bruise on the leg, can you help me?" "Sure, lets cut off your leg" Quote Link to comment Share on other sites More sharing options...
themoonrat Posted June 24, 2020 Share Posted June 24, 2020 19 hours ago, clifftm said: Found a solution but it seems very rude window.document.removeEventListener('mousemove', app.renderer.plugins.interaction.onPointerMove, true); window.document.removeEventListener('pointermove', app.renderer.plugins.interaction.onPointerMove, true); is there any way to do this more softly? From the comments... if you didn't want any move events in your game, then that is a reasonable way to do it. There's no simpler way either at a top level or on a per component level. It's that or digging into overriding functions, like Ivan suggests above, so that if the event is a move event, it's ignored if the component contains a flag or something Quote Link to comment Share on other sites More sharing options...
themoonrat Posted June 24, 2020 Share Posted June 24, 2020 1 minute ago, clifftm said: Yes, that's another variant of disabling event. But that 2 solutions looks like: "Doctor i have a bruise on the leg, can you help me?" "Sure, lets cut off your leg" I'm sorry you don't like the solutions, but it's not something that's really come up before that people haven't been satisfied covering with the existing methods. There is nothing more we can give here. Quote Link to comment Share on other sites More sharing options...
Exca Posted June 24, 2020 Share Posted June 24, 2020 Correct way would be to create your own version with a flag that does the ignoring. Then make a pull request to make it part of pixi if others see that it adds value. Quote Link to comment Share on other sites More sharing options...
clifftm Posted June 26, 2020 Author Share Posted June 26, 2020 (edited) On 6/24/2020 at 6:24 PM, ivan.popelyshev said: If you happen to know how to optimize it for most of cases and not make code difficult - please share it, we are waiting for a hero. For example, like this this.app.renderer.plugins.interaction.search.recursiveFindHit = function(interactionEvent, displayObject, func, hitTest, interactive) { let type = interactionEvent.data.originalEvent.type; if ((/.*(move|leave|out|over).*/.test(type) && displayObject.allowMove === false) || (/.*(up|down|click|cancel).*/.test(type) && displayObject.allowClick === false)) { return false; } else { return this.__proto__.recursiveFindHit.call(this, interactionEvent, displayObject, func, hitTest, interactive); } }; and then in the code you just need to this.instance.interactive = true; // enable interactive this.instance.allowMove = false; // ignore mouse moving this.instance.allowClick = true; // or just make it undefined. allow clicks Again. You have a dragonbone\spine robot with head, 2 hands, 2 legs, body and a gun = 7 mesh\sprites. You create 100x100 robots and just want to click on them and show alert(clicked robot #...) Every mouse move you will make tree traversal of all robots * 7 children, so 70000 checks if dispayobject.contains(cursor) Edited June 26, 2020 by clifftm ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.