Stalker Posted November 12, 2015 Share Posted November 12, 2015 Hi! I'm trying to create unit (mesh) selection as it is in various strategy games(AoE, CnC (attached image) ...).After some exploring, I've came to the following, but there are a couple of steps I don't know how to do: 1. Hook to events (OK - trivial)2. Draw lines using BABYLON.Mesh.CreateLines - at what position? Set LineMesh parent to camera? How to translate mouse position (scene.pointerX and Y) to world coordinates? Just draw rectangle and and set transformation matrix to identity (4x4)? Canvas 2d and 3d context can't be used together.3. Once that is known, visible meshes are selected with octree (frustum plane is created and used for selection via octree.select method). But frustum plane can be very small and very close, or very big and far away (but this it's probably solved at step 2) I haven't really got to point 3. (got stuck at 2) so it's only my speculation.I'm open to suggestions if there are any better options . Explanation for attached image for non strategy game players:Green rectangle was drawn simply clicking in one corner and dragging. It's always orthogonal to camera view and at the same position (also based on camera) even if camera is moved or rotated. Its rendered above everything and every unit inside is selected. Thanks! Quote Link to comment Share on other sites More sharing options...
Jaskar Posted November 13, 2015 Share Posted November 13, 2015 Hi Stalker! Step 1 : Good! Step 2 :Maybe you can "cheat', and draw a simple html div with borders, following the mouse coordinates ? Step 3 : (from http://answers.unity3d.com/questions/33901/view.html)Instead of trying to use a world-space selection box like taht, see if the objects' coordinates when converted to screen space are within the screen-space rectangle instead. Let us know if it's ok! And don't hesisate to share that with the community Quote Link to comment Share on other sites More sharing options...
Stalker Posted November 13, 2015 Author Share Posted November 13, 2015 Hi Jaskar! 2. I came to a similar idea and after some exploring found an example from user gwenael. He has two canvases one over another, bottom one for 3D graphics and top one for 2D, where he draws rectangles and lines. It's a cool idea, just haven't found any information yet about performance penalty, if it's negligible or not. 3. Also came across my mind, but goal is to have somewhere around 1k - 5k objects and would like to have quick access. Number isn't that big at all, but JavaScript isn't exactly known for speed. A hybrid way of using Octree would probably be using getVisibleObjects (or something similar I found somewhere in the docs) and filtering afterwards. I'll proceed in this direction and let you know with what I came up in the next few days (and I'm also open for countless of other suggestions, bad and good ones). Thank you very much for your help ! Quote Link to comment Share on other sites More sharing options...
Stalker Posted November 16, 2015 Author Share Posted November 16, 2015 At the end I did it as I wrote in my last post.2D Canvas overlaying 3D canvas where rectangle is drawn. The performance (frame time, render time, and potential FPS weren't affected), but the frame rate was slightly decreased (55-60fps) when rectangle was visible.All corners are then translated to 3D world coordinates (scene.pick method) (done when mouse button is released)All visible meshes (scene.getActiveMeshes) are stored into an array and filtered by:Name (to avoid skybox and ground)Checked if mesh is inside an rectangle using this. I'm sure the entire process can be speed up (a lot), but it will do for now. GameMonetize and iiceman 2 Quote Link to comment Share on other sites More sharing options...
Nikos123 Posted December 25, 2015 Share Posted December 25, 2015 At the end I did it as I wrote in my last post.2D Canvas overlaying 3D canvas where rectangle is drawn. The performance (frame time, render time, and potential FPS weren't affected), but the frame rate was slightly decreased (55-60fps) when rectangle was visible.All corners are then translated to 3D world coordinates (scene.pick method) (done when mouse button is released)All visible meshes (scene.getActiveMeshes) are stored into an array and filtered by:Name (to avoid skybox and ground)Checked if mesh is inside an rectangle using this. I'm sure the entire process can be speed up (a lot), but it will do for now.Thanks for sharing this, I will need some solution for my RTS game, although I'm not to keen on the complexity of needing another canvas to accomplish this. Are there any other options? Quote Link to comment Share on other sites More sharing options...
Stalker Posted December 28, 2015 Author Share Posted December 28, 2015 Hi!There always are other options , just that I haven't found any nice. One is definitely ordinary div element with absolute position and set width, height, left and right css properties (which is pretty straight forward). I was also thinking of doing everything inside BJS, but by my rough assessment it was way to complicated. Drawing a plane, parenting it to camera (depends on what kind of selection do you need), creating a render group so it's render above everything, and (probably) translating mouse coordinates to world and doing some sort of transformations so it's orthogonal to camera, keeping word coordinates after transformations... There might be a better way to do this, but didn't find it at the time. (All this is for a specific selection described at my first post). I went with another canvas because I will use it for additional 2D drawing, but it is possible that I will rewrite that part using an ordinary HTML elements. P.S.: I like what you've done so far, can't wait to see more . Nikos123 1 Quote Link to comment Share on other sites More sharing options...
Nikos123 Posted December 28, 2015 Share Posted December 28, 2015 Hi!There always are other options , just that I haven't found any nice. One is definitely ordinary div element with absolute position and set width, height, left and right css properties (which is pretty straight forward). I was also thinking of doing everything inside BJS, but by my rough assessment it was way to complicated. Drawing a plane, parenting it to camera (depends on what kind of selection do you need), creating a render group so it's render above everything, and (probably) translating mouse coordinates to world and doing some sort of transformations so it's orthogonal to camera, keeping word coordinates after transformations... There might be a better way to do this, but didn't find it at the time. (All this is for a specific selection described at my first post). I went with another canvas because I will use it for additional 2D drawing, but it is possible that I will rewrite that part using an ordinary HTML elements. P.S.: I like what you've done so far, can't wait to see more . Thanks for the Kudos, its bringing fun to the community that is one of the motivations for making such a game) I like the idea of using a div to draw the selector, I will investigate it. Quote Link to comment Share on other sites More sharing options...
Nikos123 Posted December 29, 2015 Share Posted December 29, 2015 At the end I did it as I wrote in my last post.2D Canvas overlaying 3D canvas where rectangle is drawn. The performance (frame time, render time, and potential FPS weren't affected), but the frame rate was slightly decreased (55-60fps) when rectangle was visible.All corners are then translated to 3D world coordinates (scene.pick method) (done when mouse button is released)All visible meshes (scene.getActiveMeshes) are stored into an array and filtered by:Name (to avoid skybox and ground)Checked if mesh is inside an rectangle using this. I'm sure the entire process can be speed up (a lot), but it will do for now.I decided to go for this method as I will also use canvas for drawing stuff like hit points from units taking damage and perhaps health indicators. Quote Link to comment Share on other sites More sharing options...
snot224 Posted December 31, 2015 Share Posted December 31, 2015 Hi all,for my strategy game I create a selection square that work very well, here the algorithm :1) on mouse down a ) place a DIV on the mouse start (SourisPoint1) b ) save babylon PICK point under the mouse (CanvasPoint1)2) on mouse move a ) draw selection DIV with current mouse position3) on mouse up a ) save babylon PICK point where is mouse (CanvasPoint2) b ) save mouse position (SourisPoint2) c) proceed selectionHere algorithme for selection :1) create 2 more PICK point to make a 3D square on BABYLON Canvas for that : a ) calculate the distance between SourisPoint1.x and SourisPoint2.x b ) calculate the distance between SourisPoint1.y and SourisPoint2.y c ) calculate the x and y for SourisPoint3 and SourisPoint4 (ex. SourisPoint1.x + distanceX, SourisPoint1.y + distanceY) WARNING is depending of direction of selection square was made d ) with SourisPoint3 and SourisPoint4, create 2 PICK point in babylon canvas2) calculate all lenghts of the square in the canvas (pythagore)3) calculate the surface of the 2 triangles making that square (Surface1 and Surface2)4) calculate the total surface of the 3D square (addition of the 2 triangles surfaces) (SurfaceSquare)5) for each unit a ) calculate the surface of each triangle between position of unit and each points of the 3D square (Surface1, Surface2, Surface3, Surface4) b ) calculate total surface of all that triangles (SurfaceUnit)6) If SurfaceUnit == SurfaceSquare, so unit is in the selection square.In attachment a picture representing all etapesHope it will help. Quote Link to comment Share on other sites More sharing options...
Nikos123 Posted December 31, 2015 Share Posted December 31, 2015 Thanks snot, do you have real js code for this you can share? Quote Link to comment Share on other sites More sharing options...
snot224 Posted December 31, 2015 Share Posted December 31, 2015 Yes I could paste here the code, but please be carefull this will be not workable because I use MY class names, and MY naming rulesIn your HTML<style> div.rectangleSelection { position :absolute; display :none; width :0px; height :0px; top :0px; left :0px; background-color :rgba(0,50,70,0.3); border :1px solid white; box-shadow :0 0 5px #FFF; z-index :3; }</style><div id="rectangleSelection" class="rectangleSelection"></div><canvas id="nkoCanvas"></canvas>In your event listener WARNING I USE MY "controleurInput" class here !!!// On mouse move// Saving mouse coordinate// If an action was registred in "controleurInput" do itwindow.addEventListener("mousemove", function(e){ controleurInput.sourisX = e.pageX; controleurInput.sourisY = e.pageY; if (controleurInput.action) controleurInput.doAction();});// On mouse down, if it's left button, put action "SelectionStart" in "ControleurInput"// and Do itwindow.addEventListener("mousedown", function(e){ switch (e.button) { case 0: controleurInput.action = "selectionStart"; controleurInput.doAction(); }});// On mouse up, if "controleurInput" is doing action of "selectionEnCours"// It mean we must stop selection, so we put action of "SelectionFin" in "controleurInput"window.addEventListener("mouseup", function(e){ if (controleurInput.action == "selectionEnCours") { controleurInput.action = "selectionFin"; controleurInput.doAction(); }});In your "controleurInput" class, we update position and we do actioncontroleurInput.prototype.doAction = function(){ switch (this.action) { case 'selectionStart': this.actualisePosition(); controleurObjet.doAction('selectionStart'); this.action = "selectionEnCours"; break; case 'selectionEnCours': controleurObjet.doAction('selectionEnCours'); break; case 'selectionFin': this.actualisePosition(); controleurObjet.doAction('selectionFin'); this.action = ""; break; }}// We save the current canvas positioncontroleurInput.prototype.actualisePosition = function(){ var pickResult = scene.pick(scene.pointerX, scene.pointerY,function(mesh) { return mesh.name == "floor"; }); if (pickResult.hit) { // Nouvelles positions this.posX = pickResult.pickedPoint.x; this.posZ = pickResult.pickedPoint.z; }}Here in the "controleurObjet" class that control all object in the game.controleurObjet.prototype.doAction = function(action){ switch (action) { case 'selectionStart': this.rectangleSelection['x1'] = controleurInput.posX; this.rectangleSelection['z1'] = controleurInput.posZ; this.rectangleSelection['sx1'] = controleurInput.sourisX; this.rectangleSelection['sy1'] = controleurInput.sourisY; (function($) { $('#rectangleSelection').css({ 'top' :controleurInput.sourisY-5, 'left' :controleurInput.sourisX-5 }); $('#rectangleSelection').fadeIn(200); })(jQuery); break; case 'selectionEnCours': this.selectionEnCours(); break; case 'selectionFin': this.rectangleSelection['x2'] = controleurInput.posX; this.rectangleSelection['z2'] = controleurInput.posZ; this.rectangleSelection['sx2'] = controleurInput.sourisX; this.rectangleSelection['sy2'] = controleurInput.sourisY; (function($) { $('#rectangleSelection').fadeOut(200); $('#rectangleSelection').css({ 'top' :0, 'left' :0, 'width' :0, 'height' :0 }); })(jQuery); this.selection(); break; }}// This function only place selection square and resize it when mouse movingcontroleurObjet.prototype.selectionEnCours = function(){ var widthRectangle = Math.abs(this.rectangleSelection['sx1'] - controleurInput.sourisX); var heightRectangle = Math.abs(this.rectangleSelection['sy1'] - controleurInput.sourisY); (function($) { $('#rectangleSelection').css({ 'width' : widthRectangle-5, 'height' : heightRectangle-5 }); })(jQuery); // On recale la div suivant si on séléctionne depuis la gauche vers la droite, ou de bas en haut // Depending that if you select from left, right, up or down if ((controleurInput.sourisX <= this.rectangleSelection['sx1']) && (controleurInput.sourisY >= this.rectangleSelection['sy1'])) { (function($) { $('#rectangleSelection').css({ 'width' : widthRectangle-5, 'height' : heightRectangle-5, 'left' : controleurInput.sourisX+5 }); })(jQuery); } else if ((controleurInput.sourisY <= this.rectangleSelection['sy1']) && (controleurInput.sourisX >= this.rectangleSelection['sx1'])) { (function($) { $('#rectangleSelection').css({ 'width' : widthRectangle-5, 'height' : heightRectangle-5, 'top' : controleurInput.sourisY+5 }); })(jQuery); } else if ((controleurInput.sourisY < this.rectangleSelection['sy1']) && (controleurInput.sourisX < this.rectangleSelection['sx1'])) { (function($) { $('#rectangleSelection').css({ 'width' : widthRectangle-5, 'height' : heightRectangle-5, 'left' : controleurInput.sourisX+5, 'top' : controleurInput.sourisY+5 }); })(jQuery); }}// Here the real algorithme of selectioncontroleurObjet.prototype.selection = function(){ // ************************************************** Rectangle vue page var sx1 = this.rectangleSelection['sx1']; var sx2 = this.rectangleSelection['sx2']; var sy1 = this.rectangleSelection['sy1']; var sy2 = this.rectangleSelection['sy2']; var dx = sx2-sx1; var dy = sy2-sy1; var __SELECTION_ADOUCIE__ = 3; // Distance entre X1souris et X2Souris, hypothénus // Distance between X1Souris and X2Souris var d = Math.sqrt( (dy*dy)+(dx*dx) ); // Les deux autres cotés du rectangle // The 2 overs points of the square inside the canvas var pickResult3 = scene.pick(sx1+dx, sy1); var pickResult4 = scene.pick(sx2-dx, sy2); // ************************************************** Rectangle vue scene // Coordonnées point // All point coordinate (inside the canvas) var x1 = Math.round(this.rectangleSelection['x1']*1000)/1000; var z1 = Math.round(this.rectangleSelection['z1']*1000)/1000; var x2 = Math.round(this.rectangleSelection['x2']*1000)/1000; var z2 = Math.round(this.rectangleSelection['z2']*1000)/1000; var x3 = Math.round(pickResult3.pickedPoint.x*1000)/1000; var z3 = Math.round(pickResult3.pickedPoint.z*1000)/1000; var x4 = Math.round(pickResult4.pickedPoint.x*1000)/1000; var z4 = Math.round(pickResult4.pickedPoint.z*1000)/1000; // Calcul des longueurs des 4 cotés du rectangle du canvas // Square lenght inside canvas var a = Math.sqrt( ((x3 - x2)*(x3 - x2))+((z3 - z2)*(z3 - z2)) ); var b = Math.sqrt( ((x3 - x1)*(x3 - x1))+((z3 - z1)*(z3 - z1)) ); var i = Math.sqrt( ((x2 - x4)*(x2 - x4))+((z2 - z4)*(z2 - z4)) ); var j = Math.sqrt( ((x4 - x1)*(x4 - x1))+((z4 - z1)*(z4 - z1)) ); // Diagonale var h = Math.sqrt( ((x2 - x1)*(x2 - x1))+((z2 - z1)*(z2 - z1)) ); // Calcul des perimetres // perimeter of the 2 triangles var per1 = (a + b + h)/2; var per2 = (i + j + h)/2; // Surface var Ss = Math.round((Math.sqrt(per1*(per1-a)*(per1-*(per1-h))+Math.sqrt(per2*(per2-i)*(per2-j)*(per2-h)))*100)/100; var thisObjet = this; (function($) { // Détermine si l'unité est dans le rectangle // If unit is inside the square WARNING I use a SELECTION_MAX to avoid too much selection $.each(thisObjet.tabUnitesEquipe,function(id,selectedUnit) { if ((thisObjet.tabSelection.length < thisObjet.__SELECTION_MAX__)&&(selectedUnit.mesh.isVisible)) { // Coordonnée unité var xu = selectedUnit.mesh.position.x; var zu = selectedUnit.mesh.position.z; // Calcul longueur // Lenght between unit and all square's points var m = Math.sqrt( ((xu - x1)*(xu - x1))+((zu - z1)*(zu - z1)) ); var n = Math.sqrt( ((xu - x3)*(xu - x3))+((zu - z3)*(zu - z3)) ); var o = Math.sqrt( ((xu - x2)*(xu - x2))+((zu - z2)*(zu - z2)) ); var p = Math.sqrt( ((xu - x4)*(xu - x4))+((zu - z4)*(zu - z4)) ); // Calcul des périmètres // Perimeter var per3 = (m + p + j)/2; var per4 = (m + n + b)/2; var per5 = (n + o + a)/2; var per6 = (o + p + i)/2; // Calcul des surfaces var St1 = Math.sqrt(per3*(per3-m)*(per3-p)*(per3-j)); var St2 = Math.sqrt(per4*(per4-m)*(per4-n)*(per4-); var St3 = Math.sqrt(per5*(per5-n)*(per5-o)*(per5-a)); var St4 = Math.sqrt(per6*(per6-o)*(per6-p)*(per6-i)); var St = Math.round((St1 + St2 + St3 + St4)*100)/100; if (St == Ss) { thisObjet.tabSelection.push(selectedUnit.selection()); } } }); })(jQuery);}Hope it could help Quote Link to comment Share on other sites More sharing options...
Nikos123 Posted December 31, 2015 Share Posted December 31, 2015 Cool man thanks for this. Is your game in prod? Quote Link to comment Share on other sites More sharing options...
snot224 Posted December 31, 2015 Share Posted December 31, 2015 Cool man thanks for this. Is your game in prod? Yes, still in prod Quote Link to comment Share on other sites More sharing options...
Jaskar Posted January 5, 2016 Share Posted January 5, 2016 Yes, still in prod Link please ? 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.