From d69c194cd3d22401d028b87132add229b4d224a9 Mon Sep 17 00:00:00 2001 From: bach Date: Thu, 29 Jun 2023 17:15:32 +0200 Subject: [PATCH] #2150 map improvement --- src/components/ConcernementMapItem.vue | 355 ++++++++++++++++++++----- 1 file changed, 283 insertions(+), 72 deletions(-) diff --git a/src/components/ConcernementMapItem.vue b/src/components/ConcernementMapItem.vue index fd974bd..81e8ce9 100644 --- a/src/components/ConcernementMapItem.vue +++ b/src/components/ConcernementMapItem.vue @@ -111,14 +111,22 @@ export default { if(n){ // opened this.openClose(true); }else{ // closed - this.openClose(false) + this.openClose(false); + } + }, + deep: true + }, + opened_concernement: { + handler (n, o) { + if (!n) { + this.applyShuffleForces(); } }, deep: true }, map_mode: { handler (n, o) { - console.log('watch map_mode', o, n); + // console.log('watch map_mode', o, n); if (n === 'terraindevie' && !this.opened_concernement) { this.applyShuffleForces(); // apply a little force to check the map when returning to terrain de vie } @@ -297,10 +305,27 @@ export default { }, getRandomPos(){ let pad = 200; - return { - x: pad + this.ray/2 + Math.random()*(this.canvas.width - this.ray - pad), - y: pad + this.ray/2 + Math.random()*(this.canvas.height - this.ray - pad) - }; + // if (this.concernement.id === 56) { + // return { + // x: Math.random() > 0.5 ? pad : this.canvas.width - pad, + // y: pad + this.ray/2 + Math.random()*(this.canvas.height - this.ray - pad) + // }; + // } else { + return { + x: pad + this.getGaussianRandom()*(this.canvas.width - pad*2), + y: pad + this.getGaussianRandom()*(this.canvas.height - pad*2) + }; + // } + }, + getGaussianRandom(){ + // INFO https://stackoverflow.com/a/49434653 + let u = 0, v = 0; + while(u === 0) u = Math.random(); //Converting [0,1) to (0,1) + while(v === 0) v = Math.random(); + let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v ); + num = num / 10.0 + 0.5; // Translate to 0 -> 1 + if (num > 1 || num < 0) return this.getGaussianRandom() // resample between 0 and 1 + return num }, initMatterBody (){ @@ -309,9 +334,10 @@ export default { if (!this.body) { // console.log('concernementItem creating body'); - // https://github.com/liabru/matter-attractors/issues/8 - // https://github.com/liabru/matter-attractors/blob/master/index.js - // MatterAttractors.Attractors.gravityConstant = -5; + // INFO https://github.com/liabru/matter-attractors/issues/8 + // INFO https://github.com/liabru/matter-attractors/blob/master/index.js + // INFO https://github.com/liabru/matter-attractors/blob/master/build/matter-attractors.js#L180 + MatterAttractors.Attractors.gravityConstant = -20; // Create parts of the body : main big circle & entities this.body_parts = [ @@ -321,6 +347,12 @@ export default { }) ]; + // map a range of numbers to another range of numbers + // INFO https://stackoverflow.com/a/46462321 + let entite_range = [3, 100]; + let mass_range = [5,15]; + let mass = mass_range[0] + (this.entites.length - entite_range[0]) * (mass_range[1] - mass_range[0]) / (entite_range[1] - entite_range[0]); + // create the body this.body = Matter.Body.create({ parts: this.body_parts, @@ -328,16 +360,41 @@ export default { id: this.concernement.id, frictionAir: 0, // mass: Math.pow(3, this.entites.length), - mass: 10, + // mass: 10, + mass: mass, restitution: 0.15, collisionFilter: { group: -1 }, plugin: { attractors: [ - // there is a built in helper function for Newtonian gravity! - // you can find out how it works in index.js + // // there is a built in helper function for Newtonian gravity! + // // you can find out how it works in index.js MatterAttractors.Attractors.gravity + + // function(bodyA, bodyB) { + // var force = { + // x: (bodyA.position.x - bodyB.position.x) * 1e-6, + // y: (bodyA.position.y - bodyB.position.y) * 1e-6 + // } + // // apply force to both bodies + // Matter.Body.applyForce(bodyA, bodyA.position, force); + // Matter.Body.applyForce(bodyB, bodyB.position, Matter.Vector.neg(force)); + // } + + // INFO https://github.com/liabru/matter-attractors/blob/master/build/matter-attractors.js#L192 + // function (bodyA, bodyB){ + // // use Newton's law of gravitation + // var bToA = Matter.Vector.sub(bodyB.position, bodyA.position), + // distanceSq = Matter.Vector.magnitudeSquared(bToA) || 0.0001, + // normal = Matter.Vector.normalise(bToA), + // magnitude = -MatterAttractors.Attractors.gravityConstant * (bodyA.mass * bodyB.mass / distanceSq), + // force = Matter.Vector.mult(normal, magnitude); + + // // to apply forces to both bodies + // Matter.Body.applyForce(bodyA, bodyA.position, Matter.Vector.neg(force)); + // Matter.Body.applyForce(bodyB, bodyB.position, force); + // } ] } }); @@ -1143,18 +1200,17 @@ export default { if (this.opened_concernement.id !== this.id) { this.pushAside() } + } else if (this.map_mode === 'puissancedagir' + || this.map_mode === 'action' + || this.map_mode === 'doleancer'){ // apply focus forces : move unfocused on the sides and focused on the center + this.applyFocusForces(); // } else { - // apply focus forces : move unfocused on the sides and focused on the center - if (this.map_mode === 'action' - || this.map_mode === 'puissancedagir' - || this.map_mode === 'doleancer'){ - this.applyFocusForces(); // - } + this.applyNormalForces(); // if terrain de vie apply force to gently reject items from the sides and so create a continuasly mvmt } // reset all matter rotation forces otherwise items will spin when colide - Matter.Body.setAngle(this.body, 0); - Matter.Body.setAngularSpeed(this.body, 0); + // Matter.Body.setAngle(this.body, 0); + // Matter.Body.setAngularSpeed(this.body, 0); }, applyFocusForces(){ if(!this.isFocused()) { @@ -1163,12 +1219,21 @@ export default { this.bringToCenter() } }, + isFocused(){ + return this.map_mode === 'terraindevie' + || (this.map_mode === 'action' && this.concernement.has_agissantes) + || (this.map_mode === 'puissancedagir' && this.concernement.has_puissancedagir) + || (this.map_mode === 'doleancer' && this.concernement.has_doleance); + }, pushAside(){ // console.log('pushAside', this.opened_concernement); // apply a force in direction of one side or an other depending of the start position // the force is exponentialy proportional to the distance from the side // INFO logarithmic force : https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249 - let pseudo_center_x = (this.canvas.width - this.cartouch_width) / 2; + // TODO cartouch width should change regarding actual cartouch is opened or not (and how many cartouch are opened) + let pseudo_center_x = this.opened_concernement + ? (this.canvas.width - this.cartouch_width) / 2 + : this.canvas.width / 2; // get the direction to the closest side let dir = this.pos.x > pseudo_center_x ? 1 // to the right @@ -1202,81 +1267,233 @@ export default { y: 0 } ); + + this.body.frictionAir = 0.01; }, bringToCenter(){ // bring to the centre - let pseudo_center_x = (this.canvas.width - this.cartouch_width) / 2; - // get the direction to the centre + // apply a force in direction of one side or an other depending of the start position + // the force is exponentialy inversed proportional to the distance from the side + // INFO logarithmic force : https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249 + // TODO cartouch width should change regarding actual cartouch is opened or not (and how many cartouch are opened) + let pseudo_center_x = this.opened_concernement + ? (this.canvas.width - this.cartouch_width) / 2 + : this.canvas.width / 2; let dir = this.pos.x > pseudo_center_x ? -1 // to left : 1; // to right - // max & min item position - let minp = 0; - let maxp = dir < 0 - ? this.canvas.width - pseudo_center_x - : pseudo_center_x; - // max and min force - let minf = 0; - let maxf = 1; - // scale factor - let scale = (maxf-minf) / (maxp-minp); // get the inversed distance from the side let dist = dir < 0 ? this.pos.x - pseudo_center_x : pseudo_center_x - this.pos.x; - let x_force = Math.exp(minf + scale*(dist-minp)) * dir; + if (dist > this.canvas.width/6) { // apply decreasing forces and increasing friction air only out of center to let the items float in the center zone + // max & min item position + let minp = 0; + let maxp = dir < 0 + ? this.canvas.width - pseudo_center_x + : pseudo_center_x; + + // X force decrsinsing near the center + // max and min force + let xminf = 0; + let xmaxf = 1 + Math.random()*4; + // scale factor + let xscale = (xmaxf-xminf) / (maxp-minp); + let x_force = Math.exp(xminf + xscale*(dist-minp)) * dir; + let ori_pos = dir < 0 + ? {x:this.canvas.width, y:this.body.position.y} + : {x:0, y:this.body.position.y}; + Matter.Body.applyForce( + this.body, + ori_pos, + { + x: x_force, + y: 0 + } + ); + + // Friction air fa (increasing near the center) + let fa_minf = 0; + let fa_maxf = 6; + // scale factor + let fa_scale = (fa_maxf-fa_minf) / (maxp-minp); + let fa = Math.exp(fa_minf + fa_scale*(dist-minp)*-1); + this.body.frictionAir = fa; + + console.log(`bringToCenter dist:${dist}, x_force:${x_force}, friction air:${fa}`); + } else { // in the ceneter zone let items floats freely + let velocity = Matter.Body.getVelocity(this.body); + let velocityx = Math.abs(velocity.x); + // map a range of numbers to another range of numbers + // INFO https://stackoverflow.com/a/46462321 + let velocity_range = [50, 1000]; + let fa_range = [0,3]; + let fa = fa_range[0] + (velocityx - velocity_range[0]) * (fa_range[1] - fa_range[0]) / (velocity_range[1] - velocity_range[0]); + console.log(`bringToCenter velocity.x:${velocity.x}, fa:${fa}`); - let ori_pos = dir < 0 - ? {x:this.canvas.width, y:this.body.position.y} - : {x:0, y:this.body.position.y}; - // let x_force = Math.pow(dist/800,10) * dir; - - this.body.frictionAir = 0.05; + this.body.frictionAir = fa; + } - Matter.Body.applyForce( - this.body, - ori_pos, - { - x: x_force, - y: 0 - } - ); }, applyShuffleForces() { + // console.log('applyShuffleForces'); // var dist, dir, x_velocity; // dir = this.pos.x > this.canvas.width/2 ? -1 : 1; // get the direction to the centre // dist = (dir < 0 ? this.pos.x - this.canvas.width/2 : this.canvas.width/2 - this.pos.x); // get the distance from the side // x_velocity = Math.pow(dist/650,10) * dir; - let pseudo_center_x = (this.canvas.width - this.cartouch_width) / 2; + // TODO cartouch width should change regarding actual cartouch is opened or not (and how many cartouch are opened) + let pseudo_center_x = this.opened_concernement + ? (this.canvas.width - this.cartouch_width) / 2 + : this.canvas.width / 2; // get the direction to the centre let dir = this.pos.x > pseudo_center_x ? -1 // to left : 1; // to right - // max & min item position - let minp = 0; - let maxp = dir < 0 - ? this.canvas.width - pseudo_center_x - : pseudo_center_x; - // max and min force - let minf = 0; - let maxf = 10; - // scale factor - let scale = (maxf-minf) / (maxp-minp); // get the inversed distance from the side let dist = dir < 0 + ? this.pos.x - pseudo_center_x + : pseudo_center_x - this.pos.x; + + if (dist > this.canvas.width/6) { // apply decreasing forces and increasing friction air only out of center to let the items float in the center zone + // max & min item position + let minp = 0; + let maxp = dir < 0 + ? this.canvas.width - pseudo_center_x + : pseudo_center_x; + + // X max and min force + let xminf = 0; + let xmaxf = 4 + Math.random()*3; + // scale factor + let xscale = (xmaxf-xminf) / (maxp-minp); + + let x_velocity = Math.exp(xminf + xscale*(dist-minp))*dir; + + // let y_velocity = 30 + Math.random() * 50; + // y_velocity = Math.random() > 0.5 ? -y_velocity : y_velocity; + // X max and min force + let yminf = 1; + let ymaxf = 2 + Math.random()*4; + // scale factor + let yscale = (ymaxf-yminf) / (maxp-minp); + + let y_velocity = Math.exp(yminf + yscale*(dist-minp)) * (Math.random() > 0.5 ? 1 : -1); // let ori_pos = dir < 0 + + // ? {x:this.canvas.width, y:this.body.position.y} + // : {x:0, y:this.body.position.y}; + // let x_force = Math.pow(dist/800,10) * dir; + console.log(`applyShuffleForces dir:${dir}, maxp:${maxp}, dist:${dist}, x_velocity:${x_velocity}, y_velocity:${y_velocity}`); + Matter.Body.setVelocity(this.body, {x: x_velocity, y: y_velocity}); + } else { // if in center zone real shuffle velocity + // x_velocity = -50 + Math.random()*100; + // y_velocity = -50 + Math.random()*100; + // this.setInitBodyVelocity(); + } + + this.body.frictionAir = 0.01; + }, + applyNormalForces () { + // bring gently to the centre + // apply a force in direction of one side or an other depending of the start position + // the force is exponentialy inversed proportional to the distance from the side + // INFO logarithmic force : https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249 + // TODO cartouch width should change regarding actual cartouch is opened or not (and how many cartouch are opened) + // X + let pseudo_center_x = this.opened_concernement + ? (this.canvas.width - this.cartouch_width) / 2 + : this.canvas.width / 2; + let xdir = this.pos.x > pseudo_center_x + ? -1 // to left + : 1; // to right + // get the inversed distance from the side + let xdist = xdir < 0 ? this.pos.x - pseudo_center_x : pseudo_center_x - this.pos.x; - let x_velocity = Math.exp(minf + scale*(dist-minp)); + // Y + let pseudo_center_y = this.canvas.height / 2; + let ydir = this.pos.y > pseudo_center_y + ? -1 // to top + : 1; // to bottom + // get the inversed distance from the side + let ydist = ydir < 0 + ? this.pos.y - pseudo_center_y + : pseudo_center_y - this.pos.y; - let y_velocity = -10 + Math.random() * 10; - // let ori_pos = dir < 0 - // ? {x:this.canvas.width, y:this.body.position.y} - // : {x:0, y:this.body.position.y}; - // let x_force = Math.pow(dist/800,10) * dir; + let k = 4; + if (xdist > this.canvas.width/k || ydist > this.canvas.height/k) { // apply decreasing forces and increasing friction air only out of center to let the items float in the center zone + // max and min force + let minf = 0; + let maxf = 0.1; + + // X + // max & min item position + let xminp = 0; + let xmaxp = xdir < 0 + ? this.canvas.width - pseudo_center_x + : pseudo_center_x; + // X force decrsinsing near the center + // scale factor + let xscale = (maxf-minf) / (xmaxp-xminp); + let x_force = Math.exp(minf + xscale*(xdist-xminp)) * xdir; + let xori_pos = xdir < 0 + ? {x:this.canvas.width, y:this.body.position.y} + : {x:0, y:this.body.position.y}; + Matter.Body.applyForce( + this.body, + xori_pos, + { + x: x_force, + y: 0 + } + ); + + // Y + // max & min item position + let yminp = 0; + let ymaxp = ydir < 0 + ? this.canvas.height - pseudo_center_y + : pseudo_center_y; + // X force decrsinsing near the center + // scale factor + let yscale = (maxf-minf) / (ymaxp-yminp); + let y_force = Math.exp(minf + yscale*(ydist-xminp)) * ydir; + let yori_pos = ydir < 0 + ? {x:this.body.position.x, y:this.canvas.height} + : {x:this.body.position.x, y:0}; + Matter.Body.applyForce( + this.body, + yori_pos, + { + x: 0, + y: y_force + } + ); + + // // Friction air fa (increasing near the center) + // let fa_minf = 0; + // let fa_maxf = 6; + // // scale factor + // let fa_scale = (fa_maxf-fa_minf) / (maxp-minp); + // let fa = Math.exp(fa_minf + fa_scale*(dist-minp)*-1); + // this.body.frictionAir = fa; + + // console.log(`bringToCenter dist:${xdist}, x_force:${x_force}`); + } else { // in the ceneter zone let items floats freely + // let velocity = Matter.Body.getVelocity(this.body); + // let velocityx = Math.abs(velocity.x); + // // map a range of numbers to another range of numbers + // // INFO https://stackoverflow.com/a/46462321 + // let velocity_range = [50, 1000]; + // let fa_range = [0,3]; + // let fa = fa_range[0] + (velocityx - velocity_range[0]) * (fa_range[1] - fa_range[0]) / (velocity_range[1] - velocity_range[0]); + // console.log(`bringToCenter velocity.x:${velocity.x}, fa:${fa}`); + + // this.body.frictionAir = fa; + this.body.frictionAir = 0.1; + } - Matter.Body.setVelocity(this.body, {x: x_velocity, y: y_velocity}); }, onAfterEngineUpdate (event) { // respawn element if outside screen @@ -1294,12 +1511,6 @@ export default { // this.draw() this.handlePaperVisibility() }, - isFocused(){ - return this.map_mode === 'terraindevie' - || (this.map_mode === 'action' && this.concernement.has_agissantes) - || (this.map_mode === 'puissancedagir' && this.concernement.has_puissancedagir) - || (this.map_mode === 'doleancer' && this.concernement.has_doleance); - }, }, render() { // console.log('render()', this.ctx);