I’m currently using Phaser 3, although my question isn’t technically restricted to that framework, as it’s more of a general JS/canvas/maths question, but:
I have a line drawn with graphics()
. It’s anchored at one end, and the other end is draggable. I made a quick demo and so far, so good – you can see what I have already on CodePen.
Dragging the marker around and redrawing the line is no problem, but what I’d like is for that line to have a maximum length of 100, so even if you’re still dragging beyond that point, the line would still follow the mouse, but not get any longer than 100. Dragging inside that maximum radius, the line would shrink as normal.
I’ve put together a visual that hopefully explains it:
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>
Advertisement
Answer
You are right, you would need some math, but phaser has many helper functions, that will do the heavy lifting.
The main idea is, of this solution is
- define a
maxLength
- 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)
- here is some math is needed, to create the vector, just calculate destination point minus origin point
- 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)
- if too long adjust the vector, with the handy function
- set the new coordinates for
point1
and thecurve
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/phaser@3.55.2/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/phaser@3.55.2/dist/phaser.js"></script>