Home > OS >  Limit dragged line to an arc / radius of a given length
Limit dragged line to an arc / radius of a given length

Time:10-26

I'm currently using Image showing the line being dragged, with a limiting arc where the drawing of the line stops, but the mouse can carry on.

The issue is that I suspect this is VERY MATHS and I am very, very weak with maths. Could anyone explain like I’m five what I need to do to my code to achieve this?

Edit: Adding code in a snippet here, as requested:

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 400,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var path;
var curve;
var graphics;

var game = new Phaser.Game(config);

function preload() {
    this.load.spritesheet('dragcircle', 'https://labs.phaser.io/assets/sprites/dragcircle.png', { frameWidth: 16 });
}

function create() {
    graphics = this.add.graphics();

    path = { t: 0, vec: new Phaser.Math.Vector2() };

    curve = new Phaser.Curves.Line([ 400, 390, 300, 230 ]);

    var point0 = this.add.image(curve.p0.x, curve.p0.y, 'dragcircle', 0);
  
    var point1 = this.add.image(curve.p1.x, curve.p1.y, 'dragcircle', 0).setInteractive();
  
    point1.setData('vector', curve.p1);

    this.input.setDraggable(point1);

    this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
        gameObject.x = dragX;
        gameObject.y = dragY;
      
        gameObject.data.get('vector').set(dragX, dragY);
    });

    this.input.on('dragend', function (pointer, gameObject) {
      let distance = Phaser.Math.Distance.Between(curve.p0.x, curve.p0.y, curve.p1.x, curve.p1.y);
      console.log(distance);
    });
}

function update() {
    graphics.clear();
    graphics.lineStyle(2, 0xffffff, 1);

    curve.draw(graphics);

    curve.getPoint(path.t, path.vec);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.55.2/phaser.min.js"></script>

CodePudding user response:

Yes, you might needs some math, but phaser has most of the needed functions, will do the heavy lifting.

The main idea is

  1. define a maxLength
  2. get the the new point on drag, and create a real Phaser Vector2
    • here is some math is needed, to create the vector, just calculate destination point minus origin point
      new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y) (origin point being the starting point of the desired vector, and destination point being the mouse pointer)
  3. calculate the length of the created vector and compare it with the maxLength
    • if too long adjust the vector, with the handy function setLength (link to the documentation, this is where you would have needed math, but thankfully Phaser does it for us)
  4. set the new coordinates for point1 and the curve endpoint

Here a quick demo (based on your code):

var config = {
    type: Phaser.AUTO,
    width: 500,
    height: 170,
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var curve;
var graphics;

var game = new Phaser.Game(config);

function preload() {
    this.load.spritesheet('dragcircle', 'https://labs.phaser.io/assets/sprites/dragcircle.png', { frameWidth: 16 });
}

function create() {
    graphics = this.add.graphics();

    curve = new Phaser.Curves.Line([ config.width/2, config.height - 20, config.width/2, 10 ]);

    // define a length, could be a global constant
    let maxLength = curve.p0.y - curve.p1.y;

    var point0 = this.add.image(curve.p0.x, curve.p0.y, 'dragcircle', 0);
    var point1 = this.add.image(curve.p1.x, curve.p1.y, 'dragcircle', 0).setInteractive();
  
    this.input.setDraggable(point1);
    
    // Just add for Debug Info
    this.add.circle(curve.p0.x, curve.p0.y, maxLength)
      .setStrokeStyle(1, 0xffffff, .5)

    this.input.on('drag', function (pointer) {
        
        let vector = new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y);
        let distance = Phaser.Math.Distance.Between( point0.x, point0.y, pointer.x, pointer.y);
        
        if(distance > maxLength){
            vector.setLength(maxLength);
        }
        
        point1.x = point0.x   vector.x;
        point1.y = point0.y   vector.y;     
        curve.p1.x = point1.x;
        curve.p1.y = point1.y;

    });

    // NOT REALLY NEEDED
    /*this.input.on('dragend', function (pointer, gameObject) {
      let distance = Phaser.Math.Distance.Between(curve.p0.x, curve.p0.y, curve.p1.x, curve.p1.y);
      console.log(distance);
    });*/
}

function update() {
    graphics.clear();
    graphics.lineStyle(2, 0xffffff, 1);
    curve.draw(graphics);
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

Optional - Code Version using Phaser.GameObjects.Line:

This uses less code, and thanks to the Line GameObject (link to Documentation), you can directly use the vector to update the line, and also don't need the update function, graphics and so.

const config = {
    type: Phaser.CANVAS,
    width: 500,
    height: 160,
    scene: {
        create
    }
};

const game = new Phaser.Game(config);
const MAX_LINE_LENGTH = 100;

function create() {

    let points = [ {x: config.width/2, y: config.height - 20}, {x: config.width/2, y: config.height - 120} ];
    
    let point0 = this.add.circle(points[0].x, points[0].y, 6)
        .setStrokeStyle(4, 0xff0000);
    let point1 = this.add.circle(points[1].x, points[1].y, 6)
        .setStrokeStyle(4, 0xff0000)
        .setInteractive();
  
    this.input.setDraggable(point1);
    
        // Just add for Debug Info
    this.add.circle(point0.x, point0.y, MAX_LINE_LENGTH)
      .setStrokeStyle(1, 0xffffff, .5);
    
    let line = this.add.line(points[0].x, points[0].y, 0, 0, 0, -100, 0x00ff00)
        .setOrigin(0);
  
    this.input.on('drag', function (pointer) {
        
        let vector = new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y);
        let distance = Phaser.Math.Distance.Between( point0.x, point0.y, pointer.x, pointer.y);
        
        if(distance > MAX_LINE_LENGTH){
            vector.setLength(MAX_LINE_LENGTH);
        }
        
        point1.x = point0.x   vector.x;
        point1.y = point0.y   vector.y;     
      
        line.setTo(0, 0, vector.x, vector.y);
    });

}
<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

  • Related